소개

경우 저장 장치는 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. GUID와 연결 된 클래스에 대 한 정보를 얻는 SetupDiGetClassDevs 함수를 호출 합니다.

  2. 현재 클래스의 각 장치에 대 한 인스턴스 정보를 가져오는 SetupDiEnumDeviceInfo 함수를 호출 합니다.

  3. 현재 장치 정보는 존재 하지 않는 장치를 나타내는지 여부를 확인 하려면 CM_Get_DevNode_Status 함수를 호출 합니다. CR_NO_SUCH_DEVINST 또는 CR_NO_SUCH_VALUE과 같은 함수 상태 인지 확인 합니다.

  4. 필요한 경우는 존재 하지 않는 장치에 대 한 장치 인스턴스 ID를 받으려면 고 정보를 제거 하기 전에 ID를 표시 하려면 CM_Get_Device_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. 프로젝트를 빌드하십시오.

도움이 더 필요하세요?

더 많은 옵션을 원하세요?

구독 혜택을 살펴보고, 교육 과정을 찾아보고, 디바이스를 보호하는 방법 등을 알아봅니다.

커뮤니티를 통해 질문하고 답변하고, 피드백을 제공하고, 풍부한 지식을 갖춘 전문가의 의견을 들을 수 있습니다.