缓存 (Windows Internet)

WinINet 函数具有简单而灵活的内置缓存支持。 从网络检索到的任何数据都缓存在硬盘上,并为后续请求检索。 应用程序可以控制每个请求的缓存。 对于来自服务器的 http 请求,收到的大多数标头也会缓存。 当满足缓存中的 http 请求时,缓存的标头也会返回到调用方。 无论数据来自缓存还是网络,这都使数据下载变得无缝。

使用持久性 URL 缓存函数时,应用程序必须正确分配缓冲区才能获得所需结果。 有关详细信息,请参阅 使用缓冲区

响应处理期间的缓存行为

WinINet 缓存符合 RFC 2616 中所述的 HTTP 缓存控制指令。 缓存控制指令和应用程序集标志确定可能缓存的内容;但是,WinINet 根据以下条件确定实际缓存的内容:

  • WinINet 仅缓存 HTTP 和 FTP 响应。
  • 缓存只能存储性能良好的响应,并在对后续请求的回复中使用。 行为良好的响应定义为成功返回的响应。
  • 默认情况下,WinINet 将缓存成功的响应,除非来自服务器的缓存控制指令,或者应用程序定义的标志专门指示可能不会缓存响应。
  • 一般情况下,如果满足上述要求,则会缓存对 GET 谓词的响应。 在任何情况下都不会缓存对 PUT 和 POST 谓词的响应。
  • 即使缓存已满,也会缓存项。 如果添加的项将缓存置于大小限制之上,则会计划缓存寻道器。 默认情况下,不保证项在缓存中保留超过 10 分钟。 有关详细信息,请参阅下面的 缓存清道夫 部分。
  • 默认情况下缓存 Https。 这由无法由应用程序定义的缓存指令重写的全局设置进行管理。 若要替代全局设置,请在控制面板中选择“Internet 选项”小程序,然后转到“高级”选项卡。选中“安全性”部分下的“不将加密页保存到磁盘”框。

缓存 Scavenger

缓存清理器会定期清理缓存中的项。 如果将某个项添加到缓存并且缓存已满,则该项将添加到缓存中,并计划缓存寻宝程序。 如果缓存清查器完成一轮清理,并且缓存尚未达到缓存限制,则当将另一个项目添加到缓存时,将计划另一轮清查器。 通常,当添加的项将缓存置于超过其大小限制时,会安排寻道器。 默认情况下,缓存中的最短生存时间设置为 10 分钟,除非在 cache-control 指令中另有指定。 启动缓存清除程序时,无法保证最旧的项是第一个要从缓存中删除的项。

缓存在计算机中的所有 WinINet 应用程序之间共享,供同一用户使用。 从 Windows Vista 和 Windows Server 2008 开始,缓存大小设置为磁盘大小的 1/32,最小大小为 8MB,最大大小为 50MB。

使用标志控制缓存

缓存标志允许应用程序控制何时以及如何使用缓存。 这些标志可以单独使用,也可以与访问 Internet 上的信息或资源的函数中的 dwFlags 参数结合使用。 默认情况下,函数存储从 Internet 下载的所有数据。

以下标志可用于控制缓存。

