Applies ToWindows Server 2008 Datacenter Windows Server 2008 Datacenter without Hyper-V Windows Server 2008 Enterprise Windows Server 2008 Enterprise without Hyper-V Windows Server 2008 for Itanium-Based Systems Windows Server 2008 Standard Windows Server 2008 Standard without Hyper-V Windows Server 2008 R2 Datacenter Windows Server 2008 R2 Enterprise Windows Server 2008 R2 Standard Windows Server 2012 Standard Windows Server 2012 Standard Windows Server 2012 Datacenter Windows Server 2012 Datacenter Windows Server 2016, all editions Windows Server 2016 Standard Windows Server 2016 Essentials Windows Server 2016 Windows Server 2016 Standard edition Nano Server installation option Windows Server 2016 Datacenter edition Nano Server installation option

简介

当存储设备连接到 Windows,即使只是暂时,windows 将创建该设备的注册表信息。随着时间的推移注册表可能包含许多项永远不会再次用到的设备。这篇文章描述如何从系统注册表中删除此信息。

它负责 Windows 正确清理设备的信息与存储设备之间建立连接的软件。这个过程是必要的因为 Windows 不知道临时或永久删除存储设备的时间。但这知道通常建立连接的软件。例如,如果备份软件进行备份,装载逻辑单元号 (Lun),然后卸载 Lun 要清理的 LUN 信息窗口,备份软件的责任因为同一存储设备将不再再次使用 Windows。

详细信息

当新的设备连接到计算机,Windows 系统注册表中的设备的记录信息。对于大多数设备,此过程不会带来问题。但是,提出通过光纤通道或 iSCSI LUN 的存储设备后,设备可能永远不会遇到再次由计算机。例如,通过序列号或 SCSI 页 0x80 和 0x83,可能标识设备。在此情况下,注册表可能包含项的设备,可能永远不会再次出现。不仅执行这些项目占用空间在注册表中的,这些项目最终可能会导致操作问题。例如,插功能的索引使用四位数字的十进制值,因为 10,001 设备连接时,可能会出现问题。若要解决此限制插功能,您可以不再存在硬盘设备时从注册表中删除设备信息。您可以使用Microsoft DevNodeClean实用程序来执行此操作。

如何生成用于 Windows Server 2003,Windows Server 2008,Windows Server 2008 R2 和 Visual Studio 2005

要清洁 GUID_DEVCLASS_DISKDRIVE 磁盘类 GUID 注册表并为 GUID_DEVCLASS_VOLUME 磁盘类 GUID,请执行以下步骤。 注意:我们建议您为此任务使用DevNodeClean实用程序。仅用于提供信息之目的提供了以下步骤和步骤 7 中的代码示例。

  1. 调用SetupDiGetClassDevs函数来获取与 GUID 关联的类信息。

  2. 调用SetupDiEnumDeviceInfo函数来获取每个设备当前类中的实例信息。

  3. 调用CM_Get_DevNode_Status函数来查看当前的设备信息是否表示一个不存在的设备。确定是否等于 CR_NO_SUCH_DEVINST 或 CR_NO_SUCH_VALUE 的功能状态。

  4. (可选) 为不存在的设备,调用CM_Get_Device_ID函数来获取设备实例 ID 和显示 ID 之前删除的信息。

  5. 对于不存在的设备,使用您在步骤 1 中获得的类信息,您在第 2 步中获得的实例信息。调用SetupDiCallClassInstaller (DIF_REMOVE,...)函数以从注册表中删除信息。

  6. 在当前类中的所有设备都处理时,调用SetupDiDestroyDeviceInfoList函数来清理。

