65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 清理 API

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (23投票s)

2006年8月24日

CPOL

18分钟阅读

viewsIcon

241735

downloadIcon

3743

提供了一个通用的Windows清理API,已移植到Win32和COM动态链接库。

引言

当您选择保护您的工作和互联网浏览习惯的隐私时,可以安装软件工具来清理反映这些习惯的典型文件,例如临时 Internet 文件、Cookie、Internet 历史记录、最近文档痕迹等。相反,您可以使用一些通用的清理 API,它隐藏了后台的细节,可以快速编写自己的清理程序。本文提供了一个简单的清理 API,已移植到 Win32 DLL 和等效的 COM DLL。这个清理接口实现的一个实际例子是自动化计算机清理任务的程序,它从不忘记在您离开计算机时销毁私人信息。

如果您事先对如何操作和测试方面感兴趣,我建议您立即前往“如何使用”部分。

目录

Internet 缓存清理

通常,在 Internet 上使用 IE 浏览过的所有 Internet 文件都存储(缓存)在“临时 Internet 文件”文件夹中。这加快了未来的浏览速度。Internet 缓存位于%userprofile%\Local Settings\Temporary Internet Files。如果不删除,这些文件将提供有关我们的工作和浏览习惯的信息。乍一看,清理 Internet 缓存(特别是)和计算机清理(总的来说)可能看起来很简单,因为实际上我们只需要清空(或删除)一些特定的文件夹或文件。然而,让我们回顾一下一些典型的陷阱。

典型陷阱

陷阱 #1:使用 Internet Explorer 自带的工具。既然可以在 IE 的 Internet 选项中选择删除文件/Cookie,为什么还要以编程方式进行清理呢?首先,Internet 选项实用程序有点误导您。实际上,它并没有清理“临时 Internet 文件”文件夹中的所有文件和文件夹。尽管运行清理后,Windows 资源管理器会显示一个空的列表视图控件,但当我们尝试使用命令提示符时,会看到不同的结果。

dir /s “C:\Documents and Settings\I'm\Local Settings\Temporary Internet Files”

上图显示,在 IE 清理后,“Content.IE5”文件夹和“index.dat”文件仍然存在。为什么 Windows 资源管理器显示空列表而这里却不是这样呢?因为,“临时 Internet 文件”,正如您可能知道的,是一个“特殊文件夹”(我稍后会讨论这个主题),Windows 资源管理器为“特殊文件夹”提供了特殊的 UI。

顺便说一句,您可以使用以下技巧查看 Internet 缓存的全部内容。

  • 打开 Windows 资源管理器。
  • 将以下内容复制并粘贴到地址栏:C:\Documents and Settings\I'm\Local Settings\Temporary Internet Files\Content.IE5,然后按 Enter(或将快捷方式放在桌面上,并将此带引号的路径作为快捷方式的目标)。

以编程方式进行清理的第二个原因是 Windows 没有提供自动化清理任务的接口。

陷阱 #2:使用 Windows 资源管理器手动删除。尝试使用键盘的 Delete 键删除 Windows 资源管理器中的 Internet 缓存文件夹(打算稍后重新创建它)。作为响应,Windows 会显示一条消息,说明

Temporary Internet Files is a Windows system folder and 
it is required for Windows to run properly. It cannot be deleted.

这再次是因为“临时 Internet 文件”文件夹是 Windows 的“特殊文件夹”(由 CSIDL_INTERNET_CACHEPIDL 标识),并且属于“shell”命名空间(由 COM 风格的 API 管理),而不是文件系统。与文件系统文件夹相反,“特殊文件夹”不能手动或以编程方式(通常)删除/创建。

shell”命名空间比文件系统更具包容性,即它不仅包含 NTFS 文件夹,还包含“我的文档”、“历史记录”等表示物理存储的文件夹,还包含“打印机”文件夹等虚拟文件夹,它表示指向非物理存储的打印机的链接。所有文件系统对象都可以由“shell”命名空间管理,反之则不然,因为正如微软所说,文件系统是更广泛的“shell”命名空间的子集。