含义
INTERNET_FLAG_CACHE_ASYNC 此标志无效。
INTERNET_FLAG_CACHE_IF_NET_FAIL 如果资源的网络请求因 ERROR_INTERNET_CONNECTION_RESET或ERROR_INTERNET_CANNOT_CONNECT 错误而失败,则从缓存中返回 资源HttpOpenRequest 使用此标志。
INTERNET_FLAG_DONT_CACHE 不在本地或任何网关中缓存数据。 与首选值相同, INTERNET_FLAG_NO_CACHE_WRITE
指示这是窗体提交。
INTERNET_FLAG_FROM_CACHEINTERNET_FLAG_FORMS_SUBMIT 不发出网络请求。 所有实体都从缓存返回。 如果请求的项不在缓存中,则返回合适的错误,例如ERROR_FILE_NOT_FOUND。 只有 InternetOpen 函数使用此标志。
INTERNET_FLAG_FWD_BACK 指示函数应使用当前位于 Internet 缓存中的资源的副本。 不会检查过期日期和有关资源的其他信息。 如果在 Internet 缓存中找不到请求的项,系统会尝试在网络上查找资源。 此值是在 Microsoft Internet Explorer 5 中引入的,与 Internet Explorer 的 “转发 ”和“ 后退 ”按钮操作相关联。
INTERNET_FLAG_HYPERLINK 如果在缓存中存储资源时没有过期时间,也没有返回上次修改时间,则强制应用程序重新加载资源。
INTERNET_FLAG_MAKE_PERSISTENT 不再支持。
INTERNET_FLAG_MUST_CACHE_REQUEST 如果无法缓存文件,则会导致创建临时文件。 这与首选值相同, INTERNET_FLAG_NEED_FILE
INTERNET_FLAG_NEED_FILE 如果无法缓存文件,则会导致创建临时文件。
INTERNET_FLAG_NO_CACHE_WRITE 拒绝函数在缓存中存储从 Internet 下载的数据的任何尝试。 如果应用程序不希望本地存储任何下载的资源,则此标志是必需的。
INTERNET_FLAG_NO_UI 禁用 Cookie 对话框。 HttpOpenRequestInternetOpenUrl 只能 (HTTP 请求) 使用此标志。
INTERNET_FLAG_OFFLINE 阻止应用程序向网络发送请求。 使用缓存中存储的资源解析所有请求。 如果资源不在缓存中,则返回合适的错误,例如ERROR_FILE_NOT_FOUND。
INTERNET_FLAG_PRAGMA_NOCACHE 强制源服务器解析请求,即使代理上存在缓存副本也是如此。 InternetOpenUrl 函数仅) http 和 HTTPS 请求 (,HttpOpenRequest 函数使用此标志。
INTERNET_FLAG_RELOAD 强制函数直接从 Internet 检索请求的资源。 下载的信息存储在缓存中。
INTERNET_FLAG_RESYNCHRONIZE 使应用程序从 Internet 执行资源的条件下载。 如果缓存中存储的版本是最新的,则从缓存下载信息。 否则,将从服务器重新加载信息。

 

持久缓存函数

需要持久缓存服务的客户端使用持久性缓存函数允许其应用程序将数据保存在本地文件系统中供后续使用,例如,在低带宽链接限制对数据的访问权限或根本无法访问的情况下。

缓存函数提供持久性缓存和脱机浏览。 除非 INTERNET_FLAG_NO_CACHE_WRITE 标志显式指定不缓存,否则函数将缓存从网络下载的所有数据。 不会缓存对 POST 数据的响应。

使用持久 URL 缓存函数

以下持久性 URL 缓存函数允许应用程序访问和操作缓存中存储的信息。

函数 说明
CommitUrlCacheEntryA 在缓存存储的指定文件中缓存数据,并将其与给定 URL 相关联。
CommitUrlCacheEntryW 在缓存存储的指定文件中缓存数据,并将其与给定 URL 相关联。
CreateUrlCacheEntry 分配请求的缓存存储,并创建一个本地文件名,用于保存与源名称对应的缓存条目。
CreateUrlCacheGroup 生成缓存组标识。
DeleteUrlCacheEntry 如果文件存在,则从缓存中删除与源名称关联的文件。
DeleteUrlCacheGroup 释放缓存索引文件中的 GROUPID 和任何关联的状态。
FindCloseUrlCache 关闭指定的枚举句柄。
FindFirstUrlCacheEntry 开始缓存的枚举。
FindFirstUrlCacheEntryEx 开始缓存的筛选枚举。
FindNextUrlCacheEntry 检索缓存中的下一个条目。
FindNextUrlCacheEntryEx 检索筛选的缓存枚举中的下一个条目。
GetUrlCacheEntryInfo 检索有关缓存项的信息。
GetUrlCacheEntryInfoEx 在转换 HttpSendRequest 将在脱机模式下应用的任何缓存重定向后搜索 URL。
ReadUrlCacheEntryStream 从已使用 RetrieveUrlCacheEntryStream 打开的流中读取缓存的数据。
RetrieveUrlCacheEntryFile 以文件的形式从缓存中检索缓存项。
RetrieveUrlCacheEntryStream 提供最高效且与实现无关的方式来访问缓存数据。
SetUrlCacheEntryGroup 在缓存组中添加或删除条目。
SetUrlCacheEntryInfo 设置 INTERNET_CACHE_ENTRY_INFO 结构的指定成员。
UnlockUrlCacheEntryFile 通过 RetrieveUrlCacheEntryFile 从缓存中检索文件以使用时,解锁锁定的缓存项。
UnlockUrlCacheEntryStream 关闭已使用 RetrieveUrlCacheEntryStream 检索的流。

 

枚举缓存

FindFirstUrlCacheEntryFindNextUrlCacheEntry 函数枚举缓存中存储的信息。 FindFirstUrlCacheEntry 通过采用搜索模式、缓冲区和缓冲区大小来创建句柄并返回第一个缓存条目来启动枚举。 FindNextUrlCacheEntry 采用 FindFirstUrlCacheEntry 创建的句柄、一个缓冲区和一个缓冲区大小来返回下一个缓存项。

这两个函数都在缓冲区中存储 INTERNET_CACHE_ENTRY_INFO 结构。 此结构的大小因每个条目而异。 如果传递给任一函数的缓冲区大小不足,该函数将失败, GetLastError 将返回ERROR_INSUFFICIENT_BUFFER。 缓冲区大小变量包含检索该缓存条目所需的缓冲区大小。 应分配由缓冲区大小变量指示的大小的缓冲区,并且应使用新缓冲区再次调用该函数。

INTERNET_CACHE_ENTRY_INFO 结构包含结构大小、缓存信息的 URL、本地文件名、缓存条目类型、使用计数、命中率、大小、上次修改时间、到期时间、上次访问时间、上次同步时间、标头信息、标头信息大小和文件扩展名。

FindFirstUrlCacheEntry 函数采用搜索模式、存储INTERNET_CACHE_ENTRY_INFO结构的缓冲区以及缓冲区大小。 目前,仅实现返回所有缓存条目的默认搜索模式。

枚举缓存后,应用程序应调用 FindCloseUrlCache 以关闭缓存枚举句柄。

以下示例在列表框中显示每个缓存条目的 URL, IDC_CacheList。 它使用MAX_CACHE_ENTRY_INFO_SIZE最初分配缓冲区,因为早期版本的 WinINet API 不会正确枚举缓存。 更高版本会正确枚举缓存,并且没有缓存大小限制。 在具有 Internet Explorer 4.0 中 WinINet API 版本的计算机上运行的所有应用程序都必须分配所需大小的缓冲区。 有关详细信息,请参阅 使用缓冲区

int WINAPI EnumerateCacheOld(HWND hX)
{
    DWORD dwEntrySize;
    LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry;
    DWORD MAX_CACHE_ENTRY_INFO_SIZE = 4096;
    HANDLE hCacheDir;
    int nCount=0;

    SendDlgItemMessage(hX,IDC_CacheList,LB_RESETCONTENT,0,0);
    
    SetCursor(LoadCursor(NULL,IDC_WAIT));

    dwEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
    lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];
    lpCacheEntry->dwStructSize = dwEntrySize;

again:

    hCacheDir = FindFirstUrlCacheEntry(NULL,
                                       lpCacheEntry,
                                       &dwEntrySize);
    if (!hCacheDir)                                             
    {
        delete[]lpCacheEntry;
        switch(GetLastError())
        {
            case ERROR_NO_MORE_ITEMS: 
                TCHAR tempout[80];
                _stprintf_s(tempout, 
                            80,   
                            TEXT("The number of cache entries = %d \n"),
                            nCount);
                MessageBox(hX,tempout,TEXT("Cache Enumeration"),MB_OK);
                FindCloseUrlCache(hCacheDir);
                SetCursor(LoadCursor(NULL,IDC_ARROW));
                return TRUE;
                break;
            case ERROR_INSUFFICIENT_BUFFER:
                lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) 
                                new char[dwEntrySize];
                lpCacheEntry->dwStructSize = dwEntrySize;
                goto again;
                break;
            default:
                ErrorOut( hX,GetLastError(),
                          TEXT("FindNextUrlCacheEntry Init"));
                FindCloseUrlCache(hCacheDir);
                SetCursor(LoadCursor(NULL,IDC_ARROW));
                return FALSE;
        }
    }

    SendDlgItemMessage(hX,IDC_CacheList,LB_ADDSTRING,
                       0,(LPARAM)(lpCacheEntry->lpszSourceUrlName));
    nCount++;
    delete (lpCacheEntry);

    do 
    {
        dwEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
        lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];
        lpCacheEntry->dwStructSize = dwEntrySize;

