2009-10-22 32 views
28

Tôi đang sử dụng điều khiển WebBrowser bên trong Biểu mẫu Windows để hiển thị tệp PDF.WebBrowser kiểm soát vấn đề bộ nhớ đệm

Bất cứ khi nào PDF được tạo lại, tuy nhiên, điều khiển WebBrowser chỉ hiển thị phiên bản được lưu trong bộ nhớ cache cục bộ chứ không hiển thị phiên bản cập nhật từ máy chủ.

Tôi đang sử dụng() phương thức Refresh hình dưới đây để thử và buộc điều khiển để tải lại file PDF, nhưng nó không hoạt động:

_webBrowser.Navigate(pdfUrl); 

_webBrowser.Refresh(WebBrowserRefreshOption.Completely) 

Tôi có phải làm bất cứ điều gì khác để buộc các refresh để tải lại tệp PDF từ máy chủ?

+0

Nếu bạn tải cùng một URL trong trình duyệt IE (bên ngoài ứng dụng của bạn), nó thể hiện hành vi tương tự? –

Trả lời

24

Sheng Jiang là chính xác - bạn cần bộ nhớ cache của IE có lập trình rõ ràng. Đây là mẫu mã cho thấy làm thế nào để làm điều này trong C#: http://www.gutgames.com/post/Clearing-the-Cache-of-a-WebBrowser-Control.aspx

Sao chép trong trường hợp trang bị offline:

/** 
* Modified from code originally found here: 
http://support.microsoft.com/kb/326201 
**/ 

#region Usings 
using System; 
using System.Runtime.InteropServices; 

#endregion 