陷阱 #3:命令行删除。尝试使用命令提示符中的 **del**(或核心 Win32 API)删除 Internet 缓存文件夹的内容。看起来,我们可以尝试最直接的编程方法,如下所示

del /s /q “C:\Documents and 
           Settings\I'm\Local Settings\Temporary Internet Files”

结果中,我们将看到大量这样的消息:

The process cannot access the file because it is being used by another process.

正如我们稍后将看到的,这是因为一些 Internet 缓存文件/文件夹被其他进程锁定。

陷阱 #4:选择 Windows API。如 MSDN 文档所述,Shell API 可用于管理(包括删除)“特殊文件夹”的内容。通常,您会使用 SHGetSpecialFolderLocation 将“特殊文件夹”的 COM 风格 ID(CSIDL_INTERNET_CACHECSIDL_HISTORY 等)转换为文件夹的 PIDL(shell 命名空间 ID)。接下来,使用 PIDL,您将获取指向该文件夹的 IShellFolder 指针。使用 IShellFolder 指针,您可以解卷接口,进一步枚举条目并最终进行删除。但是,在删除“历史记录”文件夹中的条目时(已获得 IShellFolder 指针),MSDN 建议(Q327569:“DeleteUrl() 不删除 Internet Explorer 历史记录文件夹条目。”)使用 IContextMenu::InvokeCommand 方法删除“历史记录”项,这有一个缺点,因为“您无法禁用出现的确认对话框”(同篇文章),这对于无 UI 的清理 API 是不可接受的。

如果我们尝试使用 Win32 的 DeleteFile/DeleteDirectory 删除 Internet 缓存文件/文件夹,会更成功吗?这对于普通文件夹效果很好:我们需要使用 FindFirstFile/FindNextFile 枚举目录中的文件/子目录,逐个删除它们,如果找到子目录则递归删除。然而,在我的实验中,使用 Win32 函数进行清理会损坏 Windows 资源管理器对 Internet 缓存文件夹的视图,尽管视图会自动恢复(子文件夹 Content.IE5 及其文件 index.dat 未被删除)。

在进行 Internet 缓存清理时,重要的是要注意它由 WinInet 库管理,因此其他 API(如 Win32 核心 API)不能保证成功。与其他库相比,WinInet 提供了一个直接的子集,专为管理 Internet 缓存的内容而设计,其中包括存储在“临时 Internet 文件”、“Cookie”和“历史记录”文件夹中的所有逻辑级别文件。

话虽如此,我通常使用 WinInet API(而不是 Shell API 或 Win32 API)进行清理。在接下来的部分中,我将简要讨论此 API 中的每个函数。

Internet 缓存的 index.dat 删除

Windows 使用 index.dat 文件来索引某些文件夹(大部分是 Internet 文件夹)的内容,以加快后续访问速度。如前所述,使用 IE 的 Internet 选项实用程序进行清理并不能完全清理 Internet 缓存。与 Windows 资源管理器显示的空内容相反,“dir /s”命令显示“临时 Internet 文件”文件夹的内容实际上并非为空,并且包含“Content.IE5”文件夹(加上子文件夹)和“index.dat”文件。这是因为“最近文档”、“历史记录”、“临时 Internet 文件”等文件夹在 Windows 中由 Windows Shell 管理,它们是“特殊文件夹”。

为什么还要关心 index.dat 文件呢?事实上,未处理的 index.dat 文件代表了个人安全漏洞。这些文件包含所有访问过的 Internet 站点的列表,可以查看、复制等。例如,假设我们不希望我们喜欢的狗狗(通过 IE 在 Internet 上找到的)的私人信息永久记录在我们的计算机上。我们清空 Internet 缓存(即,删除物理缓存的网页),但保留 index.dat 不动。乍一看,我们的隐私得到了保护。与这个假设相反,这里是典型 index.dat 查看器 程序 输出的屏幕截图。

