The Code Cave

January 4, 2007

Trigger a hardware detection scan from Delphi, InstallShield, C++, script or Run prompt

Filed under: Batch, Delphi, RegEdit, WINDOWS, XP, installation — Brian @ 2:04 pm

In my deployment process, it had looked like I was going to need to detect some changes in hardware and then perform a reboot.
I researched how to do this but it turns ou that I don’t need this code. Into the cave it goes.

You can of course run the “Add New Hardware” wizard manually. Here’s the command line to do just that:
“C:\WINDOWS\system32\rundll32.exe” C:\WINDOWS\system32\shell32.dll,Control_RunDLL “C:\WINDOWS\system32\hdwwiz.cpl”,Detect Hardware

However, what if you want to automate the process.

The information for how to do this is relatively scarce even though there is a technet page about it. Strangely enough the first thing I found was an NSIS script for doing this through that open source instalation program. The strange thing about it is that it was on a WinAMP website (link).

Here’s that code:

CODE:
  1. Function ScanForNewHW
  2. SetPluginUnload alwaysoff
  3. StrCpy $1 “”
  4.  
  5. System::Call ’setupapi::CM_Locate_DevNodeA(*i .r0, t r1, i r2) i .r3′
  6. System::Call ’setupapi::CM_Reenumerate_DevNode(i r0, i r4) i .r5′
  7.  
  8. SetPluginUnload manual
  9. System::Free 0
  10. FunctionEnd

Armed with the DLL name, the second thing I found was an Install Shield script (link) that allowed it to be done:

CODE:
  1. function ScanForHardwareChanges()
  2.   NUMBER devInst, myreturn;
  3. begin
  4.   if(UseDLL(WINSYSDIR ^ “cfgmgr32.dll”) != 0)then
  5.     MessageBox(“Didn’t load Dll”, SEVERE);
  6.     return FALSE;
  7.   endif;
  8.   myreturn = CM_Locate_DevNodeA(&devInst, \0, 0);
  9.   myreturn = CM_Reenumerate_DevNode(devInst, 0);
  10.   UnUseDLL(WINSYSDIR ^ “cfgmgr32.dll”);
  11.   return TRUE;
  12. end;

Armed with the DLL name and a possible procedure name, I was able to track down the Microsoft support page about it (link). That page provided a C routine for calling the code. Here it is:

C:
  1. BOOL ScanForHardwareChanges()
  2. {
  3.     DEVINST     devInst;
  4.     CONFIGRET   status;
  5.    
  6.     //
  7.     // Get the root devnode.
  8.     //
  9.    
  10.     status = CM_Locate_DevNode(&devInst, NULL, CM_LOCATE_DEVNODE_NORMAL);
  11.    
  12.     if (status != CR_SUCCESS) {
  13.         printf(“CM_Locate_DevNode failed: %x\n, status);
  14.         return FALSE;
  15.  
  16.     }
  17.    
  18.     status = CM_Reenumerate_DevNode(devInst, 0);
  19.    
  20.     if (status != CR_SUCCESS) {
  21.         printf(“CM_Reenumerate_DevNode failed: %x\n, status));
  22.         return FALSE;
  23.     }
  24.  
  25.     return TRUE;
  26. }

However, I wanted to do this in Delphi. With the correct constant names, I was able to find two references to this routine. The Delphi JEDI project has a provides a routine for loading the DLL that allows these calls to be made and either someone (link) translated Microsoft’s code into a routine for scanning for the hardware or there was a, now gone, JEDI demo project that included this routine. Either way, the French site was the first one I’d found that scanned for new hardware with Delphi.

Here is that code:

DELPHI:
  1. procedure SomeProcedure;
  2.   // First you need to load the module. 
  3.   LoadConfigManagerApi; 
  4.   // Then call a translation of the MS routine
  5.   ScanForHardwareChanges;
  6. end;
  7.  
  8. //  Here’s the translation of the ScanForHardwareChanges
  9. function ScanForHardwareChanges: boolean;
  10. var
  11.   dev: DEVINST;
  12.   status: CONFIGRET;
  13. begin
  14.  
  15.   status := CM_Locate_DevNode(dev, , CM_LOCATE_DEVNODE_NORMAL);
  16.  
  17.   if (status <> CR_SUCCESS) then
  18.   begin
  19.     result := FALSE;
  20.     exit;
  21.   end;
  22.  
  23.   status := CM_Reenumerate_DevNode(dev, 0);
  24.  
  25.   if (status <> CR_SUCCESS) then
  26.   begin
  27.     result := FALSE;
  28.     exit;
  29.   end;
  30.   Result := TRUE;
  31. end;

