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

January 4, 2007

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]
Function ScanForNewHW
SetPluginUnload alwaysoff
StrCpy $1 ""

System::Call 'setupapi::CM_Locate_DevNodeA(*i .r0, t r1, i r2) i .r3'
System::Call 'setupapi::CM_Reenumerate_DevNode(i r0, i r4) i .r5'

SetPluginUnload manual
System::Free 0
FunctionEnd
[/code]

Armed with the DLL name, the second thing I found was an Install Shield script (link) that allowed it to be done:
[code]
function ScanForHardwareChanges()
NUMBER devInst, myreturn;
begin
if(UseDLL(WINSYSDIR ^ "cfgmgr32.dll") != 0)then
MessageBox("Didn't load Dll", SEVERE);
return FALSE;
endif;
myreturn = CM_Locate_DevNodeA(&devInst, "\0", 0);
myreturn = CM_Reenumerate_DevNode(devInst, 0);
UnUseDLL(WINSYSDIR ^ "cfgmgr32.dll");
return TRUE;
end;
[/code]

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]
BOOL ScanForHardwareChanges()
{
DEVINST devInst;
CONFIGRET status;

//
// Get the root devnode.
//

status = CM_Locate_DevNode(&devInst, NULL, CM_LOCATE_DEVNODE_NORMAL);

if (status != CR_SUCCESS) {
printf(“CM_Locate_DevNode failed: %x\n”, status);
return FALSE;

}

status = CM_Reenumerate_DevNode(devInst, 0);

if (status != CR_SUCCESS) {
printf(“CM_Reenumerate_DevNode failed: %x\n”, status));
return FALSE;
}

return TRUE;
}
[/c]

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]
procedure SomeProcedure;
// First you need to load the module.
LoadConfigManagerApi;
// Then call a translation of the MS routine
ScanForHardwareChanges;
end;

// Here’s the translation of the ScanForHardwareChanges
function ScanForHardwareChanges: boolean;
var
dev: DEVINST;
status: CONFIGRET;
begin

status := CM_Locate_DevNode(dev, ”, CM_LOCATE_DEVNODE_NORMAL);

if (status <> CR_SUCCESS) then
begin
result := FALSE;
exit;
end;

status := CM_Reenumerate_DevNode(dev, 0);

if (status <> CR_SUCCESS) then
begin
result := FALSE;
exit;
end;
Result := TRUE;
end;
[/delphi]

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]
{******************************************************************************
ScanForHardwareChanges
by Brian Layman at TheCodeCave.com
******************************************************************************}
function ScanForHardwareChanges: Boolean;
const
CFGMGR32_DLL = ‘cfgmgr32.dll’;
CM_LOCATE_DEVNODE_NAME = ‘CM_Locate_DevNodeA’;
CM_REENUMERATE_DEVNODE_NAME = ‘CM_Reenumerate_DevNode’;
CM_LOCATE_DEVNODE_NORMAL = $00000000;
CR_SUCCESS = $00000000;
var
DeviceNode: DWord;
HCfgMgr: THandle;
CM_Locate_DevNode: function(var dnDevInst: DWord; pDeviceID: PAnsiChar;
ulFlags: ULONG): DWord; stdcall;
CM_Reenumerate_DevNode: function(dnDevInst: DWord; ulFlags: ULong): DWord; stdcall;
begin // ScanForHardwareChanges
Result := FALSE;
HCfgMgr := LoadLibrary(CFGMGR32_DLL);
if (HCfgMgr < 32)
then MessageDlg('Error: could not find Configuration Manager DLL', mtError, [mbOk], 0)
else begin
try
CM_Locate_DevNode := GetProcAddress(HCfgMgr, CM_LOCATE_DEVNODE_NAME);
CM_Reenumerate_DevNode := GetProcAddress(HCfgMgr, CM_REENUMERATE_DEVNODE_NAME);
if (CM_Locate_DevNode(DeviceNode, NIL, CM_LOCATE_DEVNODE_NORMAL) = CR_SUCCESS)
then Result := (CM_Reenumerate_DevNode(DeviceNode, 0) = CR_SUCCESS);
finally // wrap up
FreeLibrary(HCfgMgr);
end; // try/finally
end;
end; // ScanForHardwareChanges
[/delphi]

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