事实上,index.dat 提供了已访问 Internet 站点的概览。此外,为了实验起见,您可以尝试将旧的 index.dat 复制到一个干净的系统上,替换现有的 index.dat,看看“临时 Internet 文件”文件夹实际上是 index.dat 的查看器:没有缓存的网页内容(从未打开过 Internet 浏览器),但“TIF”文件夹显示了许多 URL(即 index.dat 的内容)。显然,这是一个漏洞,恶意用户可以复制单个文件来查看目标人员的浏览习惯。通常,有三个主要的 index.dat 文件会跟踪访问的站点。

  • Internet 缓存的 index.dat 位于 %userprofile%\Local Settings\Temporary Internet Files\Content.IE5
  • Internet 历史记录的 index.dat 位于 %userprofile%\Local Settings\History\History.IE5
  • Internet Cookie 的 index.dat 位于 %userprofile%\Cookies

由于任何 index.dat 文件的删除方式都相同,我将重点介绍删除缓存的 index.dat 的细节。显然,Win32 的 DeleteFile 可用于以编程方式删除 index.dat。然而,让我们尝试手动使用等效的 **del** 命令删除 index.dat。我们会遇到臭名昭著的问题,即 index.dat 无法被删除,因为

The process cannot access the file because it is being used by another process.

我在新闻组中看到很多关于如何删除此文件以及为什么无法正常删除的问题。实际上,这种情况是文件/文件夹句柄被另一个进程使用的典型情况。通常,我们需要通过终止相关进程来释放这些文件句柄。什么进程阻碍我们删除?有 Mark Russinovich 的 **handle** 实用程序,它显示了哪些正在运行的 Windows 进程在特定文件或文件夹上具有打开的句柄。下图显示了该实用程序的输出(当 IE 运行时)。

值得注意的是,最好为 handle 参数提供完整的带引号的路径,否则该实用程序容易输出无关进程。

很明显,Windows 资源管理器(explorer.exe)和 Internet Explorer(iexplore.exe)在 index.dat 上具有打开的句柄,阻碍我们使用 **del** 手动删除此文件。显然,应该终止 explorer.exeiexplore.exe 进程,然后再次使用 del。请注意,其他进程可能在 index.dat 上具有打开的句柄,但如果存在这种情况,handle 实用程序会在您的计算机上显示它们。特别是,如果 SP2 附带的 Windows Messenger 在 Windows XP 上使用过,则 Messenger 进程 msmsgs.exe 会默认在每次计算机启动时自动启动。“msmsgs.exe”也锁定 index.dat 文件。当然,可能锁定 index.dat 文件的进程列表并非详尽无遗。例如,预装了索尼软件的索尼 VAIO 笔记本电脑运行额外的进程,默认情况下会锁定 index.dat 文件。

删除 index.dat 的手动解决方案如下:

  • 运行 Windows 任务管理器并终止 explorer.exeiexplore.exe
  • 在 Windows 任务管理器中,启动命令提示符,导航到 index.dat 的位置,然后使用 **del** 命令删除它。
  • 在命令提示符中运行 explorer.exe 以恢复 shell。

同样,可以通过启动 Windows 进入安全模式来手动删除 index.dat,因为在安全模式下,可能锁定此文件的进程和服务尚未加载。

Delete_IECache 函数

到目前为止,我专注于在清空 IE 缓存时遇到的一些陷阱,特别是描述了手动删除 index.dat 的步骤。那么,以编程方式解决呢?忽略 index.dat,删除 Internet 缓存非常简单,可以使用 WinInet 函数进行编程。我们如何以编程方式删除 index.dat?表面上,Win32 的 DeleteFile 可以在 Windows 启动期间的适当时间段内使用,此时进程/服务尚未打开该文件的句柄,或者应强制释放打开的句柄,并以相同方式使用 DeleteFile。为此,清理 API 提供了 Delete_IECache 函数(另请参阅下一节),您可以通过将 bDeleteCacheIndex 参数设置为 TRUE(默认为 FALSE)来删除 index.dat(如果 index.dat 未被锁定)。

