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

WPROWADZENIE

Kiedy urządzenie magazynujące jest podłączone do systemu Windows, nawet jeśli tylko na krótko, system windows tworzy w rejestrze informacje o urządzeniu. Z czasem rejestru może zawierać wiele wpisów dla urządzeń, które nigdy nie będą używane ponownie. W tym artykule opisano jak usunąć te informacje z rejestru systemowego.

Obowiązkiem oprogramowania, który ustanawia połączenie między urządzenia pamięci masowej i Windows prawidłowo oczyścić informacji dla urządzenia. Ten proces jest konieczne, ponieważ system Windows nie wie, po usunięciu urządzenia magazynującego tymczasowo lub na stałe. Ale to wiedzieć, oprogramowanie, które zazwyczaj ustanawia połączenie. Na przykład jeśli oprogramowanie tworzenia kopii zapasowych jest instalowanie numery jednostek logicznych (LUN) do wykonywania kopii zapasowych i następnie odinstalowywanie jednostek LUN, byłoby odpowiedzialność kopii zapasowej oprogramowania, aby oczyścić informacji jednostki LUN z systemu Windows, ponieważ samego urządzenia magazynującego nie będzie już być ponownie używane przez system Windows.

Więcej informacji

Po podłączeniu nowego urządzenia do komputera, system Windows rejestruje informacje o urządzeniu w rejestrze systemowym. Dla większości urządzeń procedura ta nie stanowi problemu. Jednak po urządzenie pamięci masowej jest prezentowany przez jednostki LUN za pośrednictwem kanałów światłowodowych lub iSCSI, urządzenie nigdy nie można napotkać ponownie przez komputer. Na przykład urządzenie może być identyfikowany przez numer seryjny lub SCSI strony 0x80 i 0x83.W tej sytuacji rejestru może zawierać wpisy dla urządzeń, które mogą nie pojawić się ponownie. Nie tylko te wpisy dla zajmują miejsca w rejestrze, te wpisy po pewnym czasie może spowodować problemy operacyjne. Na przykład ponieważ indeksy dla funkcja Plug and Play za pomocą czterech cyfr dziesiętnych, może wystąpić problem po podłączeniu urządzenia 10001.Aby rozwiązać to ograniczenie funkcjonalności typu Plug and Play, można usunąć z rejestru informacje o urządzeniu, gdy urządzenie jest dysk twardy, który nie jest już obecny. Można to zrobić za pomocą narzędzia Microsoft DevNodeClean .

Jak zbudować dla systemu Windows Server 2003, Windows Server 2008, Windows Server 2008 R2 i Visual Studio 2005

Do czyszczenia rejestru dla identyfikator GUID klasy dysku GUID_DEVCLASS_DISKDRIVE oraz w przypadku GUID_DEVCLASS_VOLUME dysku identyfikator GUID klasy, wykonaj następujące kroki. Uwaga Firma Microsoft zaleca użycie devnodecleannarzędzie dla tego zadania. Następujące kroki i przykładowy kod z kroku 7 są dostarczane tylko dla celów informacyjnych.

  1. Wywołanie funkcji SetupDiGetClassDevs w celu uzyskania informacji dla klasy, która jest skojarzona z identyfikatorem GUID.

  2. Wywołanie funkcja SetupDiEnumDriverInfo do uzyskiwania informacji o wystąpieniu dla każdego urządzenia w bieżącej klasy.

  3. Wywołanie funkcji CM_Get_DevNode_Status , aby zobaczyć, czy informacje o bieżącym urządzeniu reprezentuje urządzenie nieobecny. Określić, czy stan funkcji jest równa CR_NO_SUCH_DEVINST lub cr_no_such_value.

  4. Opcjonalnie nieobecny urządzenia, można wywołać funkcji CM_Get_Device_ID , aby uzyskać identyfikator wystąpienia urządzenia i wyświetlić identyfikator przed usunięciem informacji.

  5. Brak urządzenia należy użyć klasy informacje uzyskane w kroku 1 i informacje o wystąpieniu, uzyskanym w kroku 2. Wywołanie funkcji SetupDiCallClassInstaller (DIF_REMOVE,...) , aby usunąć te informacje z rejestru.

  6. Jeśli wszystkie urządzenia w bieżącej klasy były przeładowywane, wywołać funkcję SetupDiDestroyDeviceInfoList do czyszczenia.