namespace Utilities.Web.WebBrowserHelper 
{ 
    /// <summary> 
    /// Class for clearing the cache 
    /// </summary> 
    public static class WebBrowserHelper 
    { 
     #region Definitions/DLL Imports 
     /// <summary> 
     /// For PInvoke: Contains information about an entry in the Internet cache 
     /// </summary> 
     [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 

     /// <summary> 
     /// Clears the cache of the web browser 
     /// </summary> 
     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()) { 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 
    } 
} 

Nó dựa rất nhiều vào các bài viết Microsoft KB đây: http://support.microsoft.com/kb/326201

Và để đặt trước câu hỏi - vâng, đây là một cơn đau lớn ở cổ, và không, không có cách nào khác xung quanh nó. Chúc may mắn!

0

PDF có được nhúng với thẻ đối tượng hay gì đó không? Nếu vậy, yêu cầu đối tượng trình duyệt làm mới sẽ không có bất kỳ ảnh hưởng nào - bạn phải viết trình xem PDF để làm mới (ví dụ: nhận được đối tượng trình xem PDF theo ID từ điều khiển webbrowser), vì đó là nội dung đã tải xuống .

3

Vì WebBrowser (thực sự là công cụ Trident của IE) sử dụng WinInet để kết nối mạng, bạn có thể sử dụng cache management APIs của WinInet để xóa các tệp đã lưu trong bộ nhớ cache trước khi điều hướng.

2

Thêm vào url một id ngẫu nhiên để url là duy nhất mỗi lần

+0

Điều này đã không làm việc cho tôi khi nói đến lực lượng tài nguyên như tấm phong cách bên ngoài (CSS) để được tải lại. –

0

Vescan Petru đi đúng hướng tôi nghĩ. Xoá bộ nhớ cache của trình duyệt IE là khá nặng tay và không thân thiện với người dùng. Việc thích ứng với mã MS được gợi ý được liên kết bởi Chris Clark để xóa các tập tin cụ thể khỏi bộ nhớ đệm trông khá thú vị, nhưng câu trả lời đơn giản nhất là lấy một tên tệp tạm thời mới và sau đó tạo một bản sao của tệp PDF đích với cái tên đó. Sau đó hiển thị tệp tạm thời - xóa nó khi thoát.

Đó là giải pháp làm việc của tôi được triển khai khi tôi nhấn cùng một vấn đề.

1

Để Ngăn CSS bộ nhớ đệm bạn có thể sử dụng một thủ thuật lén lút khi bao gồm cả các tập tin css:

<link type="text/css" href="css/outlook.css?<?php echo date('l jS \of F Y h:i:s A'); ?>" rel="stylesheet" />

Nó tải về một bản sao mới của css vì date_stuff thay đổi mỗi khi?.

+0

Tôi nghĩ bạn hiểu sai câu hỏi? –

+0

Điều này thực sự là một câu trả lời thực sự sạch sẽ khi bạn thay thế "css" bằng "pdf". Chỉ cần tạo một tên tệp mới mỗi lần. – Researcher

12

Đây là phần mở rộng cho câu trả lời của Chris Clark ... mã này quá quan trọng, tôi cho rằng ngăn xếp ngăn xếp là nơi an toàn hơn để giữ nó, cộng với tôi đã loại bỏ số dòng cho bạn. Dưới đây là một liên kết đến bài viết gốc một lần nữa: http://www.gutgames.com/post/Clearing-the-Cache-of-a-WebBrowser-Control.aspx

Và mã:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Runtime.InteropServices; 

namespace Utilities.Web.WebBrowserHelper 
{ 
    /** 
    * Modified from code originally found here: http://support.microsoft.com/kb/326201 
    **/ 
    public class WebBrowserHelper 
    { 
     #region Definitions/DLL Imports 
     /// <summary> 
     /// For PInvoke: Contains information about an entry in the Internet cache 
     /// </summary> 
     [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 

     /// <summary> 
     /// Clears the cache of the web browser 
     /// </summary> 
     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()) { 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 
    } 
} 
+5

Vòng lặp 'while (true)' đầu tiên trong ClearCache() xuất hiện để đi trong một vòng lặp vô hạn nếu không có điều kiện lỗi; returnValue là true, GetLastWin32Error return 0, và do đó nhóm bộ nhớ cache url tiếp theo sẽ không bao giờ được lấy ra. Tôi lấy nó mà DeleteUrlCacheGroup() sử dụng để có hành vi khác với nó bây giờ. –

+1

Cũng không hoạt động trên 64 bit. Xem câu trả lời của tôi bên dưới để biết phiên bản đã sửa. –

+0

Không có vòng lặp thực sự không phải là vô hạn ... nó chỉ vòng trong khi có lỗi, như được nhìn thấy rõ ràng bởi điều kiện tuyên bố nếu trước giờ nghỉ: ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() –

27

Tiếp tục để Serj Sagan, đây là mã với lỗi kỳ lạ Xử lý đơn giản, các vòng lặp vô hạn loại bỏ, và 32/64 bit có khả năng.

/** 
* Modified from code originally found here: http://support.microsoft.com/kb/326201 
**/ 
public class WebBrowserHelper 
{ 
    #region Definitions/DLL Imports 
    /// <summary> 
    /// For PInvoke: Contains information about an entry in the Internet cache 
    /// </summary> 
    [StructLayout(LayoutKind.Explicit)] 
    public struct ExemptDeltaOrReserverd 
    { 
     [FieldOffset(0)] 
     public UInt32 dwReserved; 
     [FieldOffset(0)] 
     public UInt32 dwExemptDelta; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct INTERNET_CACHE_ENTRY_INFOA 
    { 
     public UInt32 dwStructSize; 
     public IntPtr lpszSourceUrlName; 
     public IntPtr lpszLocalFileName; 
     public UInt32 CacheEntryType; 
     public UInt32 dwUseCount; 
     public UInt32 dwHitRate; 
     public UInt32 dwSizeLow; 
     public UInt32 dwSizeHigh; 
     public FILETIME LastModifiedTime; 
     public FILETIME ExpireTime; 
     public FILETIME LastAccessTime; 
     public FILETIME LastSyncTime; 
     public IntPtr lpHeaderInfo; 
     public UInt32 dwHeaderInfoSize; 
     public IntPtr lpszFileExtension; 
     public ExemptDeltaOrReserverd dwExemptDeltaOrReserved; 
    } 

    // 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 

    /// <summary> 
    /// Clears the cache of the web browser 
    /// </summary> 
    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; 
     const int ERROR_INSUFFICIENT_BUFFER = 0x7A; 

     // 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.    
     long groupId = 0; 
     IntPtr enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, ref groupId, IntPtr.Zero); 
     if (enumHandle != IntPtr.Zero) { 
      bool more; 
      do { 
       // Delete a particular Cache Group. 
       DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero); 
       more = FindNextUrlCacheGroup(enumHandle, ref groupId, IntPtr.Zero); 
      } while (more); 
     } 