BOOL Delete_IECache(BOOL bDeleteCache = TRUE, BOOL bDeleteCacheIndex = FALSE);

更重要的是,如果您确定其他进程没有打开该文件的句柄,可以使用 bDeleteCacheIndex = TRUE 开关。否则,index.dat 的删除会 silently 失败。

下面的代码代表了使用 WinInet 函数实现的 Delete_IECache 函数体。该代码是 IE Internet 选项中“删除文件”的编程等效项,它使您能够删除缓存的物理内容(HTML 页面、图片、脚本等)及其 index.dat 文件。基本上,所有工作都由三个函数 FindFirstUrlCacheEntryFindNextUrlCacheEntryDeleteUrlCacheEntry 完成。我们使用 FindFirstUrlCacheEntry 获取 Internet 缓存 hCacheEnumHandle 的句柄,然后使用该句柄通过 FindNextUrlCacheEntry 获取指向下一个缓存条目的指针,并使用 DeleteUrlCacheEntry 删除它们。需要注意的一点是,我们在调用 DeleteUrlCacheEntry 之前应该调整 LPINTERNET_CACHE_ENTRY_INFO 结构的大小。这很简单,因为正确的大小将在 FindNextUrlCacheEntry 的最后一个参数(输入/输出参数)中返回。

__declspec( dllexport ) BOOL Delete_IECache(bDeleteCache = 
                        TRUE, BOOL bDeleteCacheIndex = FALSE)
{
    TCHAR szUserProfile[200]; 
    TCHAR szFilePath[200];
    HANDLE hCacheEnumHandle  = NULL;
    LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry = NULL;
    DWORD dwSize = 4096; // initial buffer size

    // Delete index.dat if requested.
    // Be sure that index.dat is not locked.
    if (bDeleteCacheIndex)
    {
        // Retrieve from environment user profile path.
        ExpandEnvironmentStrings("%userprofile%", szUserProfile, 
                         sizeof(szUserProfile)); 
        wsprintf(szFilePath, "%s%s", szUserProfile, 
                 "\\Local Settings\\Temporary Internet" 
                 " Files\\Content.IE5\\index.dat");

        DeleteFile(szFilePath);

        if (!bDeleteCache) return TRUE;
    }

    // Enable initial buffer size for cache entry structure. 
    lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwSize];
    lpCacheEntry->dwStructSize = dwSize;
    
    // URL search pattern (1st parameter)
    // options are:  NULL ("*.*"), "cookie:"  
    // or "visited:". 
    hCacheEnumHandle = FindFirstUrlCacheEntry(NULL /* in */ , 
                       lpCacheEntry /* out */, 
                       &dwSize /* in, out */);
    
    // First, obtain handle to internet cache
    // with FindFirstUrlCacheEntry 
    // for later use with FindNextUrlCacheEntry. 
    if (hCacheEnumHandle != NULL) 
    {
        // When cache entry is not a cookie, delete entry. 
        if (!(lpCacheEntry->CacheEntryType & COOKIE_CACHE_ENTRY))
        {            
            DeleteUrlCacheEntry(lpCacheEntry->lpszSourceUrlName);
        }
    }
    else
    {
        switch (GetLastError())
        {
            case ERROR_INSUFFICIENT_BUFFER:
            lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwSize];
            lpCacheEntry->dwStructSize = dwSize;

            // Repeat first step search with adjusted buffer, exit if not
            // found again (in practice one buffer's size adustment is  
            // always OK).
            hCacheEnumHandle = FindFirstUrlCacheEntry(NULL, lpCacheEntry, 
                                              &dwSize);
            if (hCacheEnumHandle != NULL) 
            {
                // When cache entry is not a cookie, delete entry. 
                if (!(lpCacheEntry->CacheEntryType & COOKIE_CACHE_ENTRY))
                {            
                         DeleteUrlCacheEntry(lpCacheEntry->lpszSourceUrlName);
                     }
           break;        
            }
            else
            {
                // FindFirstUrlCacheEntry fails again, return.
                return FALSE; 
            }
        default:
            FindCloseUrlCache(hCacheEnumHandle);
            return FALSE;
    }
    }
    
    // Next, use hCacheEnumHandle obtained
    // from the previous step to delete 
    // subsequent items of cache.
    do 
    {
         // Notice that return values of FindNextUrlCacheEntry (BOOL) and 
         // FindFirstUrlCacheEntry (HANDLE) are different.
         if (FindNextUrlCacheEntry(hCacheEnumHandle, lpCacheEntry, &dwSize))
         {
             // When cache entry is not a cookie, delete entry. 
             if (!(lpCacheEntry->CacheEntryType & COOKIE_CACHE_ENTRY))
             {            
                 DeleteUrlCacheEntry(lpCacheEntry->lpszSourceUrlName);
             }
         }
         else
         {
            switch(GetLastError())
            {
                case ERROR_INSUFFICIENT_BUFFER:
                lpCacheEntry = 
                  (LPINTERNET_CACHE_ENTRY_INFO) new char[dwSize];
                lpCacheEntry->dwStructSize = dwSize;

                // Repeat next step search with adjusted buffer, exit if 
                // error comes up again ((in practice one buffer's size 
                // adustment is always OK).
                if (FindNextUrlCacheEntry(hCacheEnumHandle, lpCacheEntry, 
                                            &dwSize)) 
                {
                     // When cache entry is not a cookie, delete entry. 
                     if (!(lpCacheEntry->CacheEntryType & 
                           COOKIE_CACHE_ENTRY))
                     {
                         DeleteUrlCacheEntry(
                           lpCacheEntry->lpszSourceUrlName);
                     }
                     break;
                }
                else
                {
                    // FindFirstUrlCacheEntry fails again, return.
                    FindCloseUrlCache(hCacheEnumHandle);
                    return FALSE; 
                }
                break;
                case ERROR_NO_MORE_ITEMS:
                FindCloseUrlCache(hCacheEnumHandle);
                return TRUE; 
                default:
                FindCloseUrlCache(hCacheEnumHandle);
                return FALSE;
            }
        }
    } while (TRUE);
}

