บทนำ
เมื่ออุปกรณ์เก็บข้อมูลถูกเชื่อมต่อกับ Windows แม้เพียงสั้น ๆ windows สร้างข้อมูลรีจิสทรีสำหรับอุปกรณ์ ช่วงเวลา รีจิสทรีอาจประกอบด้วยรายการจำนวนมากสำหรับอุปกรณ์ที่จะไม่ใช้อีกต่อไป บทความนี้อธิบายวิธีการเอาข้อมูลนี้ออกจากรีจิสทรีของระบบ
เป็นความรับผิดชอบของซอฟต์แวร์ที่สร้างการเชื่อมต่อระหว่างอุปกรณ์เก็บข้อมูลและ Windows เมื่อต้องการล้างข้อมูลของอุปกรณ์ได้อย่างถูกต้อง กระบวนการนี้เป็นสิ่งจำเป็นเนื่องจาก Windows ไม่ทราบเมื่ออุปกรณ์เก็บข้อมูลจะถูกลบอย่างถาวร หรือชั่วคราว แต่ทราบจากซอฟต์แวร์ที่สร้างการเชื่อมต่อโดยทั่วไปนี้ ตัวอย่างเช่น ถ้าซอฟต์แวร์การสำรองข้อมูลถูกกำหนดหมายเลขหน่วยทางลอจิคัล (Lun) สำหรับวัตถุประสงค์ในการสำรองข้อมูล และ unmounting Lun แล้ว จะความรับผิดชอบของซอฟต์แวร์การสำรองข้อมูลเพื่อล้างข้อมูลพร้อมจาก Windows เนื่องจากอุปกรณ์เก็บข้อมูลเดียวกันจะไม่มีอีกต่อไป สามารถใช้อีกครั้ง Windows
ข้อมูลเพิ่มเติม
เมื่ออุปกรณ์ใหม่ถูกเชื่อมต่อกับคอมพิวเตอร์ Windows จะบันทึกข้อมูลที่เกี่ยวกับอุปกรณ์ในรีจิสทรีของระบบ สำหรับอุปกรณ์ส่วนใหญ่ ขั้นตอนนี้ไม่ก่อให้เกิดปัญหา อย่างไรก็ตาม หลังจากอุปกรณ์เก็บข้อมูลแบบมีการนำเสนอ โดย ผ่านช่องสัญญาณ fiber หรือ iSCSI บหยุด อุปกรณ์อาจไม่สามารถพบอีกครั้งจากคอมพิวเตอร์ ตัวอย่างเช่น คุณอาจสามารถระบุอุปกรณ์ที่ ตามหมายเลขลำดับประจำสินค้า หรือ ตามเพ 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 ให้มาสำหรับวัตถุประสงค์ในการให้ข้อมูลเท่านั้น
-
เรียกใช้ฟังก์ชันSetupDiGetClassDevsเพื่อขอรับข้อมูลสำหรับคลาสที่เกี่ยวข้องกับ GUID
-
เรียกใช้ฟังก์ชันSetupDiEnumDeviceInfoเพื่อขอรับข้อมูลของอินสแตนซ์สำหรับอุปกรณ์แต่ละชนิดในชั้นปัจจุบัน
-
เรียกใช้ฟังก์ชันCM_Get_DevNode_Statusเพื่อดูว่า ข้อมูลของอุปกรณ์ปัจจุบันแทนอุปกรณ์การขาดงาน ตรวจสอบว่า สถานะฟังก์ชัน CR_NO_SUCH_DEVINST หรือ CR_NO_SUCH_VALUE เท่านั้น
-
อีกทางหนึ่งคือ สำหรับอุปกรณ์การขาดงาน เรียกฟังก์ชันCM_Get_Device_IDเพื่อขอรับ ID อินสแตนซ์อุปกรณ์ และแสดงรหัสก่อนที่จะลบข้อมูล
-
สำหรับอุปกรณ์ขาดงาน ใช้คลาสข้อมูลที่คุณได้รับในขั้นตอนที่ 1 และข้อมูลอินสแตนซ์ที่คุณได้รับในขั้นตอนที่ 2 เรียกใช้ฟังก์ชันSetupDiCallClassInstaller (DIF_REMOVE,...)เมื่อต้องการเอาข้อมูลออกจากรีจิสทรี
-
เมื่อได้รับการจัดการอุปกรณ์ทั้งหมดในชั้นปัจจุบัน เรียกฟังก์ชันSetupDiDestroyDeviceInfoListเพื่อล้าง
หมายเหตุ ในบางสถานการณ์ คุณอาจจะต้องทำความสะอาดรีจิสทรีไม่ใช่เฉพาะสำหรับ GUID_DEVCLASS_DISKDRIVE และ GUID_DEVCLASS_VOLUME ดิสก์คลาส guid ของ แต่ยังสำหรับ GUID_DEVCLASS_SCSIADAPTER และ GUID_DEVCLASS_VOLUMESNAPSHOT คลาส Guid ของดิสก์ เมื่อต้องการทำเช่นนี้ คุณต้องเปลี่ยนคำนิยามDiskClassesToCleanในตัวอย่างรหัสต่อไปนี้แอพลิเคชันคอนโซล Win32 ต่อไปนี้คือ ตัวอย่างของโปรแกรมประยุกต์ที่ล้างรีจิสทรี เมื่อต้องการใช้โปรแกรมประยุกต์นี้ ให้ทำตามขั้นตอนเหล่านี้ Microsoft ให้ตัวอย่างการเขียนโปรแกรมไว้สำหรับประกอบการอธิบายเท่านั้นโดยไม่มีการรับประกันไม่ว่าจะโดยชัดแจ้งหรือโดยนัย กรณีนี้รวมถึงแต่มิได้จำกัดเพียงแค่การการรับประกันโดยนัยเกี่ยวกับการจำหน่ายเป็นสินค้าหรือความเหมาะสำหรับวัตถุประสงค์เฉพาะ บทความนี้ตั้งสมมติฐานว่าคุณมีความคุ้นเคยกับภาษาการเขียนโปรแกรมที่กำลังแสดงและคุ้นเคยกับเครื่องมือที่ใช้ใน การสร้างและแก้จุดบกพร่องของขั้นตอนการดำเนินการ วิศวกรฝ่ายสนับสนุนของ Microsoft สามารถช่วยอธิบายเกี่ยวกับหน้าที่การใช้งานของกระบวนการเฉพาะ อย่างไรก็ตาม จะไม่แก้ไขตัวอย่างเหล่านี้เพื่อเพิ่มฟังก์ชัน หรือสร้างขั้นตอนเพื่อตอบสนองความต้องการเฉพาะของคุณ
-
ใน Microsoft Visual Studio 2005 คลิกสร้างบนเมนูแฟ้มแล้ว คลิ กโครงการ
-
ขยายVisual C++และจากนั้น คลิกWin32
-
คลิกแอพลิเคชันคอนโซล Win32พิมพ์การล้างข้อมูลในกล่องข้อความชื่อและจากนั้น คลิกตกลง
-
คลิกเสร็จสิ้นในกล่องโต้ตอบตัวช่วยสร้างโปรแกรมประยุกต์ Win32
-
ในโซลูชัน Explorer ขยายแฟ้มแหล่งที่มาCleanup.cppคลิกขวา ความแสดงโค้ด
-
ค้นหาตำแหน่งของรหัสต่อไปนี้:
int _tmain(int argc, _TCHAR* argv[]) { return 0; } -
แทนรหัสที่คุณพบในขั้นตอนที่ 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; } -
คลิกเมนูตรวจแก้จุดบกพร่องและจากนั้น คลิกเริ่มต้นการดีบัก
วิธีการสร้างสำหรับ Windows Server 2012 และ 2012 Studio แสดงผล
เมื่อต้องสร้างสำหรับ Windows Server 2012 และ Microsoft Visual Studio 2012 ให้ทำตามขั้นตอนเหล่านี้ หมายเหตุ เราขอแนะนำให้ คุณใช้โปรแกรมอรรถประโยชน์การDevNodeCleanสำหรับงานนี้ ขั้นตอนต่อไปนี้และตัวอย่างรหัสในขั้นตอนที่ 7 ให้มาสำหรับวัตถุประสงค์ในการให้ข้อมูลเท่านั้น
-
ใน Microsoft Visual Studio 2012 คลิกสร้างบนเมนูแฟ้มแล้ว คลิ กโครงการ
-
ในกล่องโต้ตอบโครงการใหม่พิมพ์ล้างข้อมูลลงในฟิลด์ชื่อและจากนั้น คลิกสองครั้งที่โครงการ Win32
-
ในวิซาร์โปรแกรมประยุกต์ Win32 คลิกถัดไป
-
ภายใต้ชนิดของแอพลิเคชันคลิกเพื่อเลือกโปรแกรมประยุกต์คอนโซลและจากนั้น คลิกเสร็จสิ้น
-
ในโซลูชัน Explorer ขยายแฟ้มแหล่งที่มาCleanup.cppคลิกขวา ความแสดงโค้ด
-
ค้นหาตำแหน่งของรหัสต่อไปนี้:
int _tmain(int argc, _TCHAR* argv[]) { return 0; } -
แทนรหัสที่คุณพบในขั้นตอนที่ 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; } -
ในโซลูชัน Explorerล้างข้อมูลบนคลิกขวา แล้ว คลิ กคุณสมบัติ
-
ขยายคุณสมบัติการตั้งค่าคอนฟิกขยายตัวเชื่อมโยงข้อมูลและจากนั้น คลิกป้อนเข้า
-
เลือกการอ้างอิงเพิ่มเติมคลิกลูกศรลง จากนั้นแก้ไข
-
ในกล่องโต้ตอบการอ้างอิงเพิ่มเติมชนิดsetupapi.libและcfgmgr32.lib
-
คลิก ตกลง สองครั้ง
-
สร้างโครงการ