To test this yourself, just create a basic project1 unit1 project, put a TButton on the form, paste this text over unit1′s existing code, and then double click the button. You’ll then have a compilable program. You can modify it to eliminate the form if you want and do all of this between begin and end in the project unit itself.

Here you go:
[delphi]
// ****************************************************************************
// Project1 04/Jan/2007
//
// Written by Brian Layman (AKA Capt. Queeg AKA SilverPaladin)
// Visit him at http://www.TheCodeCave.com
//
// This is a simple demonstration to show how a Delphi program can be used
// to detect new hardware and reboot.
//
// Warning: I can’t think of any way that this routine could cause harm to .
// your computer, but it is a good best practice to understand every line
// of new code before you run it. Who knows what could be lurking. Better
// yet, do not run this example at all. You should stop right now and erase
// the files. For if it causes blue smoke to be emitted from your network
// card, if it erases all users from your computer, or if it makes your
// sister break up with her lawyer boyfriend and start dating a caver, it
// is not my fault. (Actually that last one might be an improvement, but
// it is still not my fault.) But the fact of the matter is, computers
// have a mind of their own and we programmers live on the wild side.
//
// Usage: Project1.exe
// Run it. Press the button. WARNING YOU WILL REBOOT AND MAY LOOSE WORK.
//
// History:
// 04/Jan/2007 – BL – Created
//
// ****************************************************************************
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ShellAPI;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

{******************************************************************************
SetTokenPrivilege
A helper function that enables or disables specific privileges on the
specified computer. A NIL in SystemName means the privilege will be granted
for the current computer. Any other value must match the name of a computer
on your network.
******************************************************************************}
procedure SetTokenPrivilege(aSystemName: PChar; aPrivilegeName: PChar; aEnabled: Boolean);
var
TTokenHd: THandle;
TTokenPvg: TTokenPrivileges;
cbtpPrevious: DWORD;
rTTokenPvg: TTokenPrivileges;
pcbtpPreviousRequired: DWORD;
TokenOpened, ValueFound: Boolean;
const
// Custom Constants
// The SE_PRIVILEGE_DISABLED = 0 is an assumption that works.
// The default I’ve seen retrieved was 2012309862 I suspect that was just junk bits
SE_PRIVILEGE_DISABLED = 0;
begin // SetTokenPrivilege
// The privilege system is only available on NT and beyond
if (Win32Platform = VER_PLATFORM_WIN32_NT)
then begin
// Retrieve the Token that represents this current application session
TokenOpened := OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,
TTokenHd);

// Check for failure
if (not TokenOpened)
then raise Exception.Create(‘The current user does not have the access ‘ +
‘required to run this program.’)
else begin
// Get the name of the privilege (since Windows is multi-lingual, this must be done)
ValueFound := LookupPrivilegeValue(aSystemName, aPrivilegeName, TTokenPvg.Privileges[0].Luid) ;
TTokenPvg.PrivilegeCount := 1;

// Enable or disable the flag according to the bool passed
if (aEnabled)
then TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_DISABLED; // See declaration
cbtpPrevious := SizeOf(rTTokenPvg) ;
pcbtpPreviousRequired := 0;
if (not ValueFound)
then raise Exception.Create(‘This program is incompatible with the ‘ +
‘operating system installed on this computer.’)
else begin
try
// Adjust the permissions as required.
Windows.AdjustTokenPrivileges(TTokenHd, False, TTokenPvg, cbtpPrevious,
rTTokenPvg, pcbtpPreviousRequired);
except
raise Exception.Create(‘The current user does not have the required ‘ +
‘access to load a registry hive.’)
end;
end;
end
end;
end; // SetTokenPrivilege

{******************************************************************************
GrantPrivilege
This routine grants the privilege(s) needed to access the hidden system hive
and load it into memory.
******************************************************************************}
procedure GrantPrivilege(aPrivilegeName: String);
begin // GrantPrivilege
SetTokenPrivilege(NIL, PChar(aPrivilegeName), TRUE);
end; // GrantPrivilege

{******************************************************************************
RevokePrivilege
This routine revokes privilege(s) given in GrantPrivilege
******************************************************************************}
procedure RevokePrivilege(aPrivilegeName: String);
begin // RevokePrivilege
SetTokenPrivilege(NIL, PChar(aPrivilegeName), FALSE);
end; // RevokePrivilege