retry:
        if (!FindNextUrlCacheEntry(hCacheDir,
                                   lpCacheEntry, 
                                   &dwEntrySize))
        {
            delete[]lpCacheEntry;
            switch(GetLastError())
            {
                case ERROR_NO_MORE_ITEMS: 
                    TCHAR tempout[80];
                    _stprintf_s(tempout,
                                80,
                                TEXT("The number of cache entries = %d \n"),nCount);
                    MessageBox(hX,
                               tempout,
                               TEXT("Cache Enumeration"),MB_OK);
                    FindCloseUrlCache(hCacheDir);
                    return TRUE;
                    break;
                case ERROR_INSUFFICIENT_BUFFER:
                    lpCacheEntry = 
                             (LPINTERNET_CACHE_ENTRY_INFO) 
                              new char[dwEntrySize];
                    lpCacheEntry->dwStructSize = dwEntrySize;
                    goto retry;
                    break;
                default:
                    ErrorOut(hX,
                             GetLastError(),
                             TEXT("FindNextUrlCacheEntry Init"));
                    FindCloseUrlCache(hCacheDir);
                    return FALSE;
            }
        }

        SendDlgItemMessage(hX,
                           IDC_CacheList,LB_ADDSTRING,
                           0,
                          (LPARAM)(lpCacheEntry->lpszSourceUrlName));
        nCount++;
        delete[] lpCacheEntry;        
    }  while (TRUE);

    SetCursor(LoadCursor(NULL,IDC_ARROW));
    return TRUE;        
}

