(Windows Internet) 缓存

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

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

响应处理期间的缓存行为

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

  • WinINet 仅缓存 HTTP 和 FTP 响应。
  • 只有良好的响应可以由缓存存储,并在后续请求的答复中使用。 正常的响应被定义为成功返回的响应。
  • 默认情况下,WinINet 将缓存成功的响应,除非服务器的缓存控制指令或应用程序定义的标志特别指出响应可能不会缓存。
  • 通常,如果满足上面列出的要求,则会缓存对 GET 谓词的响应。 在任何情况下都不会缓存对 PUT 和 POST 谓词的响应。
  • 即使在缓存已满时也将缓存项。 如果添加的项将缓存放在大小限制的范围内,则会计划缓存清除程序。 默认情况下,不保证项在缓存中保持超过10分钟。 有关详细信息,请参阅下面的 Cache Scavenger 部分。
  • 默认情况下会缓存 Https。 这由应用程序定义的缓存指令不能重写的全局设置管理。 若要替代全局设置,请在控制面板中选择 "Internet 选项" 小程序,并访问 "高级" 选项卡。选中 "安全性" 部分下的 "不将加密的页保存到磁盘" 框。

缓存清理

缓存清理会定期从缓存中清除项。 如果将某个项添加到缓存并且缓存已满,则会将该项添加到缓存,并计划缓存清除程序。 如果缓存清理程序完成一轮清理,并且缓存未达到缓存限制,则在将另一项添加到缓存中时,将为另一轮计划清除程序。 通常,当添加的项将缓存的大小限制在其大小限制范围内时,会安排清除程序。 默认情况下,缓存中的最小生存时间设置为10分钟,除非在缓存控制指令中指定了其他值。 启动缓存 scavenger 后,就不能保证最早的项最先从缓存中删除。

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

使用标志控制缓存

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

可以使用以下标志来控制缓存。

含义
INTERNET _ 标志 _ 缓存 _ 异步 此标志无效。
_ _ _ _ 网络 _ 故障时的 INTERNET 标志缓存 如果资源的网络请求因 _ INTERNET _ 连接 _ 重置错误错误 _ internet _ 无法 _ 连接 错误而失败,则从缓存返回资源。 HttpOpenRequest使用此标志。
不 _ 缓存 INTERNET 标志 _ _ 不会在本地或任何网关上缓存数据。 与首选值相同, INTERNET _ 标志 _ 不 _ _ 写入缓存
指示这是一个窗体提交。
INTERNET __ _ 缓存中的标志INTERNET _ 标志 _ 窗体 _ 提交 不发出网络请求。 将从缓存中返回所有实体。 如果请求的项不在缓存中,则返回一个合适的错误,如 _ _ 未找到错误文件 _ 。 只有 InternetOpen 函数使用此标志。
INTERNET _ 标志 _ FWD _ 指示函数应使用当前在 Internet 缓存中的资源副本。 不会检查过期日期和资源的其他信息。 如果在 Internet 缓存中找不到请求的项目,系统将尝试查找网络上的资源。 此值是在 Microsoft Internet Explorer 5 中引入的,并且与 Internet Explorer 的 " 前进 " 和 " 后退 " 按钮操作相关联。
INTERNET _ 标志 _ 超链接 如果资源存储在缓存中,则强制应用程序重新加载资源(如果没有过期时间),并且未返回上次修改时间。
INTERNET _ 标志 _ 设为 _ 永久性 不再支持。
INTERNET _ 标志 _ 必须 _ 缓存 _ 请求 如果文件无法缓存,则会导致创建临时文件。 这与首选值相同, INTERNET _ 标志 _ 需要 _ 文件
_ _ 需要 _ 文件的 INTERNET 标志 如果文件无法缓存,则会导致创建临时文件。
INTERNET _ 标志 _ 没有 _ _ 写入缓存 拒绝函数将从 Internet 下载的数据存储在缓存中的任何尝试。 如果应用程序不希望在本地存储任何下载的资源,则需要此标志。
INTERNET _ 标志 _ 无 _ UI 禁用 cookie 对话框。 此标志只能由 HttpOpenRequestINTERNETOPENURL 用于 (HTTP 请求) 。
INTERNET _ 标志 _ 脱机 阻止应用程序向网络发送请求。 所有请求均使用缓存中存储的资源进行解析。 如果该资源不在缓存中,则返回合适的错误,如 _ _ 未找到错误文件 _ 。
INTERNET _ 标志 _ PRAGMA _ NOCACHE 强制由源服务器解析请求,即使代理上存在缓存副本。 InternetOpenUrl函数仅 (HTTP 和 HTTPS 请求) 并且 HttpOpenRequest函数使用此标志。
_ _ 重新加载 INTERNET 标志 强制函数直接从 Internet 检索请求的资源。 下载的信息存储在缓存中。
INTERNET _ 标志重新 _ 同步 使应用程序从 Internet 执行资源的条件性下载。 如果缓存中存储的版本是最新的,则从缓存下载信息。 否则,将从服务器重新加载信息。

