Jak usunąć informacje rejestru z urządzeń, które nigdy więcej nie będą używane

Dotyczy
Windows 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

WSTĘP

Gdy urządzenie magazynujące jest podłączone do systemu Windows, nawet jeśli tylko na chwilę, system Windows tworzy informacje rejestru dla tego urządzenia. Z czasem rejestr może zawierać wiele wpisów dotyczących urządzeń, które nigdy więcej nie będą używane. W tym artykule opisano, jak usunąć te informacje z rejestru systemu.

Oprogramowanie nawiązujące połączenie między urządzeniem magazynującym a systemem Windows jest odpowiedzialne za poprawne oczyszczenie informacji dotyczących urządzenia. Ten proces jest niezbędny, ponieważ system Windows nie wie, kiedy urządzenie magazynujące zostanie usunięte tymczasowo lub trwale. Jednak oprogramowanie nawiązujące połączenie zazwyczaj o tym wie. Na przykład, jeśli oprogramowanie do tworzenia kopii zapasowych montuje numery jednostek logicznych (LUN) do celów tworzenia kopii zapasowych, a następnie odmontowuje jednostki LUN, to na oprogramowaniu kopii zapasowej spoczywa odpowiedzialność za oczyszczenie informacji o jednostkach LUN z systemu Windows, ponieważ to samo urządzenie magazynujące nie będzie już więcej używane przez system Windows.

Więcej informacji

Gdy nowe urządzenie jest podłączane do komputera, system Windows rejestruje informacje o tym urządzeniu w rejestrze systemowym. W przypadku większości urządzeń ta procedura nie stanowi problemu. Jednak po przedstawieniu urządzenia pamięci masowej przez jednostkę LUN za pośrednictwem kanału światłowodowego lub iSCSI komputer może już nigdy więcej nie napotkać tego urządzenia. Na przykład urządzenie można rozpoznać po numerze seryjnym lub po stronach SCSI 0x80 i 0x83.

W takiej sytuacji rejestr może zawierać wpisy dotyczące urządzeń, które mogą się już nigdy więcej nie pojawić. Te wpisy nie tylko zajmują miejsce w rejestrze, ale mogą ostatecznie spowodować problemy operacyjne. Ponieważ na przykład indeksy funkcji Plug and Play używają czterocyfrowych wartości dziesiętnych, problem może wystąpić, gdy urządzenie 10 001 jest podłączone.

Aby usunąć to ograniczenie funkcji Plug and Play, można usunąć informacje o urządzeniu z rejestru, jeśli urządzenie jest dyskiem twardym, którego już nie ma. Możesz to zrobić za pomocą narzędzia Microsoft DevNodeClean .

Jak tworzyć komputery z systemami Windows Server 2003, Windows Server 2008, Windows Server 2008 R2 i Visual Studio 2005

Aby wyczyścić rejestr pod kątem identyfikatora GUID klasy dysku GUID_DEVCLASS_DISKDRIVE i identyfikatora GUID klasy dysku GUID_DEVCLASS_VOLUME, wykonaj następujące kroki.

Uwaga: Zalecamy użycie do tego zadania narzędzia DevNodeClean . Poniższe kroki i przykładowy kod w kroku 7 są podane tylko dla celów informacyjnych.

  1. Wywołaj funkcję SetupDiGetClassDevs, aby uzyskać informacje o klasie skojarzonej z identyfikatorem GUID.
  2. Wywołaj funkcję SetupDiEnumDeviceInfo, aby uzyskać informacje o wystąpieniu dla każdego urządzenia w bieżącej klasie.
  3. Wywołaj funkcję CM_Get_DevNode_Status, aby sprawdzić, czy bieżące informacje o urządzeniu reprezentują nieobecne urządzenie. Określenie, czy stan funkcji jest równy CR_NO_SUCH_DEVINST czy CR_NO_SUCH_VALUE.
  4. Opcjonalnie, w przypadku nieobecnego urządzenia, wywołaj funkcję CM_Get_Device_ID, aby uzyskać identyfikator wystąpienia urządzenia i wyświetlić identyfikator przed usunięciem informacji.
  5. W przypadku nieobecnego urządzenia użyj informacji o zajęciach uzyskanych w kroku 1 i informacji o wystąpieniu uzyskanych w kroku 2. Wywołaj funkcję SetupDiCallClassInstaller(DIF_REMOVE, ...), aby usunąć informacje z rejestru.
  6. Po obsłużeniu wszystkich urządzeń w bieżącej klasie wywołaj funkcję SetupDiDestroyDeviceInfoList, aby ją wyczyścić.

