簡介

當將存放裝置連接到視窗,,即使只會簡單,windows 就會建立裝置的登錄資訊。經過一段時間,登錄可能包含許多項目不會使用一次的裝置。本文說明如何從系統登錄中移除這項資訊。

它負責建立存放裝置與 Windows 來適當地清除裝置的資訊之間的連線的軟體。此程序是必要的因為 Windows 並不會知道暫時或永久地移除儲存裝置是時也一樣。但是,通常會建立連線的軟體確實知道這。例如,如果備份軟體進行備份,裝載邏輯單元編號 (Lun),然後卸載 Lun 會清除視窗的 LUN 資訊備份軟體的責任因為相同的存放裝置將不再再次使用 windows。

更多的資訊

當新的裝置被連接到電腦時,Windows 系統登錄中的裝置相關的記錄資訊。對於大多數的裝置,此程序不會造成問題。不過,會顯示 LUN 透過光纖通道或 iSCSI 存放裝置之後,裝置可能永遠不會遇到一次電腦。例如,以序列號碼或 0x80 和 0x83 的 SCSI 網頁,可能會識別裝置。

在此情況下,登錄可能包含可能永遠不會出現一次的裝置的項目。不只沒有這些項目佔據在登錄中的空間,,這些項目最後可能導致操作問題。例如,因為隨插即用功能的索引會使用四位數的十進位值,問題可能會發生在連接裝置 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 之前您移除資訊。

  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. 在 Visual Studio 2012 Microsoft,按一下 [新增],請在 [檔案] 功能表上,然後按一下專案

  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. 建置專案。

需要更多協助?

擴展您的技能
探索訓練
優先取得新功能
加入 Microsoft 測試人員

這項資訊有幫助嗎?

您對翻譯品質的滿意度為何?
以下何者是您會在意的事項?

感謝您的意見反應!

×