清理 API 实现的一个例子是 Synaptex 4S Lock 1.08 程序,它在其清理模块中使用 Delete_IECache 函数,在启动时或关机期间删除 index.dat 以实现自动化清理。下图显示了 4S Lock 1.08 的清理界面,可以从此处下载(4.7 MB)。

Internet Cookie 清理

Cookie 存储用户特定的信息,例如用于访问网页的用户名和密码,更广泛地说,它们经常用于存储网页自定义信息。虽然它们使我们不必重新输入自己的凭据,但其中存储的私有数据可能构成安全漏洞。

实际上,Cookie 是 Internet 缓存的一部分,位于“%userprofile%\Local Settings\Temporary Internet Files”文件夹中,尽管 Windows 将它们物理存储在另一个位置“%userprofile%\Cookies”。由于 Internet 缓存由 WinInet 库管理,因此 FindFirstUrlCacheEntry/FindNextUrlCacheEntry 也可以找到 Cookie,并且它们可以像其他缓存条目一样使用 DeleteUrlCacheEntry 删除。为了更快地访问以前存储的 Cookie,Windows 会在 Cookie 的 index.dat 文件(位于“%userprofile%\Cookies”中)中索引 Cookie 文件。即使删除了 Cookie,index.dat 通常仍会包含 Cookie 列表。

因此,清理 API 提供了 Delete_IECookies 函数,其中 bDeleteCookiesbDeleteCookiesIndex 的设置取决于用户的选择。请确保在将 bDeleteCookiesIndex 设置为 TRUE 之前,Cookie 的 index.dat 没有被锁定。