注意:在某些情况下,可能需要清除注册表不仅为 GUID_DEVCLASS_DISKDRIVE 和 GUID_DEVCLASS_VOLUME 磁盘类 Guid,但也为 GUID_DEVCLASS_SCSIADAPTER 和 GUID_DEVCLASS_VOLUMESNAPSHOT 磁盘类 Guid。若要执行此操作,必须更改下面的代码示例中的DiskClassesToClean定义。下面的 Win32 控制台应用程序是清理注册表的应用程序的一个示例。若要使用此应用程序,请执行以下步骤。 Microsoft 提供的编程示例仅用于说明,没有任何明示或暗示的担保。这包括但不限于适销性或特定用途适用性的暗示担保。本文假定您熟悉所演示的编程语言和用于创建和调试过程的工具。Microsoft 的支持工程师可以帮助解释某个特定过程的功能。但是,他们不会修改这些示例以提供额外的功能或构建过程以满足您的特定要求。

  1. 在 Microsoft Visual Studio 2005 中,在文件菜单上单击新建,然后单击项目

  2. Visual C++,展开,然后单击Win32

  3. 单击Win32 控制台应用程序,请在名称文本框中,键入清除,然后单击确定

  4. 单击在Win32 应用程序向导对话框中的完成

  5. 在解决方案资源管理器中,展开源代码文件,用鼠标右键单击Cleanup.cpp,然后单击查看代码

  6. 找到下面的代码:

    int _tmain(int argc, _TCHAR* argv[])
    {
    return 0;
    }
    
  7. 替换为以下代码的步骤 6 中发现的代码。

    /**************************************************************************************************/     
    /*                                                                                                */     
    /* Copyright (c) 2007 Microsoft Corporation.  All Rights Reserved                                 */     
    /*                                                                                                */     
    /**************************************************************************************************/     
    
    #pragma warning( disable : 4201 ) // nonstandard extension used : nameless strut/union
    
    #include <windows.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stddef.h>
    #include <tchar.h>
    #include <setupapi.h>
    #include <cfgmgr32.h>
    #include <initguid.h>
    #include <devguid.h>
    
    #define SIZECHARS(x) (sizeof((x))/sizeof(TCHAR))
    #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
    
    CONST GUID *DiskClassesToClean[2] = {
        &GUID_DEVCLASS_DISKDRIVE,
        &GUID_DEVCLASS_VOLUME
    };
    
    /**************************************************************************************************/
    /*                                                                                                */
    /* The user must be member of Administrator group and must have backup and restore permissions         */
    /* (SE_BACKUP_NAME and SE_RESTORE_NAME). No check for these is performed in this example.              */
    /*                                                                                                */
    /**************************************************************************************************/
    int
    __cdecl
    main(
         IN int    ArgC,
         IN char * pArgV[]
        )
    {
        HDEVINFO DeviceInfoSet;
        SP_DEVINFO_DATA DeviceInfoData;
        ULONG DevicesRemoved = 0,
              i,
              MemberIndex,
              Status, 
              Problem,
              ulClassesToCleanIdx;
        BOOL bDoRemove = TRUE;
        CONFIGRET cr;
        TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
        OSVERSIONINFO osvi;
        const GUID ** ClassesToClean;
    
        //
        // Parse parameters.
        //
        for (i = 1; i < (ULONG)ArgC; i++) {
            //
            // Check for help.
            //
            if ( (lstrcmpi(pArgV[i], TEXT("-?")) == 0) ||
                    (lstrcmpi(pArgV[i], TEXT("/?")) == 0) ){
    
                printf("\nCleanUp will remove phantom storage device nodes from this machine.\n\n");
                printf("Usage:  CleanUp \n");
                printf("\twhere /n displays but does not remove the phantom devnodes.\n");
                printf("\nBackup and Restore privileges are required to run this utility.\n");
                return 0;
            }
    
            //
            // Check for -n, which means just list the devices that we would remove.
            //
            if ( (lstrcmpi(pArgV[i], TEXT("-n")) == 0) ||
                 (lstrcmpi(pArgV[i], TEXT("/n")) == 0) ) {
                bDoRemove = FALSE;
            }
        }
    
        //
        // Run only on Windows XP/2003 (version 5.1) or later.
        //
    
        ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    
        if (!GetVersionEx(&osvi)) {
            printf("CleanUp:  Unable to verify Windows version, exiting...\n");
            return -1;
        }
    
        if ((osvi.dwMajorVersion == 5) &&
            ((osvi.dwMinorVersion == 1) || (osvi.dwMinorVersion == 2))) {
        }
        else if (osvi.dwMajorVersion>=6) {
        }
        else
        {
            printf("CleanUp:  This utility is  designed to run on Windows XP/2003 and later\n");
            return -1;
        }
    
        ClassesToClean = DiskClassesToClean;
        ulClassesToCleanIdx = arraysize(DiskClassesToClean);
    
        for (i=0; (i<ulClassesToCleanIdx) && (bDoRemove); i++) {
    
            DeviceInfoSet = SetupDiGetClassDevs(ClassesToClean[i],
                                                NULL,
                                                NULL,
                                                0
                                                );
    
            if (INVALID_HANDLE_VALUE!=DeviceInfoSet) {
    
                DeviceInfoData.cbSize = sizeof(DeviceInfoData);
                MemberIndex = 0;
    
                while (SetupDiEnumDeviceInfo(DeviceInfoSet,
                                             MemberIndex++,
                                             &DeviceInfoData
                                             )) {
    
                    //
                    // Determine whether this device is a phantom.
                    //
                    cr = CM_Get_DevNode_Status(&Status,
                                               &Problem,
                                               DeviceInfoData.DevInst,
                                               0
                                               );
    
                    if ((cr == CR_NO_SUCH_DEVINST) ||
                        (cr == CR_NO_SUCH_VALUE)) {
                        //
                        // This is a phantom. Now get the DeviceInstanceId so we
                        // can display this as output, then delete the phantom if requested.
                        //
                        if (CM_Get_Device_ID(DeviceInfoData.DevInst,
                                             DeviceInstanceId,
                                             SIZECHARS(DeviceInstanceId),
                                             0) == CR_SUCCESS) {
    
                            if (bDoRemove) {
                                printf("DevNodePhantomCleaner:  %s will be removed.\n",
                                       DeviceInstanceId);
    
                                //
                                // Call DIF_REMOVE to remove the device's hardware
                                // and software registry keys.
                                //
                                if (SetupDiCallClassInstaller(DIF_REMOVE,
                                                              DeviceInfoSet,
                                                              &DeviceInfoData
                                                              )) {
                                    DevicesRemoved++;
                                } else {
                                    printf("CleanUp:  Error 0x%X removing phantom\n",
                                           GetLastError);
                                }
                            } else {
                                printf("CleanUp:  %s would have been removed.\n",
                                       DeviceInstanceId);
                            }
                        }
                    }
                }
    
                SetupDiDestroyDeviceInfoList(DeviceInfoSet);
            }
        }
    
        return DevicesRemoved;
    }
  8. 单击调试菜单,然后单击启动调试