     // Start to delete URLs that do not belong to any group. 
     int cacheEntryInfoBufferSizeInitial = 0; 
     FindFirstUrlCacheEntry(null, IntPtr.Zero, ref cacheEntryInfoBufferSizeInitial); // should always fail because buffer is too small 
     if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { 
      int cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial; 
      IntPtr cacheEntryInfoBuffer = Marshal.AllocHGlobal(cacheEntryInfoBufferSize); 
      enumHandle = FindFirstUrlCacheEntry(null, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); 
      if (enumHandle != IntPtr.Zero) { 
       bool more; 
       do { 
        INTERNET_CACHE_ENTRY_INFOA internetCacheEntry = (INTERNET_CACHE_ENTRY_INFOA)Marshal.PtrToStructure(cacheEntryInfoBuffer, typeof(INTERNET_CACHE_ENTRY_INFOA)); 
        cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize; 
        DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName); 
        more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); 
        if (!more && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { 
         cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial; 
         cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, (IntPtr)cacheEntryInfoBufferSize); 
         more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); 
        } 
       } while (more); 
      } 
      Marshal.FreeHGlobal(cacheEntryInfoBuffer); 
     } 
    } 
} 
+0

Cảm ơn bạn rất nhiều vì phiên bản của bạn! Bạn có thể đưa ra một giải thích ngắn gọn về vấn đề là gì, rằng nó không chạy trên kiến ​​trúc 64bit và cái gì gây ra vòng lặp vô hạn? – melodia

+0

@melodia, xem phần giải thích vòng lặp vô hạn của Sandra Walters ở trên. Tôi nghĩ rằng các vấn đề 64-bit liên quan đến các thuộc tính FieldOffset rõ ràng. Chúng không cần thiết, và làm lộn xộn các trường IntPtr, nó muốn 8 byte trong các tình huống 64-bit. –

+0

"Tránh nhận xét như" cảm ơn "". Vít nó. Cảm ơn! – TEK

2

Chúng tôi thấy rằng việc xóa hoàn toàn bộ nhớ cache mất quá nhiều thời gian. Một giải pháp thay thế có vẻ hoạt động tốt (và khắc phục sự cố trong câu hỏi gốc của Làm mới không hoạt động) là di chuyển cuộc gọi đến Làm mới sau khi tài liệu đã tải xong.

webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(OnWebBrowserDocumentCompleted); 

// ... 

private void OnWebBrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
{ 
    if (cacheIsStale) 
    { 
     webBrowser.Refresh(WebBrowserRefreshOption.Completely); 
    } 
} 

Cách xác định giá trị cacheIsStale sẽ tùy thuộc vào đơn đăng ký của bạn.

-1

Đối với những gì nó có giá trị, một phương tiện đơn giản để đi đến mục tiêu của bạn có thể chỉ đơn giản là làm cho URI un-cache-thể, một cái gì đó như thế này:

 int junkData = rnd.Next(1, 1000); 
     System.Uri pugme = new System.Uri("http://pugbomb.me/?" + junkData.ToString()); 
     webBrowser.Navigate(pugme); 
0

Đối với những người trong chúng ta vẫn cần phải viết VB.NET, tôi chuyển mã được đăng bởi Serj Sagan và Oliver Bock ở trên để VB và thấy rằng nó hoạt động tốt.

Cảm ơn lòng tốt này tồn tại, tôi đã thực sự đổ mồ hôi vấn đề này trong một thời gian dài.

 ' 
    ' Modified from code originally found here: http://support.microsoft.com/kb/326201 
    ' 
    Public Class WebBrowserHelper 