检索缓存条目信息

GetUrlCacheEntryInfo 函数允许检索指定 URL 的INTERNET_CACHE_ENTRY_INFO结构。 此结构包含结构大小、缓存信息的 URL、本地文件名、缓存条目类型、使用计数、命中率、大小、上次修改时间、过期时间、上次访问时间、上次同步时间、标头信息、标头信息大小和文件扩展名。

GetUrlCacheEntryInfo 接受 URL、 INTERNET_CACHE_ENTRY_INFO 结构的缓冲区和缓冲区大小。 如果找到该 URL,则会将信息复制到缓冲区中。 否则,函数将失败, GetLastError 返回ERROR_FILE_NOT_FOUND。 如果缓冲区大小不足以存储缓存条目信息,则函数将失败, GetLastError 将返回ERROR_INSUFFICIENT_BUFFER。 检索信息所需的大小存储在缓冲区大小变量中。

GetUrlCacheEntryInfo 不执行任何 URL 分析,因此即使缓存了资源,也不会在缓存中找到包含定位点 (#) 的 URL。 例如,如果 URL “https://example.com/example.htm#sample"传递后,函数返回ERROR_FILE_NOT_FOUND,即使 “https://example.com/example.htm"位于缓存中。

以下示例检索指定 URL 的缓存条目信息。 然后,该函数在 IDC_CacheDump 编辑框中显示标头信息。

int WINAPI GetCacheEntryInfo(HWND hX,LPTSTR lpszUrl)
{
    DWORD dwEntrySize=0;
    LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry;

    SetCursor(LoadCursor(NULL,IDC_WAIT));
    if (!GetUrlCacheEntryInfo(lpszUrl,NULL,&dwEntrySize))
    {
        if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
        {
            ErrorOut(hX,GetLastError(),TEXT("GetUrlCacheEntryInfo"));
            SetCursor(LoadCursor(NULL,IDC_ARROW));
            return FALSE;
        }
        else
            lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) 
                            new char[dwEntrySize];
    }
    else
        return FALSE; // should not be successful w/ NULL buffer
                      // and 0 size

    if (!GetUrlCacheEntryInfo(lpszUrl,lpCacheEntry,&dwEntrySize))
    {
        ErrorOut(hX,GetLastError(),TEXT("GetUrlCacheEntryInfo"));
        SetCursor(LoadCursor(NULL,IDC_ARROW));
        return FALSE;
    }
    else
    {
        if ((lpCacheEntry->dwHeaderInfoSize)!=0)
        {
            LPSTR(lpCacheEntry->lpHeaderInfo)
                                [lpCacheEntry->dwHeaderInfoSize]=TEXT('\0');
            SetDlgItemText(hX,IDC_Headers,
                           lpCacheEntry->lpHeaderInfo);
        }
        else
        {
            SetDlgItemText(hX,IDC_Headers,TEXT("None"));
        }

        SetCursor(LoadCursor(NULL,IDC_ARROW));
        return TRUE;
    }
        
}