Uwaga W niektórych scenariuszach może mieć do czyszczenia rejestru, nie tylko dla GUID_DEVCLASS_DISKDRIVE i GUID_DEVCLASS_VOLUME dysku identyfikatorów GUID klas, ale również dla GUID_DEVCLASS_SCSIADAPTER i GUID_DEVCLASS_VOLUMESNAPSHOT dysku identyfikatorów GUID klas. Aby to zrobić, należy zmienić definicję DiskClassesToClean w następujący przykładowy kod.Następująca aplikacja konsoli systemu Win32 jest przykładem aplikacji, która czyści rejestru. Aby używać tej aplikacji, wykonaj następujące kroki. Firma Microsoft podaje przykłady programowania wyłącznie, bez jakichkolwiek gwarancji wyrażonych wprost lub domyślnie. To obejmuje, ale nie jest ograniczona, ustawowej rękojmi co do przydatności handlowej lub przydatności do określonego celu. W tym artykule założono, że użytkownik zna demonstrowany język programowania oraz narzędzia, które są używane do tworzenia i debugowania procedur. Wykwalifikowani pracownicy pomocy technicznej firmy Microsoft mogą pomóc w wyjaśnieniu, jak działa określona procedura. Nie będą jednak modyfikować tych przykładów ani dodawać funkcjonalności i konstruować procedur w celu zaspokojenia określonych potrzeb użytkownika.

  1. W programie Microsoft Visual Studio 2005 w menu plik kliknij polecenie Nowy , a następnie kliknij Projekt.

  2. Rozwiń Visual C++, a następnie kliknij przycisk Win32.

  3. Kliknij Aplikacji konsoli Win32, w polu tekstowym Nazwa wpisz Oczyszczanie , a następnie kliknij przycisk OK.

  4. Kliknij przycisk Zakończ w oknie dialogowym Kreatora aplikacji Win32 .

  5. W oknie Solution Explorer rozwiń Pliki źródłowe, kliknij prawym przyciskiem myszy Cleanup.cpp, a następnie kliknij Widok Kod.

  6. Zlokalizuj następujący kod:

    int _tmain(int argc, _TCHAR* argv[])
    {
    return 0;
    }
    
  7. Zastąp kod, który zostanie znaleziony w kroku 6 z następującego kodu.

    /**************************************************************************************************/     
    /*                                                                                                */     
    /* 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. Kliknij przycisk program Debug: polecenie menu, a następnie kliknij Rozpocznij debugowanie.

Jak zbudować dla systemu Windows Server 2012 i Visual Studio 2012

Aby zbudować dla systemu Windows Server 2012 i Microsoft Visual Studio 2012, wykonaj następujące kroki. Uwaga Firma Microsoft zaleca użycie devnodecleannarzędzie dla tego zadania. Następujące kroki i przykładowy kod z kroku 7 są dostarczane tylko dla celów informacyjnych.

  1. W programie Microsoft Visual Studio 2012 w menu plik kliknij polecenie Nowy , a następnie kliknij Projekt.

  2. W oknie dialogowym Nowy projekt w polu Nazwa wprowadź oczyszczania , a następnie kliknij dwukrotnie Projekt systemu Win32.

  3. W Kreatorze aplikacji Win32 kliknij przycisk Dalej.

  4. W obszarze Typ aplikacjikliknij, aby wybrać Aplikację konsoli, a następnie kliknij przycisk Zakończ.

  5. W oknie Solution Explorer rozwiń Pliki źródłowe, kliknij prawym przyciskiem myszy Cleanup.cpp, a następnie kliknij Widok Kod.

  6. Zlokalizuj następujący kod:

    int _tmain(int argc, _TCHAR* argv[])
    {
    return 0;
    }
    
  7. Zastąp kod, który zostanie znaleziony w kroku 6 z następującego kodu.

    //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. W oknie Solution Explorer kliknij prawym przyciskiem myszy oczyszczania, a następnie kliknij Właściwości.

  9. Rozwiń Właściwości konfiguracji, rozwiń Linker, a następnie kliknij dane wejściowe.

  10. Wybierz Dodatkowe zależności, kliknij strzałkę w dół, a następnie wybierz Edytuj.

  11. Okno dialogowe Dodatkowe zależności , typ setupapi.lib i cfgmgr32.lib.

  12. Kliknij dwa razy przycisk OK .

  13. Skompiluj projekt.

Potrzebujesz dalszej pomocy?

Chcesz uzyskać więcej opcji?

Poznaj korzyści z subskrypcji, przeglądaj kursy szkoleniowe, dowiedz się, jak zabezpieczyć urządzenie i nie tylko.

Społeczności pomagają zadawać i odpowiadać na pytania, przekazywać opinie i słuchać ekspertów z bogatą wiedzą.