Sign in with Microsoft
Sign in or create an account.

מבוא

כאשר התקן אחסון מחובר ל- Windows, גם אם רק לזמן קצר, חלונות יוצרת מידע הרישום עבור ההתקן. לאורך זמן, הרישום עשוי להכיל ערכים רבים עבור התקנים אשר לעולם לא ישמשו שוב. מאמר זה מתאר כיצד להסיר מידע זה מרישום המערכת.

הוא באחריות התוכנה המגדיר את החיבור בין התקן אחסון Windows כדי לנקות כראוי את המידע עבור ההתקן. תהליך זה חיוני מאחר ש- Windows אינו יודע כאשר התקן אחסון מוסר באופן זמני או לצמיתות. אך התוכנה המגדיר את החיבור בדרך כלל לדעת זאת. לדוגמה, אם תוכנת גיבוי טעינת מספרים יחידה לוגית (רכיבי Lun) למטרות גיבוי ולאחר מכן ביטול טעינה את רכיבי Lun, היא הייתה האחריות של תוכנות גיבוי כדי לנקות את המידע LUN מ- Windows, מכיוון באותו התקן אחסון לא תהיה יותר ניתן להשתמש שוב על-ידי Windows.

מידע נוסף

כאשר הוא מחובר התקן חדש למחשב, Windows מתעדת מידע אודות ההתקן ברישום המערכת. עבור רוב ההתקנים, הליך זה שלא להוות בעיה. עם זאת, לאחר התקן אחסון מוצגת על-ידי LUN דרך ערוץ סיבים או דרך iSCSI, ההתקן עשוי לעולם להיות נתקל שוב על-ידי המחשב. לדוגמה, התקן יזוהו על-ידי מספר סידורי או עמודים SCSI 0x80 ו- 0x83.

במצב זה, הרישום עשוי להכיל ערכים עבור התקנים לעולם שעלולים להופיע שוב. לא רק ערכים אלה תופסים שטח ברישום, ערכים אלה בסופו של דבר עלול לגרום בעיות תפעולי. לדוגמה, מאחר אינדקסים עבור הפונקציונליות הכנס-הפעל להשתמש בערכים עשרוניים ארבע ספרות, בעיה עלולה להתרחש בעת חיבור ההתקן 10,001.

כדי לפתור מגבלה זו הפונקציונליות הכנס-הפעל, ייתכן שתרצה להסיר מידע התקן מהרישום כאשר ההתקן כונן קשיח אשר אינו קיים עוד. באפשרותך לעשות זאת על-ידי שימוש בכלי השירות DevNodeClean של Microsoft .

כיצד לבנות עבור Windows Server 2003, Windows Server 2008, Windows Server 2008 R2 ו- Visual Studio 2005

כדי לנקות את הרישום עבור מחלקת דיסק GUID_DEVCLASS_DISKDRIVE GUID עבור GUID_DEVCLASS_VOLUME הדיסק המחלקה GUID, בצע את הפעולות הבאות.

הערה אנו ממליצים להשתמש בכלי השירות DevNodeClean עבור משימה זו. השלבים הבאים בדוגמת הקוד בשלב 7 ניתנים למטרות אינפורמטיביות בלבד.

  1. קריאה לפונקציה SetupDiGetClassDevs לקבל מידע עבור המחלקה המשויכת ה-GUID.

  2. קריאה לפונקציה SetupDiEnumDeviceInfo כדי להשיג מידע מופע עבור כל התקן במחלקה הנוכחית.

  3. קריאה לפונקציה CM_Get_DevNode_Status כדי לראות אם מידע התקן הנוכחי מייצג התקן חסר. לקבוע אם המצב פונקציה שווה CR_NO_SUCH_DEVINST או CR_NO_SUCH_VALUE.

  4. לחלופין, עבור התקן חסר, קרא לפונקציה CM_Get_Device_ID כדי להשיג את מזהה מופע ההתקן וכדי להציג את המזהה לפני שתסיר את המידע.

  5. עבור ההתקן חסר, השתמש מידע המחלקה שקיבלת בשלב 1 ואת המידע מופע שקיבלת בשלב 2. קריאה לפונקציה SetupDiCallClassInstaller (DIF_REMOVE,...) כדי להסיר את פרטי הרישום.

  6. כאשר יש עבר הטיפול כל ההתקנים במחלקה הנוכחית, קרא לפונקציה SetupDiDestroyDeviceInfoList כדי לנקות.

הערה בתרחישים מסוימים, ייתכן שיהיה עליך לנקות את הרישום לא רק עבור GUID_DEVCLASS_DISKDRIVE ו- GUID_DEVCLASS_VOLUME דיסק המחלקה Guid, אלא גם עבור המחלקה Guid הדיסק, GUID_DEVCLASS_SCSIADAPTER ואת GUID_DEVCLASS_VOLUMESNAPSHOT. כדי לעשות זאת, עליך לשנות את הגדרת DiskClassesToClean הקוד לדוגמה שלהלן.

היישום מסוף Win32 הבא הוא דוגמה של יישום מנקה את הרישום. כדי להשתמש ביישום זה, בצע את הפעולות הבאות.

מיקרוסופט מציעה דוגמאות תכנות לצורך ההדגמה בלבד, ללא אחריות, בין מפורשת ובין משתמעת. זה כולל, אך אינו מוגבל ל, אחריות מכללא לגבי סחירות או התאמה למטרה מסוימת. מאמר זה מבוסס על ההנחה שאתה מכיר את שפת התכנות המודגמת ובקי בהפעלת הכלים המשמשים ליצירת פרוצדורות ולניפוי שגיאות. מהנדסי התמיכה של 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 ו- 2012 Studio חזותי של Microsoft, בצע את הפעולות הבאות.

הערה אנו ממליצים להשתמש בכלי השירות 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. הרחב את תצורת המאפיינים, הרחב את מקשר (linker)ולאחר מכן לחץ על הקלט.

  10. בחר יחסי תלות נוספים, לחץ על החץ למטה ולאחר מכן בחר לערוך.

  11. בתיבת הדו-שיח יחסי תלות נוספים , סוג setupapi.lib ו cfgmgr32.lib.

  12. לחץ פעמיים על אישור.

  13. בנה את הפרויקט.

זקוק לעזרה נוספת?

הרחב את הכישורים שלך
סייר בהדרכה
קבל תכונות חדשות לפני כולם
הצטרף למשתתפי Microsoft insider

האם מידע זה היה שימושי?

עד כמה אתם מרוצים מאיכות השפה?
מה השפיע על החוויה שלכם?

תודה על המשוב!

×