다시 Windows Server 2003 또는 이후 버전을 실행 중인 컴퓨터에서 사용 하지 않을 수 있는 장치에 대 한 레지스트리 정보를 제거 하는 방법

소개

Windows Server 2003 또는 이후 버전의 Windows 실행 하는 컴퓨터에서 파이버 채널 또는 iSCSI 프로토콜을 통해 연결 된 저장 장치는 짧은 기간에 연결할 수 있습니다. 저장 장치가 연결 되 면 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.libcfgmgr32.lib.
  12. 확인을 두 번 클릭합니다.
  13. 프로젝트를 빌드하십시오.

속성

문서 ID: 934234 - 마지막 검토: 2017. 2. 7. - 수정: 1

Microsoft Windows Server 2003, Standard Edition (32-bit x86), Microsoft Windows Server 2003, Enterprise Edition (32-bit x86), Microsoft Windows Server 2003, Datacenter Edition (32-bit x86), Microsoft Windows Server 2003, Enterprise x64 Edition, Microsoft Windows Server 2003, Datacenter x64 Edition, Microsoft Windows Server 2003, Standard x64 Edition, Microsoft Windows Server 2003, Enterprise Edition for Itanium-based Systems, Microsoft Windows Server 2003, Datacenter Edition for Itanium-Based Systems, Microsoft Windows Server 2003 R2 Standard Edition (32-bit x86), Microsoft Windows Server 2003 R2 Enterprise Edition (32-Bit x86), Microsoft Windows Server 2003 R2 Datacenter Edition (32-Bit x86), Microsoft Windows Server 2003 R2 Datacenter x64 Edition, Microsoft Windows Server 2003 R2 Enterprise x64 Edition, Microsoft Windows Server 2003 R2 Standard x64 Edition, Microsoft Windows Storage Server 2003 R2 x64 Enterprise, Microsoft Windows Storage Server 2003 R2 x64 Standard, 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

피드백