创建缓存项

应用程序使用 CreateUrlCacheEntryCommitUrlCacheEntry 函数创建缓存条目。

CreateUrlCacheEntry 接受 URL、预期文件大小和文件扩展名。 然后, 函数创建一个本地文件名,用于保存对应于 URL 和文件扩展名的缓存项。

使用本地文件名,将数据写入本地文件。 将数据写入本地文件后,应用程序应调用 CommitUrlCacheEntry

CommitUrlCacheEntry 接受 URL、本地文件名、到期时间、上次修改时间、缓存条目类型、标头信息、标头信息大小和文件扩展名。 然后, 函数将数据缓存在缓存存储中指定的文件中,并将其与给定 URL 相关联。

以下示例使用先前调用 CreateUrlCacheEntry 创建的本地文件名(存储在文本框中 ,IDC_LocalFile)将文本框中的文本 (IDC_CacheDump)存储在缓存条目中。 使用 fopenfprintffclose 将数据写入文件后,将使用 CommitUrlCacheEntry 提交条目。

int WINAPI CommitEntry(HWND hX)
{
    LPTSTR lpszUrl, lpszExt, lpszFileName;
    LPTSTR lpszData,lpszSize;
    DWORD dwSize;
    DWORD dwEntryType=0;
    FILE *lpfCacheEntry;
    LPFILETIME lpdtmExpire, lpdtmLastModified;
    LPSYSTEMTIME lpdtmSysTime;
    errno_t err;

    if( SendDlgItemMessage(hX,IDC_RBNormal,BM_GETCHECK,0,0) )
    {
        dwEntryType = dwEntryType + NORMAL_CACHE_ENTRY;
    }
    else if( SendDlgItemMessage(hX,IDC_RBSticky, BM_GETCHECK,0,0) )
    {
        dwEntryType = dwEntryType + STICKY_CACHE_ENTRY;
    }
    else if(SendDlgItemMessage( hX,IDC_RBSparse, BM_GETCHECK,0,0) )
    {
        dwEntryType = dwEntryType + SPARSE_CACHE_ENTRY;
    }
 

    if( SendDlgItemMessage(hX,IDC_RBCookie, BM_GETCHECK,0,0))
    {
            dwEntryType = dwEntryType + COOKIE_CACHE_ENTRY;
    }
    else if( SendDlgItemMessage(hX,IDC_RBUrl, BM_GETCHECK,0,0) )
    {
        dwEntryType = dwEntryType + URLHISTORY_CACHE_ENTRY;
    }


    if( SendDlgItemMessage(hX,IDC_RBNone, BM_GETCHECK,0,0) )
    {
        dwEntryType=0;
    }
        
    lpdtmSysTime = new SYSTEMTIME;
    lpdtmExpire = new FILETIME;
    lpdtmLastModified = new FILETIME;

    GetLocalTime(lpdtmSysTime);
    SystemTimeToFileTime(lpdtmSysTime,lpdtmExpire);
    SystemTimeToFileTime(lpdtmSysTime,lpdtmLastModified);
    delete(lpdtmSysTime);

    lpszUrl = new TCHAR[MAX_PATH];
    lpszFileName = new TCHAR[MAX_PATH];
    lpszExt = new TCHAR[5];
    lpszSize = new TCHAR[10];

    GetDlgItemText(hX,IDC_SourceURL,lpszUrl,MAX_PATH);
    GetDlgItemText(hX,IDC_LocalFile,lpszFileName,MAX_PATH);
    GetDlgItemText(hX,IDC_FileExt,lpszExt,5);

    GetDlgItemText(hX,IDC_SizeLow,lpszSize,10);
    dwSize = (DWORD)_ttol(lpszSize);
    delete(lpszSize);

    if (dwSize==0)
    {
        if((MessageBox(hX,
                       TEXT("Incorrect File Size.\nUsing 8000 characters, Okay?\n"),
                       TEXT("Commit Entry"),MB_YESNO))
                        ==IDYES)
        {
            dwSize = 8000;
        }
        else
        {
            return FALSE;
        }
    }

    lpszData = new TCHAR[dwSize];
    GetDlgItemText(hX,IDC_CacheDump,lpszData,dwSize);
        
     err = _tfopen_s(&lpfCacheEntry,lpszFileName,_T("w"));
     if (err)
        return FALSE;
    fprintf(lpfCacheEntry,"%s",lpszData);
    fclose(lpfCacheEntry);
    delete(lpszData);

    if ( !CommitUrlCacheEntry( lpszUrl, 
                               lpszFileName, 
                               *lpdtmExpire,
                               *lpdtmLastModified, 
                               dwEntryType,
                               NULL,
                               0,
                               lpszExt,
                               0) )
    {
        ErrorOut(hX,GetLastError(),TEXT("Commit Cache Entry"));
        delete(lpszUrl);
        delete(lpszFileName);
        delete(lpszExt);
        delete(lpdtmExpire);
        delete(lpdtmLastModified);
        return FALSE;
    }
    else
    {
        delete(lpszUrl);
        delete(lpszFileName);
        delete(lpszExt);
        delete(lpdtmExpire);
        delete(lpdtmLastModified);
        return TRUE;
    }
}