BOOL Delete_IECookies(BOOL bDeleteCookies = TRUE, 
                      BOOL bDeleteCookiesIndex = FALSE);

Delete_IECookies 函数的代码与 Delete_IECache 几乎相同,但在枚举 Cookie 时,我使用“cookie:”(而不是 NULL)作为 FindFirstUrlCacheEntry 函数的第一个参数。

Internet 历史记录清理

Internet 历史记录是您以前访问过的 Internet 站点的列表,反映了您的个人 Internet 浏览历史记录,您可以通过单击 Internet Explorer 中的“历史记录”按钮来查看它。Internet 历史记录位于“%userprofile%\Local Settings\History”中,并有一个隐藏的 History.IE5 子文件夹,其中包含历史记录的 index.dat

与 Internet 缓存的内容一样,在命令提示符下更好地查看历史记录文件夹的全部内容,它会显示隐藏的文件夹和文件(History.IE5index.dat)。尝试清空历史记录文件夹,包括 History.IE5index.dat,会导致我们在上一节玩删除 TIF(临时 Internet 文件)时遇到的问题。通常,隐藏的历史记录内容会被正在运行的进程锁定,并且在释放锁定(手动或以编程方式)之前或在历史记录对象尚未被锁定的适当时间段内进行删除之前,都无法删除。与以前一样,尝试使用 IE 的 Internet 选项/清除历史记录、**del** /s 或 Win32 的 DeleteFile/DeleteDirectory(请参阅上一节的陷阱 #1-4)删除 Internet 历史记录会带来不完整的结果。

这是清理 Internet 历史记录的代码,包括删除历史记录的 index.dat。请注意,在将 bDeleteIndex 设置为 TRUE 之前,您应该确保 index.dat 没有被锁定。

__declspec( dllexport ) HRESULT Delete_IEHistory(BOOL bDeleteHistory = TRUE, 
                                     BOOL bDeleteHistoryIndex = FALSE) 
{
    TCHAR szUserProfile[200];
    TCHAR szFilePath[200];     
    HRESULT hr;

    // Delete index.dat if requested.
    // Be sure that index.dat is not locked. 
    if (bDeleteHistoryIndex)
    {
        // Retrieve from environment user profile path. 
        ExpandEnvironmentStrings("%userprofile%", szUserProfile, 
                                 sizeof(szUserProfile)); 
        wsprintf(szFilePath, "%s%s", szUserProfile, 
                             "\\Local Settings\\History" 
                             "\\History.IE5\\index.dat");
        DeleteFile(szFilePath);

        if (!bDeleteHistoryIndex) return S_OK;
    } 

    CoInitialize(NULL);

    IUrlHistoryStg2* pUrlHistoryStg2 = NULL;
    hr = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC, 
                          IID_IUrlHistoryStg2, 
                          (void**)&pUrlHistoryStg2);
    if (SUCCEEDED(hr))
    {
        hr = pUrlHistoryStg2->ClearHistory();
        pUrlHistoryStg2->Release();
    }

    CoUninitialize();

    return hr;
}

IE 地址栏历史记录清理

之前在 IE 地址栏中输入的 URL 被称为已键入 URL,可以通过展开地址栏的下拉列表来查看。它们以 url1、url2、url3 等形式记录在注册表中,位于 HKCU\Software\Microsoft\Internet Explorer\TypedURLs

它们的删除只是一个枚举条目并逐个删除的问题。

__declspec( dllexport ) void Delete_IEAddressBarHistory()
{
    HKEY hKey;
    DWORD dwResult;
    TCHAR szValueName[10];
    int i;

    // Open TypedURLs key.
    dwResult = RegOpenKey(HKEY_CURRENT_USER,
                   "Software\\Microsoft\\Internet Explorer\\TypedURLs", &hKey );

    i = 1; wsprintf(szValueName, "url%d", i); 
    while (RegDeleteValue(hKey, szValueName) == ERROR_SUCCESS) 
    {
        i++; wsprintf(szValueName, "url%d", i);
    }

    RegCloseKey(hKey); 
}