{******************************************************************************
RebootSystem
******************************************************************************}
function RebootSystem(Message: String; Timeout: DWord;
ForceClose: WordBool = FALSE): WordBool;
begin // RebootSystem
if (Message = ”) then Message := #0; //null terminate for next

GrantPrivilege(‘SeShutdownPrivilege’);
try
Result := InitiateSystemShutdown(NIL, @Message[1], TimeOut, ForceClose, TRUE);
finally
RevokePrivilege(‘SeShutdownPrivilege’);
end;
end; // RebootSystem

{******************************************************************************
ScanForHardwareChanges
******************************************************************************}
function ScanForHardwareChanges: Boolean;
const
CFGMGR32_DLL = ‘cfgmgr32.dll’;
CM_LOCATE_DEVNODE_NAME = ‘CM_Locate_DevNodeA’;
CM_REENUMERATE_DEVNODE_NAME = ‘CM_Reenumerate_DevNode’;
CM_LOCATE_DEVNODE_NORMAL = $00000000;
CR_SUCCESS = $00000000;
var
DeviceNode: DWord;
HCfgMgr: THandle;
CM_Locate_DevNode: function(var dnDevInst: DWord; pDeviceID: PAnsiChar;
ulFlags: ULONG): DWord; stdcall;
CM_Reenumerate_DevNode: function(dnDevInst: DWord; ulFlags: ULong): DWord; stdcall;
begin // ScanForHardwareChanges
Result := FALSE;
HCfgMgr := LoadLibrary(CFGMGR32_DLL);
if (HCfgMgr < 32)
then MessageDlg(‘Error: could not find Configuration Manager DLL’, mtError, [mbOk], 0)
else begin
try
CM_Locate_DevNode := GetProcAddress(HCfgMgr, CM_LOCATE_DEVNODE_NAME);
CM_Reenumerate_DevNode := GetProcAddress(HCfgMgr, CM_REENUMERATE_DEVNODE_NAME);
if (CM_Locate_DevNode(DeviceNode, NIL, CM_LOCATE_DEVNODE_NORMAL) = CR_SUCCESS)
then Result := (CM_Reenumerate_DevNode(DeviceNode, 0) = CR_SUCCESS);
finally // wrap up
FreeLibrary(HCfgMgr);
end; // try/finally
end;
end; // ScanForHardwareChanges

{******************************************************************************
Button1Click
******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin // Button1Click
if (ScanForHardwareChanges)
then RebootSystem(‘Hardware change Successful’, 15);
end; // Button1Click

end.

[/delphi]

Share and Enjoy:
  • del.icio.us
  • Fark
  • Reddit
  • Digg
  • DZone
  • email
  • Facebook
  • FriendFeed
  • Google Bookmarks
  • Netvibes
  • Ping.fm
  • Posterous
  • Slashdot
  • StumbleUpon
  • Suggest to Techmeme via Twitter
  • Technorati
  • Tumblr
  • Yahoo! Bookmarks
  • Add to favorites
  • Blogosphere News
  • HackerNews
  • Identi.ca
  • LinkedIn
  • MySpace
  • Print
  • Yahoo! Buzz

Comments

2 Responses to “Trigger a hardware detection scan from Delphi, InstallShield, C++, script or Run prompt”

  1. someone on May 30th, 2008 1:08 pm

    Year and a half old but still it was usefull. Thanks man ;) Can’t stand using huge libraries just for a few lines of code…

  2. Raven on November 27th, 2008 11:25 am

    Thanks for this article. It was very useful for me
    з.ы. Перевод статьи на русский посредством i18ln – жжот!

Got something to say?





Who is Brian Layman

I am a WordPress expert living in North East Ohio. I am part of the ever expanding Open Source Internet workforce. I am able to stay at home, with my wife and four home schooled kids, while working as the Senior Developer for b5media - a blogging network that has hosted over 300+

I co-host the NEO WordPress Monthly meetup. I am the board chair of our local church. I host and have provided development services for clients such TV personalities Rhett and Link as well as corporations such as Borland International.

In my spare time I try to sneak out, canoe, mountain bike and camp as often as I can. Sometimes I also defend the earth against zombies and aliens, but usually not during the camping trips.

Services Provided

In providing hosting, email, theme and plugin development to my clients, I function as a single point of contact answering to the needs of their expanding sites.