删除缓存项

DeleteUrlCacheEntry 函数采用 URL 并删除与其关联的缓存文件。 如果缓存文件不存在,该函数将失败, GetLastError 将返回ERROR_FILE_NOT_FOUND。 如果缓存文件当前处于锁定状态或正在使用中,则函数将失败, 并且 GetLastError 将返回ERROR_ACCESS_DENIED。 解锁后,文件将被删除。

检索缓存条目文件

对于需要资源文件名的应用程序,请使用 RetrieveUrlCacheEntryFileUnlockUrlCacheEntryFile 函数。 不需要文件名的应用程序应使用 RetrieveUrlCacheEntryStreamReadUrlCacheEntryStreamUnlockUrlCacheEntryStream 函数来检索缓存中的信息。

RetrieveUrlCacheEntryStream 不执行任何 URL 分析,因此,即使缓存了资源,也不会在缓存中找到包含定位点 (#) 的 URL。 例如,如果 URL “https://example.com/example.htm#sample"传递后,函数返回ERROR_FILE_NOT_FOUND,即使 “https://example.com/example.htm"位于缓存中。

RetrieveUrlCacheEntryFile 接受 URL、存储 INTERNET_CACHE_ENTRY_INFO 结构的缓冲区以及缓冲区大小。 为调用方检索并锁定函数。

使用文件中的信息后,应用程序应调用 UnlockUrlCacheEntryFile 来解锁文件。

缓存组

若要创建缓存组,必须调用 CreateUrlCacheGroup 函数来为缓存组生成 GROUPID 。 通过将缓存条目的 URL 和 INTERNET_CACHE_GROUP_ADD 标志提供给 SetUrlCacheEntryGroup 函数,可以将条目添加到缓存组。 若要从组中删除缓存项,请将缓存条目的 URL 和INTERNET_CACHE_GROUP_REMOVE标志传递给 SetUrlCacheEntryGroup

FindFirstUrlCacheEntryExFindNextUrlCacheEntryEx 函数可用于枚举指定缓存组中的条目。 枚举完成后,函数应调用 FindCloseUrlCache

使用可变大小信息处理结构

缓存可以包含存储的每个 URL 的可变大小信息。 这反映在 INTERNET_CACHE_ENTRY_INFO 结构中。 当缓存函数返回此结构时,它们会创建一个缓冲区,该缓冲区的大小始终为 INTERNET_CACHE_ENTRY_INFO 以及任何可变大小的信息。 如果指针成员不为 NULL,它将指向紧跟在结构后面的内存区域。 将函数返回的缓冲区复制到另一个缓冲区时,指针成员应固定为指向新缓冲区中的相应位置,如以下示例所示。

lpDstCEInfo->lpszSourceUrlName = 
    (LPINTERNET_CACHE_ENTRY_INFO) ((LPBYTE) lpSrcCEInfo + 
       ((DWORD)(lpOldCEInfo->lpszSourceUrlName) - (DWORD)lpOldCEInfo));

如果指定的缓冲区太小而无法包含函数检索的缓存条目信息,则某些缓存函数会失败并显示ERROR_INSUFFICIENT_BUFFER错误消息。 在这种情况下,函数还会返回缓冲区的所需大小。 然后,可以分配适当大小的缓冲区,并再次调用函数。

注意

WinINet 不支持服务器实现。 此外,不应从服务使用它。 对于服务器实现或服务,请使用 Microsoft Windows HTTP Services (WinHTTP)