مقدمة
عند توصيل جهاز تخزين إلى Windows، حتى لو بإيجاز، يقوم windows بإنشاء معلومات التسجيل الخاصة بالجهاز. مع مرور الوقت، قد يحتوي التسجيل على العديد من الإدخالات للأجهزة التي سيتم عدم استخدامها مرة أخرى. توضح هذه المقالة كيفية إزالة هذه المعلومات من تسجيل النظام.
أنها مسؤولية البرنامج الذي يقوم بتأسيس اتصال بين جهاز التخزين و Windows لمسح المعلومات الخاصة بالجهاز بشكل صحيح. هذه العملية ضرورية لأن Windows لا يعرف عند إزالة جهاز تخزين مؤقتاً أو نهائياً. ولكن يعرف البرنامج عادة بتأسيس الاتصال هذا. على سبيل المثال، إذا كان تركيب أرقام الوحدات المنطقية (LUNs) لأغراض النسخ الاحتياطي برنامج النسخ الاحتياطي وثم إلغاء تحميل LUNs، سيكون مسؤولية برنامج النسخ الاحتياطي لتنظيف معلومات رقم وحدة منطقية من Windows، لأن نفس جهاز التخزين لن يمكن استخدام مرة أخرى من Windows.
مزيد من المعلومات
عند قيام جهاز متصلاً بكمبيوتر، يسجل Windows معلومات حول الجهاز في تسجيل النظام. لمعظم الأجهزة، هذا الإجراء لا يشكل مشكلة. ومع ذلك، بعد تقديم جهاز تخزين بواسطة رقم وحدة منطقية من خلال قناة ألياف أو iSCSI، الجهاز قد لا تواجهها مرة أخرى الكمبيوتر. على سبيل المثال، قد يمكن تعريف جهاز برقم تسلسلي أو بصفحات SCSI 0x80 و 0x83.ديفنوديكلين Microsoft .
في هذه الحالة، قد يحتوي التسجيل على إدخالات للأجهزة التي قد لا تظهر مرة أخرى. ليس فقط القيام بهذه الإدخالات حيزاً في التسجيل، يؤدي هذه الإدخالات مشكلات تشغيلية في نهاية المطاف. على سبيل المثال، نظراً لاستخدام فهارس لوظيفة التوصيل والتشغيل قيم أربعة أرقام عشرية، قد تحدث مشكلة عند توصيل الجهاز 10,001. لحل هذا القيد في وظيفة التوصيل والتشغيل، قد تحتاج إلى إزالة معلومات الجهاز من السجل عندما يكون الجهاز محرك الأقراص الثابتة الذي لم يعد موجوداً. يمكنك القيام بذلك باستخدام الأداة المساعدةكيفية بناء على Windows Server 2003 أو Windows Server 2008، Windows Server 2008 R2 أو Visual Studio 2005
لمسح السجل لفئة القرص GUID_DEVCLASS_DISKDRIVE GUID GUID_DEVCLASS_VOLUME القرص فئة المعرف الفريد العمومي، اتبع الخطوات التالية.ديفنوديكلين لهذه المهمة. يتم توفير مثال التعليمات البرمجية في الخطوة 7 والخطوات التالية لأغراض إعلامية فقط.
ملاحظة: نوصي باستخدام الأداة المساعدة-
استدعاء دالة سيتوبديجيتكلاسديفس للحصول على معلومات لفئة المقترن بالمعرف الفريد العمومي.
-
استدعاء دالة سيتوبدينومديفيسينفو للحصول على معلومات مثيل لكل جهاز في الفئة الحالية.
-
استدعاء دالة CM_Get_DevNode_Status لمعرفة ما إذا كانت معلومات الجهاز الحالي يمثل جهاز مفقود. تحديد ما إذا كانت حالة الدالة يساوي CR_NO_SUCH_DEVINST أو CR_NO_SUCH_VALUE.
-
بشكل اختياري، لعدم وجود جهاز استدعاء دالة CM_Get_Device_ID للحصول على معرف مثيل الجهاز وعرض المعرف قبل إزالة المعلومات.
-
الجهاز غير موجود، استخدم معلومات الفئة الذي حصلت عليه في الخطوة 1 والمعلومات المثيل الذي حصلت عليه في الخطوة 2. استدعاء دالة سيتوبديكالكلاسينستالير (DIF_REMOVE،...) لإزالة المعلومات من التسجيل.
-
عند معالجة كافة الأجهزة في فئة الحالية، قم باستدعاء دالة سيتوبديديسترويديفيسينفوليست لتنظيف.
ملاحظة: في بعض وحدات السيناريو، قد يلزم تنظيف السجل ليس فقط ل GUID_DEVCLASS_DISKDRIVE و GUID_DEVCLASS_VOLUME الأقراص الفئة Guid، بل أيضا للفئة Guid الأقراص GUID_DEVCLASS_SCSIADAPTER و GUID_DEVCLASS_VOLUMESNAPSHOT. للقيام بذلك، يجب تغيير تعريف ديسككلاسيستوكلين في نموذج التعليمات البرمجية التالية.
تطبيق وحدة تحكم Win32 التالية مثالاً لتطبيق مسح السجل. لاستخدام هذا التطبيق، اتبع الخطوات التالية. تقدم Microsoft أمثلة برمجية للتوضيح فقط، دون أي ضمان صريح أو ضمني. هذا يتضمن، على سبيل المثال لا الحصر، الضمانات الضمنية الخاصة بالتسويق أو الملاءمة لغرض معين. تفترض هذه المقالة أنك معتاد على لغة البرمجة التي يتم شرحها والأدوات المستخدمة لإنشاء الإجراءات وتصحيحها. يساعد مهندسو الدعم لدى Microsoft شرح وظيفة إجراء محدد. ومع ذلك، لن يقوموا بتعديل هذه الأمثلة لتقديم وظيفة إضافية أو إنشاء إجراءات تستوفي متطلبات محددة.-
في Microsoft Visual Studio 2005، انقر فوق جديد في القائمة ملف ، ومن ثم انقر فوق المشروع.
-
توسيع Visual c + +، ومن ثم انقر فوق Win32.
-
انقر فوق تطبيق وحدة تحكم Win32واكتب "تنظيف" في مربع النص الاسم ثم انقر فوق موافق.
-
انقر فوق إنهاء في مربع الحوار معالج التطبيق Win32 .
-
في "مستكشف الحلول"، قم بتوسيع الملفات المصدرانقر بالزر الأيمن 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 و Visual Studio 2012
لإنشاء Windows Server 2012 و Microsoft Visual Studio 2012، اتبع الخطوات التالية.ديفنوديكلين لهذه المهمة. يتم توفير مثال التعليمات البرمجية في الخطوة 7 والخطوات التالية لأغراض إعلامية فقط.
ملاحظة: نوصي باستخدام الأداة المساعدة-
في Microsoft Visual Studio 2012، وانقر فوق جديد في القائمة ملف ، ومن ثم انقر فوق مشروع.
-
في مربع الحوار مشروع جديد ، اكتب "تنظيف" في حقل " الاسم "، وانقر نقراً مزدوجاً فوق مشروع Win32.
-
في معالج التطبيق Win32، انقر فوق التالي.
-
ضمن نوع التطبيق، انقر لتحديد تطبيق وحدة التحكمومن ثم انقر فوق إنهاء.
-
في "مستكشف الحلول"، قم بتوسيع الملفات المصدرانقر بالزر الأيمن 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; }
-
في "مستكشف الحلول"، انقر فوق "تنظيف"ومن ثم انقر فوق خصائص.
-
توسيع خصائص تكوينوتوسيع رابطثم انقر فوق الإدخال.
-
تحديد تبعيات إضافيةوانقر فوق السهم لأسفل ثم حدد تحرير.
-
في مربع الحوار تبعيات إضافية و نوع setupapi.lib و cfgmgr32.lib.
-
انقر نقرا مزدوج فوق موافق .
-
إنشاء المشروع.