Microsoft KB Archive/934234

= How to remove registry information about devices that will never be used again on a computer that is running Windows Server 2003 =

Article ID: 934234

Article Last Modified on 10/11/2007

-

APPLIES TO


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

-



INTRODUCTION
On a computer that is running Microsoft Windows Server 2003, a storage device that is connected by using a fiber channel or by using the iSCSI protocol may be connected only for a short time. When a storage device is connected, Windows Server 2003 creates registry information for the device. Over time, the registry may contain many entries for devices that will never be used again. This article describes how to remove this information from the registry.



MORE INFORMATION
When a new device is connected to a computer, Windows Server 2003 records information about the device in the registry. For most devices, this procedure is not a problem. However, after a storage device is presented by a logical unit number (LUN) by using a fiber channel or by using iSCSI, the device may never be seen again by the computer. For example, a device might be identified by a serial number or by SCSI pages 0x80 and 0x83.

Because of this situation, the registry may contain entries for devices that may never appear again. Not only do these entries occupy space in the registry, these entries may eventually cause operational problems. Because indexes for &quot;Plug and Play&quot; functionality use four digit decimal values, a problem may occur when device 10,001 is connected.

To resolve this limitation in &quot;Plug and Play&quot; functionality, you may want to remove device information from the registry when the device is a hard disk drive that is not present.

To clean the registry for the GUID_DEVCLASS_DISKDRIVE disk class GUID and for the GUID_DEVCLASS_VOLUME disk class GUID, follow these steps:
 * 1) Call the SetupDiGetClassDevs function to obtain information for the class that is associated with the GUID.
 * 2) Call the SetupDiEnumDeviceInfo function to obtain instance information for each device in the current class.
 * 3) Call the CM_Get_DevNode_Status function to see whether the current device information represents an absent device. Determine whether the function status is equal to CR_NO_SUCH_DEVINST or to CR_NO_SUCH_VALUE.
 * 4) Optionally, for an absent device, call the CM_Get_Device_ID function to obtain the device instance ID and to display the ID before you remove the information.
 * 5) For the absent device, use the class information that you obtained in step 1 and the instance information that you obtained in step 2. Call the SetupDiCallClassInstaller(DIF_REMOVE, …) function to remove the information from the registry.
 * 6) When all the devices in the current class have been handled, call the SetupDiDestroyDeviceInfoList function to clean up.

The following Win32 console application is an example of an application that cleans the registry. To use this application, follow these steps.

Microsoft provides programming examples for illustration only, without warranty either expressed or implied. This includes, but is not limited to, the implied warranties of merchantability or fitness for a particular purpose. This article assumes that you are familiar with the programming language that is being demonstrated and with the tools that are used to create and to debug procedures. Microsoft support engineers can help explain the functionality of a particular procedure. However, they will not modify these examples to provide added functionality or construct procedures to meet your specific requirements.  In Microsoft Visual Studio 2005, click New on the File menu, and then click Project. Expand Visual C++, and then click Win32. Click Win32 Console Application, type Cleanup in the Name text box, and then click OK. Click Finish in the Win32 Application Wizard dialog box. In Solution Explorer, expand Source Files, right-click Cleanup.cpp, and then click View Code.  Locate the following code: int _tmain(int argc, _TCHAR* argv[]) {   return 0; }   Replace the code that you found in step 6 with the following code. /**************************************************************************************************/    /*                                                                                                */     /* Copyright (c) 2007 Microsoft Corporation. All Rights Reserved                                */ /*                                                                                               */     /**************************************************************************************************/


 * 1) pragma warning( disable : 4201 ) // nonstandard extension used : nameless strut/union


 * 1) include <windows.h>
 * 2) include <stdlib.h>
 * 3) include <stdio.h>
 * 4) include <stddef.h>
 * 5) include <tchar.h>
 * 6) include <setupapi.h>
 * 7) include <cfgmgr32.h>
 * 8) include <initguid.h>
 * 9) include <devguid.h>


 * 1) define SIZECHARS(x) (sizeof((x))/sizeof(TCHAR))
 * 2) 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(&quot;-?&quot;)) == 0) ||                (lstrcmpi(pArgV[i], TEXT(&quot;/?&quot;)) == 0) ){

printf(&quot;\nCleanUp will remove phantom storage device nodes from this machine.\n\n&quot;); printf(&quot;Usage: CleanUp \n&quot;); printf(&quot;\twhere /n displays but does not remove the phantom devnodes.\n&quot;); printf(&quot;\nBackup and Restore privileges are required to run this utility.\n&quot;); return 0; }

//       // Check for -n, which means just list the devices that we would remove. //       if ( (lstrcmpi(pArgV[i], TEXT(&quot;-n&quot;)) == 0) ||             (lstrcmpi(pArgV[i], TEXT(&quot;/n&quot;)) == 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(&quot;CleanUp: Unable to verify Windows version, exiting...\n&quot;); return -1; }

if ((osvi.dwMajorVersion == 5) &&       ((osvi.dwMinorVersion == 1) || (osvi.dwMinorVersion == 2))) { }   else if (osvi.dwMajorVersion>=6) { }   else {       printf(&quot;CleanUp:  This utility is  designed to run on Windows XP/2003 and later\n&quot;); 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(&quot;CleanUp: %s will be removed.\n&quot;,                                   DeviceInstanceId);

//                           // Call DIF_REMOVE to remove the device's hardware // and software registry keys. //                           if (SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfoData )) {                               DevicesRemoved++; } else { printf(&quot;CleanUp: Error 0x%X removing phantom\n&quot;,                                       GetLastError); }                       } else { printf(&quot;CleanUp: %s would have been removed.\n&quot;,                                   DeviceInstanceId); }                   }                }            }

SetupDiDestroyDeviceInfoList(DeviceInfoSet); }   }

return DevicesRemoved; } </li> Click the Debug menu, and then click Start Debugging.</li></ol>

Additional query words: iSCSI LUN win2003

Keywords: kbhowto kbinfo kbcode kboem KB934234

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.