桌面最近文档清理

此列表跟踪最近打开的文档,例如 Word、Excel、记事本文档等,可以从“开始”/“我的最近文档”菜单中访问。所有清理工作都由单个 Shell 命令完成。

__declspec( dllexport ) void Delete_DesktopRecentDocsHistory()
{
    SHAddToRecentDocs(SHARD_PATH, NULL /* NULL clears history */);
}

桌面运行历史记录清理

之前在“开始”/“运行...”中键入过的命令可以通过展开其下拉控件来查看。它们被称为 RunMRU 列表(MRU 表示“最近使用”,使用连续的字母作为注册表的值名称 a、b、c 等记录,位于 HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU)。

键入错误的命令不会被记录。RunMRU 列表限制为 26 个条目。如果将记录第 27 条命令名,它将替换最高值名称(“a”)的值数据,依此类推。

与 IE 地址栏中键入 URL 的记录方法相比,RunMRU 列表有一个 MRUList 值名称,该名称是通过连接 RunMRU 列表的值名称而形成的,可用于枚举和清理列表,如下所示。

__declspec( dllexport ) void Delete_DesktopRunHistory()
{
    HKEY hKey;
    DWORD dwResult;
    TCHAR szValueName[10];

    string c, s;
    s = "abcdefghijklmnopqrstuvwxyz";

    // Open RunMRU key.
    dwResult = RegOpenKey(HKEY_CURRENT_USER,
               "Software\\Microsoft\\Windows\\" 
               "CurrentVersion\\Explorer\\RunMRU", &hKey );

    for (int i = 0; i < 26 /* z */; i++)
    {
        c = s.at(i); wsprintf(szValueName, "%s", c.c_str());
        RegDeleteValue(hKey, szValueName); 
    }

    RegDeleteValue(hKey, _T("MRUList"));


    RegCloseKey(hKey); 
}

桌面回收站

除非您在删除文件时按住 SHIFT 键,否则它们会被放入回收站以便于恢复。您可能希望使用单个 Shell 清理函数来自动清空回收站,如下所示。

__declspec( dllexport ) void Delete_DesktopRecycleBinContents()
{
    SHEmptyRecycleBin(NULL, NULL, 
             SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);
}

如何使用

Windows 的清理 API 代表了一组函数,这些函数已移植到 Win32 DLL 和 COM DLL 中,对于这两种 DLL 类型,名称均为 cleanup.dll,它们作为可下载的项目提供(我使用了 VS.NET 2003 作为 IDE)。在构建测试客户端之前,应将 DLL 项目构建为发布版本。虽然 COM 清理 API 接口由于 COM 风格的要求与 Win32 接口略有不同,但两个 API 内部都是相同的,并且仅使用标准的 Win32 函数(不使用 C 运行时库)。因此,cleanup.dll 不仅依赖于 Windows XP 或 Windows 2003 上可用的库,而且也依赖于 Windows 95 及更早版本(安装了 IE)上的库。特别是,Win32 DLL 使用标准的 kernel32.dlluser32.dllshell32.dllole32.dlladvapi32.dllwininet.dll

因此,选择哪个 DLL 取决于个人偏好和风格。在 C# 或 COM 应用程序中,COM 的 cleanup.dll 更可取;在 MFC 或紧凑型 Win32 应用程序中,您可能更喜欢 Win32 的 cleanup.dll

下表提供了 Win32 DLL 的清理 API 函数原型和说明。重要的一点是,在删除 index.dat 文件(TIF、Cookie 和历史记录)时,您的应用程序有责任确保这些文件未被锁定。如果 index.dat 文件被锁定,相应的函数将 silent 且无害地失败。前面提到的 4S Lock 1.08 的清理模块是一个在调用清理 API 函数之前检查 index.dat 文件锁定状态的应用程序示例。

  函数原型 描述