That routine was picked up on a Russian site (link) and modified to be independent of the JEDI files. However, both of these routines include way more information than is needed.

The process is really simple.
1. Load the DLL
2. Get the location of the two methods you need.
3. Call them (using the appropriate constants
4. Unload everything.

I’ve written my own Delphi routine that does all that and has no extra baggage dragged (drug?) along for the ride..

My all-in-one solution:

DELPHI:
  1. {******************************************************************************
  2.   ScanForHardwareChanges
  3.   by Brian Layman at TheCodeCave.com
  4. ******************************************************************************}
  5. function ScanForHardwareChanges: Boolean;
  6. const
  7.   CFGMGR32_DLL                 = ‘cfgmgr32.dll’;
  8.   CM_LOCATE_DEVNODE_NAME       = ‘CM_Locate_DevNodeA’;
  9.   CM_REENUMERATE_DEVNODE_NAME  = ‘CM_Reenumerate_DevNode’;
  10.   CM_LOCATE_DEVNODE_NORMAL     = $00000000;
  11.   CR_SUCCESS                   = $00000000;
  12. var
  13.    DeviceNode: DWord;
  14.    HCfgMgr: THandle;
  15.    CM_Locate_DevNode: function(var dnDevInst: DWord; pDeviceID: PAnsiChar;
  16.                                ulFlags: ULONG): DWord; stdcall;
  17.    CM_Reenumerate_DevNode: function(dnDevInst: DWord; ulFlags: ULong): DWord; stdcall;
  18. begin // ScanForHardwareChanges
  19.   Result := FALSE;
  20.   HCfgMgr := LoadLibrary(CFGMGR32_DLL);
  21.   if (HCfgMgr <32)
  22.   then MessageDlg(‘Error: could not find Configuration Manager DLL’, mtError, [mbOk], 0)
  23.   else begin
  24.     try
  25.       CM_Locate_DevNode := GetProcAddress(HCfgMgr, CM_LOCATE_DEVNODE_NAME);
  26.       CM_Reenumerate_DevNode := GetProcAddress(HCfgMgr, CM_REENUMERATE_DEVNODE_NAME);
  27.       if (CM_Locate_DevNode(DeviceNode, NIL, CM_LOCATE_DEVNODE_NORMAL) = CR_SUCCESS)
  28.       then Result := (CM_Reenumerate_DevNode(DeviceNode, 0) = CR_SUCCESS);
  29.     finally // wrap up
  30.       FreeLibrary(HCfgMgr);
  31.     end;    // try/finally
  32.   end;
  33. end// ScanForHardwareChanges

As a bonus, here it is combined into a project that scans for new hardware and then reboots the computer.
(more…)

January 3, 2007

How to remove the Internet and Mail icons from the Start Menu with RegEdit

Filed under: RegEdit, Registry, WINDOWS, XP — Brian @ 9:45 am

There’s always the easy way. by Right clicking and choosing properties on the start bar:
Just click away...

But here’s the quick and dirty… Create a .reg file with this content and apply it.
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows
\CurrentVersion\Explorer\StartPage]
“Favorites”=hex:00
“FavoritesChanges”=dword:00000001
“FavoritesResolve”=hex:00,00,00,00,00,00,00,00

Scripters, here are the commands to do it from a batch file

DOS:
  1. :: Clear the pinned icons
  2. REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /V "Favorites" /T REG_BINARY /D 00 /F
  3. REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /V "FavoritesResolve" /T REG_BINARY /D 0000000000000000 /F
  4. REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /V "FavoritesChanges" /T REG_DWORD /D 00000001 /F

Powered by WordPress