My service portfolio includes but is not limited to WordPress hosting, optimization, theme development and custom plugin creation. Community creation via vBulletin, Ning and BuddyPress and bbpress

I also am well experienced in site conversion, transition and merges. To clarify this, website technologies change and giving up your data is not an option. I have transitioned literally hundreds of sites from one platform to another.

viagra 50 mg indian version of viagra cialis cheapest viagra india online viagra cost comparison viagra for sale without prescription generic tadalafil online buy viagra in korea indian levitra discount cialis online viagra prescription over the counter vardenafil cialis otc cialis no rx cialis 30 mg viagra ranbaxy buy levitra in uk cialis low price tadalafil tablets 10mg cheap viagra fast shipping cheap generic levitra cialis discount cialis 5mg viagra discount prices buy levitra without prescription vardenafil online generic levitra canada viagra professional price cheapest sildenafil citrate indian version of cialis viagra lowest price viagra online prescriptions tadalafil 10mg levitra over the counter levitra prescriptions online buy viagra without a prescription liquid tadalafil citrate buy viagra prescription online tadalafil 20mg india india viagra generic sildenafil citrate for sale vardenafil hcl 10mg cialis discount coupon buy levitra australia viagra over the counter in canada liquid sildenafil tadalafil price comparison viagra cost in india cialis mail order sildenafil sales buy vardenafil cialis offer cheap vardenafil generic cialis no prescription viagra tabs generic indian names viagra price canada vardenafil hcl 20 mg generic viagra without prescription viagra by scilla biotechnologies buy generic cialis free viagra viagra over the counter viagra pills kamagra 100 mg cialis from india tadalafil australia tadalafil 20mg tablets tadalafil soft tabs sildenafil pills viagra no prescription required generic viagra paypal tadalafil online indian viagra cost tadalafil online pharmacy generic soft viagra sildenafil soft tablets viagra generic names buy viagra in ireland levitra without prescription levitra online purchase cialis pill indian tadalafil levitra 5mg cialis cost per pill tadalafil oral jelly sildenafil no prescription vardenafil price generic cialis 10mg cheap cialis no prescription order sildenafil citrate indian generic viagra blue viagra buy cialis usa apcalis 20mg tablets viagra overnight delivery sildenafil india purchase viagra without a prescription viagra prescriptions order viagra without prescription viagra with no prescription levitra for sale purchase viagra canada discount levitra viagra 200mg cheap viagra 100mg cialis overnight delivery buy sildenafil online viagra made in india cialis tabs 10mg viagra indian pharmacy viagra for sale in ireland viagra uk prices buy viagra in europe generic cialis india levitra online viagra for sale india buy viagra in dublin generic cialis soft tabs viagra 50mg cost generic sildenafil 100mg tadalafil generic viagra super active 100 mg kamagra 100mg sildenafil 100 mg tablets cialis no prescription viagra low price online cialis suhagra tablets buy cialis daily use tadalafil sample cialis prices viagra prescription online buy cialis pill kamagra from india cialis online levitra mg vigora india vardenafil 10 mg sildenafil citrate 100mg buy viagra in india buy cialis professional viagra in india buy viagra in singapore generic revatio viagra substitutes sildenafil canada viagra no script cheap kamagra viagra retail price cheap lovegra order viagra uk buy cialis in mexico viagra prescription price purchase cialis online without prescription online cialis prescription ranbaxy caverta buy viagra in hong kong sildenafil price cialis mastercard buy viagra in england viagra mail order canada cialis tablets for sale order cialis cialis soft tabs generic levitra india tadalafil prices cheap sildenafil citrate tablets cialis online prescriptions cialis 5 mg daily levitra prices prescriptions viagra viagra over the counter alternative cialis 20 mg tablets cialis generic india cialis prescribing cialis 20mg daily sildenafil 50 mg viagra drug prices tadalafil generic india cialis sale viagra prices buy viagra 50 mg levitra pharmacy buy viagra generic viagra prescription drug cialis daily cost vardenafil uk viagra soft tabs online buy viagra super active cialis 10mg price 25mg viagra silagra 100mg online viagra prescriptions cialis prescription cheap cialis india revatio 20 mg indian equivalent of viagra tadalafil india viagra capsules cheapest viagra buy cialis without prescription tadalafil overnight cheap tadalafil online purchase viagra online no prescription