#1 BOOL Delete_IECache(BOOL bDeleteCache = TRUE, BOOL bDeleteCacheIndex = FALSE)

在 Internet 上使用 IE 浏览过的所有 Internet 文件都存储(缓存)在“临时 Internet 文件”文件夹中。这加快了未来的浏览速度。要清空 Internet 缓存,但保留其 index.dat,请使用:

Delete_IECache();

如果您确信该文件未被锁定,也可以使用 Delete_IECache 删除缓存的 index.dat(设置 bDeleteCacheIndex = TRUE)。

#2 BOOL Delete_IECookies(BOOL bDeleteCookies = TRUE, BOOL bDeleteCookiesIndex = FALSE)

Cookie 存储用户特定的网页自定义信息。它们使您不必重新输入您的凭据,如姓名和密码。因此,其中存储的私有数据可能构成安全漏洞。要清空 Internet Cookie,但保留其 index.dat,请使用:

Delete_IECookies();

如果您确信该文件未被锁定,可以使用 Delete_IECookies 删除 Cookie 的 index.dat(设置 bDeleteCookiesIndex = TRUE)。

#3 HRESULT Delete_IEHistory(BOOL bDeleteHistory = TRUE, BOOL bDeleteHistoryIndex = FALSE)

Internet 浏览历史记录反映了用户的浏览习惯,通过单击 IE 的“历史记录”按钮即可查看。要清空 Internet 历史记录,但保留其 index.dat,请使用:

Delete_IEHistory();

如果您确信该文件未被锁定,可以使用 Delete_IEHistory 删除历史记录的 index.dat(设置 bDeleteCookiesIndex = TRUE)。

#4 void Delete_IEAddressBarHistory()

Delete_IEAddressBarHistory() 可用于清空以前输入的 Internet 地址列表,该列表反映了用户的浏览习惯,可以通过展开 Internet Explorer 中的地址栏下拉控件来查看。

#5 void Delete_DesktopRecentDocsHistory()

Delete_DesktopRecentDocsHistory() 函数可用于清空最近打开的文档列表,例如 Word、Excel、记事本文档等,该列表可以从“开始”/“我的最近文档”菜单中访问。

#6 void Delete_DesktopRunHistory() Delete_DesktopRunHistory() 函数可用于清空个人命令历史记录,该历史记录反映了在“开始”/“运行”中输入的命令。该列表可以通过展开“开始”/“运行”中的下拉控件来查看。
#7 void Delete_DesktopRecycleBinContents() 除非在删除文件时按住 SHIFT 键,否则它们会被放入回收站以便于恢复。Delete_DesktopRecycleBinContents() 函数可用于清空回收站的内容。

最后,您将在文章的下载中找到三个测试应用程序(除了 Win32 和 COM cleanup.dll 的两个项目)。

  • 用于 Win32 清理 API 的 MFC 测试客户端,它测试 Win32 的 cleanup.dll
  • 用于 COM 清理 API 的 C# 测试客户端,它测试 COM 的 cleanup.dll
  • 用于 COM 清理 API 的 MFC 测试客户端,它测试 COM 的 cleanup.dll

所有这些测试应用程序都具有相同的界面。例如,用于测试 Win32 cleanup.dll 的 MFC 应用程序的界面如下所示。

结论

本文提供了一个通用的 Windows 清理 API、测试应用程序和完整的源代码。只要安装了 IE(或 wininet.dll 可用),该清理 API 就可以在 Windows 95 及更早版本的所有 Windows 系统上使用。清理 API 打包在 Win32 和 COM DLL 中,它们在内部是相同的,并且可以轻松地在您的自定义应用程序(C++、MFC、Win32、C#、ASP.NET 等)中使用,前提是您根据 CodeProject 的常规使用条款引用了本文。希望本文提供的信息和工具能让人们在任何环境中感觉更安全。

联系我

您可以通过 mlambert@synaptex.biz 联系 Marcel Lambert。

© . All rights reserved.