Region "Định nghĩa/DLL Nhập khẩu"

 ''' <summary> 
     ''' For PInvoke: Contains information about an entry In the Internet cache 
     ''' </summary> 
     <StructLayout(LayoutKind.Explicit)> 
     Public Structure ExemptDeltaOrReserverd 
      <FieldOffset(0)> 
      Public dwReserved As UInt32 
      <FieldOffset(0)> 
      Public dwExemptDelta As UInt32 
     End Structure 

     <StructLayout(LayoutKind.Sequential)> 
     Public Structure INTERNET_CACHE_ENTRY_INFOA 
      Public dwStructSize As UInt32 
      Public lpszSourceUrlName As IntPtr 
      Public lpszLocalFileName As IntPtr 
      Public CacheEntryType As UInt32 
      Public dwUseCount As UInt32 
      Public dwHitRate As UInt32 
      Public dwSizeLow As UInt32 
      Public dwSizeHigh As UInt32 
      Public LastModifiedTime As FILETIME 
      Public ExpireTime As FILETIME 
      Public LastAccessTime As FILETIME 
      Public LastSyncTime As FILETIME 
      Public lpHeaderInfo As IntPtr 
      Public dwHeaderInfoSize As UInt32 
      Public lpszFileExtension As IntPtr 
      Public dwExemptDeltaOrReserved As ExemptDeltaOrReserverd 
     End Structure 

     ' 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 Shared Function FindFirstUrlCacheGroup(dwFlags As Integer, dwFilter As Integer, lpSearchCondition As IntPtr, dwSearchCondition As Integer, ByRef lpGroupId As Long, 
          lpReserved As IntPtr) As IntPtr 
     End Function 

     ' 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 Shared Function FindNextUrlCacheGroup(hFind As IntPtr, ByRef lpGroupId As Long, lpReserved As IntPtr) As Boolean 
     End Function 

     ' 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 Shared Function DeleteUrlCacheGroup(GroupId As Long, dwFlags As Integer, lpReserved As IntPtr) As Boolean 
     End Function 

     ' For PInvoke: Begins the enumeration Of the Internet cache 
     <DllImport("wininet", SetLastError:=True, CharSet:=CharSet.Auto, EntryPoint:="FindFirstUrlCacheEntryA", CallingConvention:=CallingConvention.StdCall)> 
     Public Shared Function FindFirstUrlCacheEntry(<MarshalAs(UnmanagedType.LPTStr)> lpszUrlSearchPattern As String, lpFirstCacheEntryInfo As IntPtr, 
                 ByRef lpdwFirstCacheEntryInfoBufferSize As Integer) As IntPtr 
     End Function 

     ' For PInvoke: Retrieves the Next entry In the Internet cache 
     <DllImport("wininet", SetLastError:=True, CharSet:=CharSet.Auto, EntryPoint:="FindNextUrlCacheEntryA", CallingConvention:=CallingConvention.StdCall)> 
     Public Shared Function FindNextUrlCacheEntry(hFind As IntPtr, lpNextCacheEntryInfo As IntPtr, ByRef lpdwNextCacheEntryInfoBufferSize As Integer) As Boolean 
     End Function 

     ' 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 Shared Function DeleteUrlCacheEntry(lpszUrlName As IntPtr) As Boolean 
     End Function 

Region End

 ''' <summary> 
     ''' Clears the cache of the web browser 
     ''' </summary> 
     Public Shared Sub ClearCache() 
      ' Indicates that all of the cache groups in the user's system should be enumerated 
      Const CACHEGROUP_SEARCH_ALL As Integer = &H0 
      ' 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 CACHEGROUP_FLAG_FLUSHURL_ONDELETE As Integer = &H2 
      Const ERROR_INSUFFICIENT_BUFFER As Integer = &H7A 

      ' 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.    
      Dim groupId As Long = 0 
      Dim enumHandle As IntPtr = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, groupId, IntPtr.Zero) 

      If (enumHandle <> IntPtr.Zero) Then 
       Dim more As Boolean 

       Do 
        ' Delete a particular Cache Group. 
        DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero) 
        more = FindNextUrlCacheGroup(enumHandle, groupId, IntPtr.Zero) 
       Loop While (more) 
      End If 

      ' Start to delete URLs that do Not belong to any group. 
      Dim cacheEntryInfoBufferSizeInitial As Integer = 0 

      FindFirstUrlCacheEntry(Nothing, IntPtr.Zero, cacheEntryInfoBufferSizeInitial) ' should always fail because buffer Is too small 

      If Marshal.GetLastWin32Error() = ERROR_INSUFFICIENT_BUFFER Then 
       Dim cacheEntryInfoBufferSize As Integer = cacheEntryInfoBufferSizeInitial 
       Dim cacheEntryInfoBuffer As IntPtr = Marshal.AllocHGlobal(cacheEntryInfoBufferSize) 

       enumHandle = FindFirstUrlCacheEntry(Nothing, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial) 

       If (enumHandle <> IntPtr.Zero) Then 
        Dim more As Boolean 
        Do 
         Dim internetCacheEntry As INTERNET_CACHE_ENTRY_INFOA = CType(Marshal.PtrToStructure(cacheEntryInfoBuffer, GetType(INTERNET_CACHE_ENTRY_INFOA)), INTERNET_CACHE_ENTRY_INFOA) 

         cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize 
         DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName) 
         more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial) 

         If Not more AndAlso Marshal.GetLastWin32Error() = ERROR_INSUFFICIENT_BUFFER Then 
          cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial 
          cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, CType(cacheEntryInfoBufferSize, IntPtr)) 
          more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial) 
         End If 
        Loop While (more) 
       End If 

       Marshal.FreeHGlobal(cacheEntryInfoBuffer) 
      End If 
     End Sub 
    End Class 
Các vấn đề liên quan