C# WebBrowser 控件:清除缓存而不清除 cookie

Posted

技术标签:

【中文标题】C# WebBrowser 控件:清除缓存而不清除 cookie【英文标题】:C# WebBrowser control: Clearing cache without clearing cookies 【发布时间】:2011-01-03 02:25:08 【问题描述】:

我有这段代码可以清除 C# WebBrowser 控件中的缓存。问题在于它还会清除 cookie。我似乎是整个互联网上唯一不想要这样的人。

我需要维护 cookie,但要丢弃缓存。

特别感兴趣的是这一行:

const int CACHEGROUP_SEARCH_ALL = 0x0;

它似乎定义了哪些“缓存组”(不管它们是什么)被清除,我希望 cookie 是一个我可以以某种方式跳过的缓存组。然而,试图找到这方面的任何信息只会让人头疼。

此代码最初取自 MSDN 文章,但它甚至没有提及 cookie 或缓存组。

您可以在代码顶部查看 MSDN 文章。

/** * Modified from code originally found here: http://support.microsoft.com/kb/326201 **/ using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Diagnostics; namespace Goop // Class for deleting the cache. public static class WebBrowserHelper #region Definitions/DLL Imports // For PInvoke: Contains information about an entry in the Internet cache [StructLayout(LayoutKind.Explicit, Size = 80)] public struct INTERNET_CACHE_ENTRY_INFOA [FieldOffset(0)] public uint dwStructSize; [FieldOffset(4)] public IntPtr lpszSourceUrlName; [FieldOffset(8)] public IntPtr lpszLocalFileName; [FieldOffset(12)] public uint CacheEntryType; [FieldOffset(16)] public uint dwUseCount; [FieldOffset(20)] public uint dwHitRate; [FieldOffset(24)] public uint dwSizeLow; [FieldOffset(28)] public uint dwSizeHigh; [FieldOffset(32)] public System.Runtime.InteropServices.ComTypes.FILETIME LastModifiedTime; [FieldOffset(40)] public System.Runtime.InteropServices.ComTypes.FILETIME ExpireTime; [FieldOffset(48)] public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime; [FieldOffset(56)] public System.Runtime.InteropServices.ComTypes.FILETIME LastSyncTime; [FieldOffset(64)] public IntPtr lpHeaderInfo; [FieldOffset(68)] public uint dwHeaderInfoSize; [FieldOffset(72)] public IntPtr lpszFileExtension; [FieldOffset(76)] public uint dwReserved; [FieldOffset(76)] public uint dwExemptDelta; // For PInvoke: Initiates the enumeration of the cache groups in the Internet cache [DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindFirstUrlCacheGroup", CallingConvention = CallingConvention.StdCall)] public static extern IntPtr FindFirstUrlCacheGroup( int dwFlags, int dwFilter, IntPtr lpSearchCondition, int dwSearchCondition, ref long lpGroupId, IntPtr lpReserved); // For PInvoke: Retrieves the next cache group in a cache group enumeration [DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindNextUrlCacheGroup", CallingConvention = CallingConvention.StdCall)] public static extern bool FindNextUrlCacheGroup( IntPtr hFind, ref long lpGroupId, IntPtr lpReserved); // For PInvoke: Releases the specified GROUPID and any associated state in the cache index file [DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "DeleteUrlCacheGroup", CallingConvention = CallingConvention.StdCall)] public static extern bool DeleteUrlCacheGroup( long GroupId, int dwFlags, IntPtr lpReserved); // For PInvoke: Begins the enumeration of the Internet cache [DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindFirstUrlCacheEntryA", CallingConvention = CallingConvention.StdCall)] public static extern IntPtr FindFirstUrlCacheEntry( [MarshalAs(UnmanagedType.LPTStr)] string lpszUrlSearchPattern, IntPtr lpFirstCacheEntryInfo, ref int lpdwFirstCacheEntryInfoBufferSize); // For PInvoke: Retrieves the next entry in the Internet cache [DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindNextUrlCacheEntryA", CallingConvention = CallingConvention.StdCall)] public static extern bool FindNextUrlCacheEntry( IntPtr hFind, IntPtr lpNextCacheEntryInfo, ref int lpdwNextCacheEntryInfoBufferSize); // For PInvoke: Removes the file that is associated with the source name from the cache, if the file exists [DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "DeleteUrlCacheEntryA", CallingConvention = CallingConvention.StdCall)] public static extern bool DeleteUrlCacheEntry( IntPtr lpszUrlName); #endregion #region Public Static Functions /// /// Clears the cache of the web browser /// public static void ClearCache() // Indicates that all of the cache groups in the user's system should be enumerated const int CACHEGROUP_SEARCH_ALL = 0x0; // Indicates that all the cache entries that are associated with the cache group // should be deleted, unless the entry belongs to another cache group. const int CACHEGROUP_FLAG_FLUSHURL_ONDELETE = 0x2; // File not found. const int ERROR_FILE_NOT_FOUND = 0x2; // No more items have been found. const int ERROR_NO_MORE_ITEMS = 259; // Pointer to a GROUPID variable long groupId = 0; // Local variables int cacheEntryInfoBufferSizeInitial = 0; int cacheEntryInfoBufferSize = 0; IntPtr cacheEntryInfoBuffer = IntPtr.Zero; INTERNET_CACHE_ENTRY_INFOA internetCacheEntry; IntPtr enumHandle = IntPtr.Zero; bool returnValue = false; // Delete the groups first. // Groups may not always exist on the system. // For more information, visit the following Microsoft Web site: // http://msdn.microsoft.com/library/?url=/workshop/networking/wininet/overview/cache.asp // By default, a URL does not belong to any group. Therefore, that cache may become // empty even when the CacheGroup APIs are not used because the existing URL does not belong to any group. enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, ref groupId, IntPtr.Zero); // If there are no items in the Cache, you are finished. if (enumHandle != IntPtr.Zero && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) return; // Loop through Cache Group, and then delete entries. while (true) if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error()) break; // Delete a particular Cache Group. returnValue = DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero); if (!returnValue && ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error()) returnValue = FindNextUrlCacheGroup(enumHandle, ref groupId, IntPtr.Zero); if (!returnValue && (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error())) break; // Start to delete URLs that do not belong to any group. enumHandle = FindFirstUrlCacheEntry(null, IntPtr.Zero, ref cacheEntryInfoBufferSizeInitial); if (enumHandle != IntPtr.Zero && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) return; cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial; cacheEntryInfoBuffer = Marshal.AllocHGlobal(cacheEntryInfoBufferSize); enumHandle = FindFirstUrlCacheEntry(null, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); while (true) internetCacheEntry = (INTERNET_CACHE_ENTRY_INFOA)Marshal.PtrToStructure(cacheEntryInfoBuffer, typeof(INTERNET_CACHE_ENTRY_INFOA)); if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || cacheEntryInfoBufferSize == 0) break; cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize; returnValue = DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName); if (!returnValue) returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); if (!returnValue && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) break; if (!returnValue && cacheEntryInfoBufferSizeInitial > cacheEntryInfoBufferSize) cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial; cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, (IntPtr)cacheEntryInfoBufferSize); returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); Marshal.FreeHGlobal(cacheEntryInfoBuffer); #endregion

