【问题标题】:Wininet cache API hangs in Windows 8Wininet 缓存 API 在 Windows 8 中挂起
【发布时间】:2012-07-26 06:27:05
【问题描述】:

我正在使用 P/Invoke 和 C# 来清除缓存条目,如下所示。该代码似乎在 32 位和 64 位的 Windows 7 上都可以正常工作。在 Windows 8 Release Candidate 上,它在DeleteUrlsFromGroup 调用时挂起。

[DllImport(@"wininet",
    SetLastError = true,
    CharSet = CharSet.Auto,
    EntryPoint = "FindFirstUrlCacheGroup",
    CallingConvention = CallingConvention.StdCall)]
private 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)]
private 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)]
private 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)]
private 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)]
private 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)]
static extern bool DeleteUrlCacheEntry(string lpszUrlName);

/// <summary>
/// Clears the cache of the web browser
/// </summary>
[HandleProcessCorruptedStateExceptions]
public static void ClearCache(Uri hostName)
{
    if (hostName == null)
    {
        return;
    }

    long groupId = 0;
    try
    {
        // Delete the groups first.
        IntPtr enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, ref groupId, IntPtr.Zero);
        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.
            // Hangs on WIndows 8
            bool 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;
        }
        DeleteUrlsFromGroup(hostName); // this hangs on Windows 8
    }
    catch (AccessViolationException)
    {

    }
}

对 Windows 8 的 Win API 更改有任何见解/参考吗?

提前致谢。

【问题讨论】:

  • 还没有。必须进行版本检查以跳过 Windows 8 的违规代码。

标签: c# pinvoke windows-8 wininet


【解决方案1】:

我没有看到 DeleteUrlsFromGroup 的 pinvoke 声明,只有 DeleteUrlCacheEntry。我认为这是挂起的方法?

如果是这样,你显式调用函数的 ANSI 版本似乎很奇怪:

EntryPoint = "DeleteUrlCacheEntryA"

但也指定:

CharSet = CharSet.Auto

这表明您正在将 Unicode 字符串传递给需要 ANSI 字符串的函数。来自 MSDN:

自动为目标操作系统适当地编组字符串。在 Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系列上,默认为 Unicode;在 Windows 98 和 Windows Me 上默认为 Ansi。

不要指定带有 *A 或 *W 扩展名的函数,因为 pinvoke 层会为您映射它,或者调用 *W 版本的函数,因为您使用 CharSet.Auto 传递 Unicode 字符串。如果您要显式调用函数的 ANSI/Unicode 版本,我也会显式地使用匹配的 CharSet。

【讨论】:

  • 他确实有DeleteUrlCacheGroup。问题中的DeleteUrlsFromGroup 似乎是一个错字,因为没有这样的 API。
  • 我认为它是 DeleteUrlCacheEntry,因为该方法至少与他正在调用的不存在方法的签名匹配,即单个字符串参数。
  • 感谢您的更新。我将在我们的测试 Windows8 盒子上对此进行测试,如果它有效,则标记为已接受。之所以有 CharSet.Auto*A 版本的导入是因为它直接取自 support.microsoft.com/kb/326201 。我需要更仔细地查看微软的代码。
  • @jimbojones 你解决过这个问题吗?同一篇该死的 kb 文章出现同样的错误
【解决方案2】:

也有同样的麻烦,但对于 c++(来自此 KB http://support.microsoft.com/kb/815718)。 我最终只是检查 DeleteUrlCacheGroup() 是否继续尝试删除相同的 groupId 值。

我会跟踪前一个 groupId,如果它与当前 groupId 匹配,我就中断循环。

【讨论】:

    【解决方案3】:

    @jimbojones :我不确定您是否仍在寻找答案,但我刚刚遇到了同样的问题并找到了解决方法。问题不在于“DeleteUrlCacheGroup”,它在您的 while 循环中

    while (true)
            {
                if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error())
                {
                    break;
                }
    
                // Delete a particular Cache Group.
                // Hangs on WIndows 8
                bool 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;
            }
    

    如果使用 groupdid '0' 调用您的代码,它将永远不会返回 false 并因此导致您的循环无限,这实际上导致您的应用程序挂起。我没有在 Windows 8 上遇到这个问题,而是在 Windows 7 本身上。场景可能会有所不同,但我认为您面临同样的问题。

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-19
        • 1970-01-01
        • 2020-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-01
        • 1970-01-01
        相关资源
        最近更新 更多