持久性缓存函数

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

缓存函数提供持久缓存和脱机浏览。 除非 INTERNET _ 标志 _ 没有 _ 缓存 _ 写入 标志显式指定了缓存,否则函数将缓存从网络下载的所有数据。 不缓存对 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 _ 缓存 _ 项 _ 信息 结构的指定成员。
UnlockUrlCacheEntryFile 当通过 RetrieveUrlCacheEntryFile从缓存中检索要使用的文件时,解除锁定缓存条目。
UnlockUrlCacheEntryStream 关闭使用 RetrieveUrlCacheEntryStream检索到的流。

枚举缓存

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

这两个函数都将 INTERNET _ 缓存 _ 条目 _ 信息 结构存储到缓冲区中。 对于每个条目,此结构的大小各不相同。 如果传递到任一函数的缓冲区大小不足,则函数将失败,并且 GetLastError 返回 _ 错误 _ 缓冲区不足。 缓冲区大小变量包含检索该缓存条目所需的缓冲区大小。 应分配缓冲区大小变量所指示大小的缓冲区,并使用新的缓冲区再次调用该函数。

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

FindFirstUrlCacheEntry函数采用搜索模式,这是存储 INTERNET _ 缓存 _ 条目 _ 信息结构和缓冲区大小的缓冲区。 目前仅实现默认搜索模式,该模式将返回所有缓存条目。

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

下面的示例在 IDC _ CacheList 的列表框中显示每个缓存项的 URL。 它使用最大 _ 缓存 _ 条目 _ 信息 _ 大小初始分配缓冲区,因为 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 _ 缓存 _ 条目 _ 信息结构。 此结构包含结构大小、缓存信息的 URL、本地文件名、缓存项类型、使用计数、命中率、大小、上次修改时间、过期、上次访问时间、上次同步时间、标头信息、标头信息大小和文件扩展名。

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

GetUrlCacheEntryInfo 不会执行任何 URL 分析,因此在缓存中找不到包含锚 () 的 URL # ,即使资源已缓存也是如此。 例如,如果传递了 URL " https://example.com/example.htm\#sample ",则 _ _ _ 即使 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的前一次调用创建的本地文件名,该文件名存储在 _ 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 返回 _ " _ 找不到错误文件" _ 。 如果缓存文件当前已锁定或正在使用中,则该函数将失败,且 GetLastError 返回错误 " _ 访问 _ 被拒绝"。 文件在解除锁定时被删除。

检索缓存条目文件

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

RetrieveUrlCacheEntryStream 不会执行任何 URL 分析,因此在缓存中找不到包含锚 () 的 URL # ,即使资源已缓存也是如此。 例如,如果传递了 URL " https://example.com/example.htm\#sample ",则 _ _ _ 即使 https://example.com/example.htm 在缓存中有 "",该函数也会返回找不到的错误文件。

RetrieveUrlCacheEntryFile 接受 URL、存储 INTERNET _ 缓存 _ 条目 _ 信息 结构和缓冲区大小的缓冲区。 为调用方检索和锁定函数。

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

缓存组

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

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

处理具有可变大小信息的结构

缓存可以包含存储的每个 URL 的可变大小信息。 这会在 INTERNET _ 缓存 _ 条目 _ 信息 结构中反映出来。 当缓存函数返回此结构时,它们会创建一个缓冲区,该缓冲区始终是 INTERNET _ 缓存 _ 条目 _ 信息 的大小加上任何可变大小信息。 如果指针成员不为 NULL,则它会直接指向结构之后的内存区域。 将函数返回的缓冲区复制到另一个缓冲区时,应将指针固定到新缓冲区中的适当位置,如下面的示例所示。

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

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

备注

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