非常感谢任何和所有帮助。

【问题讨论】:

Gunnarsson 先生,关于这个问题的任何更新?? WebBrowserHelper 的代码有什么变化?? @alhambraeidos:不,我最终运行了一个控制台命令。它会将焦点从我的窗口移开大约半秒钟,但就我的目的而言,这没关系。 【参考方案1】:

查看INTERNET_CACHE_ENTRY_INFOA 的文档,尤其是描述 CacheEntryType 的部分:

指示缓存类型的位掩码 条目及其属性。缓存 条目类型包括:历史条目 (URLHISTORY_CACHE_ENTRY)、cookie 条目(COOKIE_CACHE_ENTRY),和 正常缓存内容 (NORMAL_CACHE_ENTRY)。

此成员可以是零个或多个 以下属性标志和缓存 键入下面列出的标志。

下面是条目类型列表,其中一个是

COOKIE_CACHE_ENTRY

这似乎是您在扔掉所有东西之前要检查的内容?

【讨论】:

由于时间限制,我最终通过命令行完成,但你的帖子让我走上了正轨。谢谢!【参考方案2】:

条件应该如下,我用的是VB。

Dim icei As INTERNET_CACHE_ENTRY_INFO

......

If (icei.CacheEntryType And COOKIE_CACHE_ENTRY) <> COOKIE_CACHE_ENTRY And _
                (icei.CacheEntryType And NORMAL_CACHE_ENTRY) = NORMAL_CACHE_ENTRY Then

      cachefile = GetStrFromPtrA(icei.lpszSourceUrlName)

      Call DeleteUrlCacheEntry(cachefile)

End If

这将删除缓存的文件,但保留 cookie。

【讨论】:

【参考方案3】:

FiddlerCore 公开了一个具有该签名的方法。 ClearCacheItems(bool clearCookies, bool clearFiles)。

--咆哮--

每个人都链接到的那篇 kb 文章中有很多错误(其他答案的源代码来自哪里),我浪费了大约 2 天时间试图让它在所有必要的设置下工作。它是通过互联网复制粘贴的,根据操作系统和 IE 版本报告了许多错误。

Fiddler 最初由 Microsoft 员工编写,由 FiddlerCore.dll 提供支持。 Fiddler 的 Telerik(当前所有者/维护者/卖家)仍然免费更新、维护和赠送 FiddlerCore。如果您不想添加对 FiddlerCore 的引用,则可以反汇编 dll,它显示了调用所有这些可怕的 WinINet 函数的正确方法,但我认为在此处发布它会对 Telerik / plagarism 造成伤害。

目前,Fiddlercore 托管在这里:http://www.telerik.com/fiddler/fiddlercore

【讨论】:

我真的不知道为什么这个唯一正确的答案没有得到太多的支持。无论如何,这给了我成为第一的优势。

以上是关于C# WebBrowser 控件:清除缓存而不清除 cookie的主要内容,如果未能解决你的问题,请参考以下文章

在C# WinForm 里WebBrowser这个控件能清楚Cookie和浏览器里的缓存么?要代码 急急急急急

如何清除 System.Windows.Forms.WebBrowser 会话数据?

清除 WebBrowser 附加控件内容以在用户窗体中重用它

C#强制清除缓存

在 C# 中清除智能令牌的 Pin 缓存

c# IE 清除缓存