Uwaga W niektórych scenariuszach może być konieczne oczyszczenie rejestru nie tylko w celu wyczyszczenia GUID_DEVCLASS_DISKDRIVE i GUID_DEVCLASS_VOLUME identyfikatorów GUID klas dysku, ale także identyfikatorów GUID klas dysku GUID_DEVCLASS_SCSIADAPTER i GUID_DEVCLASS_VOLUMESNAPSHOT. W tym celu należy zmienić definicję DiskClassesToClean w poniższym przykładowym kodzie.

Przykładem aplikacji czyszczącej rejestr jest poniższa aplikacja konsolowa Win32. Aby użyć tej aplikacji, wykonaj następujące kroki.

Firma Microsoft udostępnia przykłady programowania wyłącznie w celach ilustracyjnych, bez gwarancji wyrażonej lub dorozumianej. To obejmuje między innymi dorozumiane gwarancje przydatności handlowej lub przydatności do określonego celu. W tym artykule założono, że znasz język programowania, który jest demonstrowany, oraz narzędzia, które są używane do tworzenia i debugowania procedur. Inżynierowie pomocy technicznej firmy Microsoft mogą pomóc w wyjaśnieniu funkcjonalności danej procedury. Nie będą jednak modyfikować tych przykładów, aby zapewnić dodatkową funkcjonalność lub konstruować procedur spełniających specyficzne wymagania użytkownika. 

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

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

  3. Kliknij pozycję Aplikacja konsolowa Win32, wpisz ciąg Oczyszczanie w polu tekstowym Nazwa, a następnie kliknij przycisk OK.

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

  5. W Eksplorator rozwiązań rozwiń Files źródłowy, kliknij prawym przyciskiem myszy Cleanup.cpp, a następnie kliknij polecenie Wyświetl kod.

  6. Odszukaj następujący kod:

    int _tmain(int argc, _TCHAR* argv[])
    {
    return 0;
    }
    
    
  7. Zastąp kod znaleziony w kroku 6 następującym kodem.

    /**************************************************************************************************/     
    /*                                                                                                */     
    /* 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 menu Debuguj , a następnie kliknij polecenie Rozpocznij debugowanie.

Jak tworzyć kompilacje dla systemów Windows Server 2012 i Visual Studio 2012

Aby skompilować system Windows Server 2012 i Microsoft Visual Studio 2012, wykonaj poniższe kroki.

Uwaga: Zalecamy użycie do tego zadania narzędzia DevNodeClean . Poniższe kroki i przykładowy kod w kroku 7 są podane tylko dla celów informacyjnych.

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

  2. W oknie dialogowym Nowy projekt wpisz Oczyszczanie w polu Nazwa , a następnie kliknij dwukrotnie pozycję Win32 Project.

  3. W Kreatorze aplikacji Win32 kliknij przycisk Dalej.

  4. W obszarze Typ aplikacji zaznacz kliknięciem pozycję Aplikacja konsolowa, a następnie kliknij przycisk Zakończ.

  5. W Eksplorator rozwiązań rozwiń Files źródłowy, kliknij prawym przyciskiem myszy Cleanup.cpp, a następnie kliknij polecenie Wyświetl kod.

  6. Odszukaj następujący kod:

    int _tmain(int argc, _TCHAR* argv[])
    {
    return 0;
    }
    
    
  7. Zastąp kod znaleziony w kroku 6 następującym kodem.

    //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 Eksplorator rozwiązań kliknij prawym przyciskiem myszy polecenie Oczyść, a następnie kliknij polecenie Właściwości.

  9. Rozwiń węzeł Właściwości konfiguracji, rozwiń węzeł Konsolidator, a następnie kliknij pozycję Dane wejściowe.

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

  11. W oknie dialogowym Dodatkowe zależności wpisz setupapi.lib i cfgmgr32.lib.

  12. Kliknij dwa razy przycisk OK.

  13. Skompiluj projekt.