如何构建 Windows Server 2012 和 Visual Studio 2012

若要生成 Windows Server 2012 和 Microsoft Visual Studio 2012,请按照下列步骤。 注意:我们建议您为此任务使用DevNodeClean实用程序。仅用于提供信息之目的提供了以下步骤和步骤 7 中的代码示例。

  1. 在 Microsoft Visual Studio 2012 年,在文件菜单上单击新建,然后单击项目

  2. 新建项目对话框中,在名称字段中,键入清理,然后双击Win32 项目

  3. 在 Win32 应用程序向导中,单击下一步

  4. 应用程序类型,选择控制台应用程序,请单击,然后单击完成

  5. 在解决方案资源管理器中,展开源代码文件,用鼠标右键单击Cleanup.cpp,然后单击查看代码

  6. 找到下面的代码:

    int _tmain(int argc, _TCHAR* argv[])
    {
    return 0;
    }
    
  7. 替换为以下代码的步骤 6 中发现的代码。

    //DevPhantomClnr.cpp : Defines the entry point for the console application.
    // 
     
    #include "stdafx.h"
    
    /**************************************************************************************************/     
    /*                                                                                                */     
    /* Copyright (c) 2007 Microsoft Corporation.  All Rights Reserved                                 */     
    /*                                                                                                */     
    /**************************************************************************************************/     
    
    #pragma warning( disable : 4201 ) // nonstandard extension used : nameless strut/union
    
    #include <windows.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stddef.h>
    #include <tchar.h>
    #include <setupapi.h>
    #include <cfgmgr32.h>
    #include <initguid.h>
    #include <devguid.h>
    
    #define SIZECHARS(x) (sizeof((x))/sizeof(TCHAR))
    #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
    
    CONST GUID *DiskClassesToClean[2] = {
        &GUID_DEVCLASS_DISKDRIVE,
        &GUID_DEVCLASS_VOLUME
    };
    
    /**************************************************************************************************/
    /*                                                                                                */
    /* The user must be member of Administrator group and must have backup and restore permissions         */
    /* (SE_BACKUP_NAME and SE_RESTORE_NAME). No check for these is performed in this example.              */
    /*                                                                                                */
    /**************************************************************************************************/
    int
    __cdecl
    main(
         IN int    ArgC,
         IN LPCWSTR pArgV[]
        )
    {
        HDEVINFO DeviceInfoSet;
        SP_DEVINFO_DATA DeviceInfoData;
        ULONG DevicesRemoved = 0,
              i,
              MemberIndex,
              Status, 
              Problem,
              ulClassesToCleanIdx;
        BOOL bDoRemove = TRUE;
        CONFIGRET cr;
        TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
        OSVERSIONINFO osvi;
        const GUID ** ClassesToClean;
    
        //
        // Parse parameters.
        //
        for (i = 1; i < (ULONG)ArgC; i++) {
            //
            // Check for help.
            //
            if ( (lstrcmpi(pArgV[i], L"-?") == 0) ||
                    (lstrcmpi(pArgV[i], L"/?") == 0) ){
    
                printf("\nDevNodePhantomCleaner will remove phantom storage device nodes from this machine.\n\n");
                printf("Usage:  nDevNodePhantomCleaner \n");
                printf("\tWhere /n displays but does not remove the phantom devnodes.\n");
                printf("\nBackup and Restore privileges are required to run this utility.\n");
                return 0;
            }
    
            //
            // Check for -n, which means just list the devices that we would remove.
            //
            if ( (lstrcmpi(pArgV[i], L"-n") == 0) ||
                 (lstrcmpi(pArgV[i], L"/n") == 0) ) {
                bDoRemove = FALSE;
            }
        }
    
        //
        // Run only on Windows XP/2003 (version 5.1) or later.
        //
    
        ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    
        if (!GetVersionEx(&osvi)) {
            printf("DevNodePhantomCleaner:  Unable to verify Windows version, exiting...\n");
            return -1;
        }
    
        if ((osvi.dwMajorVersion == 5) &&
            ((osvi.dwMinorVersion == 1) || (osvi.dwMinorVersion == 2))) {
        
        // 5.1 || 5.2
    
        }
    
        else if (osvi.dwMajorVersion>=6) {
        
        //Nothing special on 6.x
    
        }
    
        else
        {
            printf("DevNodePhantomCleaner:  This utility is  designed to run on Windows XP/2003 and later\n");
            return -1;
        }
    
        ClassesToClean = DiskClassesToClean;
        ulClassesToCleanIdx = arraysize(DiskClassesToClean);
    
        for (i=0; (i<ulClassesToCleanIdx) && (bDoRemove); i++) {
    
            DeviceInfoSet = SetupDiGetClassDevs(ClassesToClean[i],
                                                NULL,
                                                NULL,
                                                0
                                                );
    
            if (INVALID_HANDLE_VALUE!=DeviceInfoSet) {
    
                DeviceInfoData.cbSize = sizeof(DeviceInfoData);
                MemberIndex = 0;
    
                while (SetupDiEnumDeviceInfo(DeviceInfoSet,
                                             MemberIndex++,
                                             &DeviceInfoData
                                             )) {
    
                    //
                    // Determine whether this device is a phantom.
                    //
                    cr = CM_Get_DevNode_Status(&Status,
                                               &Problem,
                                               DeviceInfoData.DevInst,
                                               0
                                               );
    
                    if ((cr == CR_NO_SUCH_DEVINST) ||
                        (cr == CR_NO_SUCH_VALUE)) {
                        //
                        // This is a phantom. Now get the DeviceInstanceId so we
                        // can display this as output, then delete the phantom if requested.
                        //
                        if (CM_Get_Device_ID(DeviceInfoData.DevInst,
                                             DeviceInstanceId,
                                             SIZECHARS(DeviceInstanceId),
                                             0) == CR_SUCCESS) {
    
                            if (bDoRemove) {
                                printf("DevNodePhantomCleaner:  %ws will be removed.\n",
                                       DeviceInstanceId);
    
                                //
                                // Call DIF_REMOVE to remove the device's hardware
                                // and software registry keys.
                                //
                                if (SetupDiCallClassInstaller(DIF_REMOVE,
                                                              DeviceInfoSet,
                                                              &DeviceInfoData
                                                              )) {
                                    DevicesRemoved++;
                                } else {
                                    printf("DevNodePhantomCleaner:  Error 0x%x removing phantom\n",
                                           GetLastError());
                                }
                            } else {
                                printf("DevNodePhantomCleaner:  %ws would have been removed.\n",
                                       DeviceInstanceId);
                            }
                        }
                    }
                }
    
                SetupDiDestroyDeviceInfoList(DeviceInfoSet);
            }
        }
    
        return DevicesRemoved;
    }
  8. 在解决方案资源管理器中,清理,用鼠标右键单击,然后单击属性

  9. 展开配置属性,展开链接器,然后单击输入

  10. 选择附加依赖项,请单击向下箭头,然后选择编辑

  11. 附加依赖项对话框中,类型setupapi.lib和cfgmgr32.lib。

  12. 单击确定两次。

  13. 生成项目。

需要更多帮助?

需要更多选项?

了解订阅权益、浏览培训课程、了解如何保护设备等。

社区可帮助你提出和回答问题、提供反馈,并听取经验丰富专家的意见。