<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0QESXc8fyp7ImA9WhRVFUw.&quot;"><id>tag:blogger.com,1999:blog-27669260</id><updated>2012-01-13T23:28:28.977-05:00</updated><category term="VBScript" /><category term="C++" /><category term="setupapi" /><category term="WMI" /><category term="drivers" /><category term="security" /><category term="programming" /><category term="windows" /><category term="free stuff" /><category term=".net" /><category term="desktop engineer" /><category term="MSI" /><category term="imaging" /><category term="vb.net" /><category term="DOS" /><category term="WIM" /><title>Rob's Blog</title><subtitle type="html">Personal blog on Desktop Engineer things that I've learned or am currently learning.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://robhaupt.blogspot.com/" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/blogspot/ALKg" /><feedburner:info uri="blogspot/alkg" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0IGQHk4eCp7ImA9WxVXE0g.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-4125201709747743139</id><published>2009-02-11T08:27:00.003-05:00</published><updated>2009-02-11T08:38:41.730-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-11T08:38:41.730-05:00</app:edited><title>Controlling the Order that Services start</title><content type="html">The other day I had a problem where a new service was starting, but it seemed to delay the start of another service which I needed to be available early in the boot (Say at the GINA). &lt;br /&gt;&lt;br /&gt;A quick google found that Services can be a part of Service Groups.  The Service Groups can be ordered by using the registry editor.  The Order is listed at&lt;br /&gt;&lt;br /&gt;HKLM\SYSTEM\CurrentControlSet\Control\ServiceGroupOrdering&lt;br /&gt;&lt;br /&gt;The list is in the form of a multi-string value.  Services are started from top to bottom.  To delay a service you can just move the Service Group it belongs to down.   A little thought is required since you are moving the order that services are started.  You don't want to start a service before its dependent services have all started. &lt;br /&gt;&lt;br /&gt;To find out which group a service belongs to you can go to&lt;br /&gt;&lt;br /&gt;HKLM\SYSTEM\CurrentControlSet\Services&lt;br /&gt;&lt;br /&gt;Find your service and look for the Group value name.  It looks like it is possible for a service to not have a group.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-4125201709747743139?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/4125201709747743139/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=4125201709747743139" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/4125201709747743139?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/4125201709747743139?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/sojWRNXvZQU/controlling-order-that-services-start.html" title="Controlling the Order that Services start" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2009/02/controlling-order-that-services-start.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQMRn8ycCp7ImA9WxdbE04.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-105905505727147522</id><published>2008-08-08T22:34:00.002-04:00</published><updated>2008-08-09T21:56:27.198-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-09T21:56:27.198-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Using DPInst</title><content type="html">Someday you may need to install a driver on a windows system.  If you are in an enterprise environment, you may have a few requirements.  First, you don't want the end-user prompted to install drivers.  They may actually do it and end up installing something you don't want them to install.  That brings us to a second need, a silent install.  We don't want the user to be interupted.  Lastly, it is important to have some flexibility on what were installing.  For instance, maybe we only want to install the driver if the device is installed.  OR maybe we want to pre-install a driver for later use.  Whatever our case may be, &lt;a href="http://msdn.microsoft.com/en-us/library/ms790308.aspx"&gt;DPInst&lt;/a&gt; is a good solution in most cases.&lt;br /&gt;&lt;br /&gt;First things first, you can download DPInst as part of the Driver Installation Framework from Microsoft's &lt;a href="http://www.microsoft.com/whdc/driver/install/DIFxtls.mspx"&gt;WHDC&lt;/a&gt; site. You may instead want to install the full &lt;a href="http://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx"&gt;Windows Driver Kit&lt;/a&gt; (WDK) which will include future updates to DPInst.&lt;br /&gt;&lt;br /&gt;You can refer to the &lt;a href="http://msdn.microsoft.com/en-us/library/ms790806.aspx"&gt;command-line switches&lt;/a&gt; for more info, but here are some of the more useful switches.&lt;br /&gt;&lt;br /&gt;/path&lt;br /&gt;&lt;br /&gt;This switch changes the DPInst working directory.  Normally DPInst will only search the directory it is ran from.&lt;br /&gt;&lt;br /&gt;/s&lt;br /&gt;&lt;br /&gt;Switches to silent mode.  This will quietly install drivers.&lt;br /&gt;&lt;br /&gt;/LM&lt;br /&gt;&lt;br /&gt;Uses Legacy mode to install drivers.  That allows you to install drivers that aren't signed.&lt;br /&gt;&lt;br /&gt;/sh&lt;br /&gt;&lt;br /&gt;Scans your hardware and installs only if the device is present and the new driver is better than what is already installed.&lt;br /&gt;&lt;br /&gt;/se /sa /sw&lt;br /&gt;&lt;br /&gt;These are for suppressing EULA, Add/Remove Programs Entry, and the Wizard in that order.  The silent switch should take care of the first and last switch.  The Add/Remove Programs Entry you may want to remove.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-105905505727147522?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/105905505727147522/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=105905505727147522" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/105905505727147522?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/105905505727147522?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/eYT-pArg-bU/using-dpinst.html" title="Using DPInst" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/08/using-dpinst.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUGQX0zeyp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-1391509148801564430</id><published>2008-07-28T22:20:00.008-04:00</published><updated>2009-03-06T08:47:00.383-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:47:00.383-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="VBScript" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>My five VBScript 'best practices'</title><content type="html">&lt;span style="font-family:arial;"&gt;I've been programming in VBScript for a while now.  Over that time I've seen some things that for better or worse made me take note.  I thought that I would share those, in an attempt to at worst open a dialogue on some level and at best convince some VBScripters to slightly modify their actions.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;1. Misuse of On Error Resume Next&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;The &lt;/span&gt;&lt;a style="font-family: arial;" href="http://msdn.microsoft.com/en-us/library/5hsw66as%28VS.80%29.aspx"&gt;On Error Resume Next&lt;/a&gt;&lt;span style="font-family:arial;"&gt; statement can be quite useful, but all too often it finds its way to the top of a VBScript.  Doing this will basically render the entire script free of errors.    The statement does have its uses though.  Lets say that I want to open a file for writing.  Lets consider the things that could go wrong&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul style="font-family: arial;"&gt;&lt;li&gt;No Permission to write there&lt;/li&gt;&lt;li&gt;File exists already&lt;/li&gt;&lt;li&gt;File is locked&lt;/li&gt;&lt;li&gt;Disk is full&lt;/li&gt;&lt;li&gt;User doesn't have enough disk quota space&lt;/li&gt;&lt;li&gt;Saving to Network Drive that is offline&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:arial;"&gt;We could spend half a day and code around each one of these items.  Instead we could do the following:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;On Error Resume Next&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;&lt;code&gt;&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;If Err Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;    HandleError&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;    Err.Clear    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;On Error Goto 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;What happens here is that everything between the On Error Resume Next and the On Error Goto 0 statement don't raise errors.  Everything before and after will still cause issues.  We can test for errors by checking the Err variable.  It returns true for non-zero numbers.  So if we have an error code we enter the condition and handle the error.  Once done handling our error we call Err.Clear.  This clears out the error code so when we test it later in the code we don't get this error.  The last statement simply turns error suppression back off.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Also, if you call On Error Resume Next in a function or subroutine then it will only stay in effect for that function and all calls made by that function.  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I prefer the second option, just because I like knowing where error suppression starts and stops.  With the second option, you can turn on error suppression in one function, call a second function and still have error suppression turned on.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;My main point in all of this, is that you have to know where your script is failing.  Covering up the problems will curse you sooner or later.  Its ok to use error suppression, but so long as you are handling the problems when they arise.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-family:arial;"&gt;2. Not using Option Explicit&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I'd almost like to say as a general rule, you should take both this and the previous rule together and for every script that has On Error Resume Next as the first line of code, should be replaced with &lt;/span&gt;&lt;a style="font-family: arial;" href="http://msdn.microsoft.com/en-us/library/zcd4xwzs%28VS.80%29.aspx"&gt;Option Explicit&lt;/a&gt;&lt;span style="font-family:arial;"&gt;.  In fact most every script should have Option Explicit as the first line.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;What Option Explicit will do for you, is make sure your variables are declared.  It does this, by not allowing undeclared variables in your code. So if I said&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;Option Explicit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;i = 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I'd get an error of "Variable is undefined 'i'"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I'd have to add&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;Option Explicit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;dim i&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;i = 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;You can add multiple variables by separating them by commas&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;dim LastName, FirstName, BirthDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;All this will save you the hassle of debugging your code only to find out that you mistyped your variable name.  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;This may seem like a lot of work to do.  Ultimately though, it is only really 2 lines of code.  Once to turn this option on and a second to declare your variables.  What you gain is completely eliminating one of the more common reasons why scripts fail.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-family:arial;"&gt;3. Don't repeat yourself&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I've seen a lot of scripts that are three or even four times longer than they need to be.  This happens because they are simply copying and pasting their code and only modifying one or two parts.  Whenever you find yourself in this situation, you should immediately start thinking of sub routines.  Sometimes you may not notice until after you've written your script.  In those cases, if you ever think that you'll need to modify this script you should go back and refactor it correctly.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Here is an example of what we can refactor.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;ItemToWrite = Items(ItemOne)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WshShell.RegWrite "HKLM\Software\MyProduct\ItemOne", ItemToWrite&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;ItemToWrite = Items(ItemTwo)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WshShell.RegWrite "HKLM\Software\MyProduct\ItemTwo", ItemToWrite&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;ItemToWrite = Items(ItemThree)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WshShell.RegWrite "HKLM\Software\MyProduct\ItemThree", ItemToWrite&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;This gets refactored into&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WriteKey "HKLM\Software\MyProduct\ItemOne",Items(ItemOne)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WriteKey "HKLM\Software\MyProduct\ItemTwo",Items(ItemTwo)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WriteKey "HKLM\Software\MyProduct\ItemThree",Items(ItemThree)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;Sub WriteKey(KeyPath,ItemToWrite)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;    WshShell.Regwrite KeyPath,ItemToWrite&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Now we have one line per item instead of two and a single point where we are writing to the registry.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;But, lets go a bit further.  In this code we repeat "HKLM\Software\MyProduct\" three times.  What happens if we misspelled one of those lines.  Worse is if we need to change it.  We now have to change three lines.  Lets change this to&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;Const MYKEY = "HKLM\Software\MyProduct\"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WriteKey MYKEY &amp;amp; "ItemOne",Items(ItemOne)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WriteKey MYKEY &amp;amp; "ItemTwo",Items(ItemTwo)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;WriteKey MYKEY &amp;amp; "ItemThree",Items(ItemThree)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;Sub WriteKey(KeyPath,ItemToWrite)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;    WshShell.Regwrite KeyPath,ItemToWrite&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:arial;" &gt;End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;We did add a line, but in turn we saved our self the trouble of changing three lines whenever we change that key path. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Whenever you intend to use a string or a number several times, it is best to simply put it in a constant and simply reference it.  If you need to modify the string once and then use it multiple times, I'd recommend just using a variable instead of a constant.  Either way it will help you when modifying your code.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-family:arial;"&gt;4. Not using descriptive variable names&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;In some of my examples, you may see me using a single letter for a variable (Such as i).  In practice though this is only good in a few specific examples.  Many scripts that are giving examples of some technique will often use a non-descriptive variable(s).  I think this leads to individuals using non-descriptive variables in their actual code.  Your script will determine your level of descriptiveness, but sometimes just saying 'Name' can be good.  Othertimes you'll need "LastName'.  Either is better than 'n'.  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I deviate from this in one distinct way.  When using a loop that has a variable to be used as the index of an array I'll likely use just 'i'. This is fairly common.  Sometimes nested for loops for will i and then j.  At this point you may be better off using 'Row' and 'Col'.  Again, that all depends on your situation.  In those situations though, you are using a variable in a single location and not interspersed throughout your code.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-family:arial;"&gt;5. Not using Comments&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;I look at programming/scripting languages as a compromise in communicating your actions with the computer and with other users.  Comments allow us to extend our communication with the user.  By user, I don't just mean you.  I also mean the next person who gets the 'joy' of reading your code.  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;A lot of people do believe in writing comments, but still don't get it right.  A comment should be used to say why you did something, not what you did.  Most mediocre scripters will be able to take your script and decipher what you did.  What they won't be able to do, is figure out why you wrote the code you did.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;Taking this approach can sometimes mean writing less comments than you normally would.  &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.codinghorror.com/blog/archives/001150.html"&gt;Jeff Atwood&lt;/a&gt;&lt;span style="font-family:arial;"&gt; expanded on the idea of commenting on why you did something and had some excellent suggestions on what you can do to be more descriptive with your intent.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-1391509148801564430?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/1391509148801564430/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=1391509148801564430" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1391509148801564430?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1391509148801564430?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/ovQtmfrDO7w/my-five-vbscript-best-practices.html" title="My five VBScript 'best practices'" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/07/my-five-vbscript-best-practices.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIDR385fCp7ImA9WxdVF0U.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-2296480177839266832</id><published>2008-07-22T21:22:00.004-04:00</published><updated>2008-07-22T23:09:36.124-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-22T23:09:36.124-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Using Devcon</title><content type="html">A while back I wrote about using SetupAPI functions in VB.NET.  The goal was to be able to work with devices and ultimately enable and disable a device.&lt;br /&gt;&lt;br /&gt;The code was what I would eventually use, but initially I used Devcon.  Devcon is essentially the Device Manager over a command line.  It is &lt;a href="http://support.microsoft.com/kb/311272"&gt;freely available&lt;/a&gt;.  You can even get the source code from the &lt;a href="http://www.microsoft.com/whdc/devtools/ddk/default.mspx"&gt;Windows Server 2003 Driver Development Kit&lt;/a&gt; (DDK).  It may be available in the newer &lt;a href="http://www.microsoft.com/whdc/Devtools/wdk/default.mspx"&gt;Windows Driver Kit&lt;/a&gt; (WDK) as well.&lt;br /&gt;&lt;br /&gt;To demonstrate the usefulness of devcon, we can look at some examples from my blog and see how they coorelate to devcon commands&lt;br /&gt;&lt;br /&gt;&lt;a href="http://robhaupt.blogspot.com/2007/05/working-with-devices-retrieving-device.html"&gt;Retrieving Device Setup Class Names&lt;/a&gt; and &lt;a href="http://robhaupt.blogspot.com/2008/05/working-with-devices-getting-friendly.html"&gt;Getting Friendly Class Names&lt;/a&gt;:&lt;br /&gt;We can use the following command&lt;br /&gt;&lt;br /&gt;devcon classes&lt;br /&gt;&lt;br /&gt;This would give us output similar to:&lt;br /&gt;&lt;br /&gt;Listing 53 setup class(es).&lt;br /&gt;WCEUSBS             : Windows CE USB Devices&lt;br /&gt;USB                 : Universal Serial Bus controllers&lt;br /&gt;PnpPrinters         : IEEE 1394 and SCSI printers&lt;br /&gt;Dot4                : IEEE 1284.4 devices&lt;br /&gt;Dot4Print           : IEEE 1284.4 compatible printers&lt;br /&gt;CDROM               : DVD/CD-ROM drives&lt;br /&gt;Computer            : Computer&lt;br /&gt;DiskDrive           : Disk drives&lt;br /&gt;Display             : Display adapters&lt;br /&gt;fdc                 : Floppy disk controllers&lt;br /&gt;hdc                 : IDE ATA/ATAPI controllers&lt;br /&gt;Keyboard            : Keyboards&lt;br /&gt;MEDIA               : Sound, video and game controllers&lt;br /&gt;Modem               : Modems&lt;br /&gt;Monitor             : Monitors&lt;br /&gt;Mouse               : Mice and other pointing devices&lt;br /&gt;MTD                 : PCMCIA and Flash memory devices&lt;br /&gt;MultiFunction       : Multifunction adapters&lt;br /&gt;Net                 : Network adapters&lt;br /&gt;NetClient           : Network Client&lt;br /&gt;NetService          : Network Service&lt;br /&gt;NetTrans            : Network Protocol&lt;br /&gt;PCMCIA              : PCMCIA adapters&lt;br /&gt;Ports               : Ports (COM &amp;amp; LPT)&lt;br /&gt;Printer             : Printers&lt;br /&gt;SCSIAdapter         : SCSI and RAID controllers&lt;br /&gt;System              : System devices&lt;br /&gt;Unknown             : Other devices&lt;br /&gt;FloppyDisk          : Floppy disk drives&lt;br /&gt;Processor           : Processors&lt;br /&gt;MultiPortSerial     : Multi-port serial adapters&lt;br /&gt;SmartCardReader     : Smart card readers&lt;br /&gt;VolumeSnapshot      : Storage volume shadow copies&lt;br /&gt;1394Debug           : 1394 Debugger Device&lt;br /&gt;1394                : IEEE 1394 Bus host controllers&lt;br /&gt;Infrared            : Infrared devices&lt;br /&gt;Image               : Imaging devices&lt;br /&gt;TapeDrive           : Tape drives&lt;br /&gt;Volume              : Storage volumes&lt;br /&gt;Battery             : Batteries&lt;br /&gt;HIDClass            : Human Interface Devices&lt;br /&gt;61883               : 61883 Device Class&lt;br /&gt;LegacyDriver        : Non-Plug and Play Drivers&lt;br /&gt;SDHost              : Secure Digital host controllers&lt;br /&gt;UsbPcCardReader     : USB PC-Card Readers&lt;br /&gt;Avc                 : AVC Device Class&lt;br /&gt;Enum1394            : IEEE 1394 IP Network Enumerator&lt;br /&gt;MediumChanger       : Medium Changers&lt;br /&gt;NtApm               : NT Apm/Legacy Support&lt;br /&gt;SBP2                : SBP2 IEEE 1394 Devices&lt;br /&gt;Bluetooth           : Bluetooth Radios&lt;br /&gt;WPD                 : Windows Portable Devices&lt;br /&gt;USB                 : Motorola USB Device&lt;br /&gt;&lt;br /&gt;You'll note that we aren't receiving the Class Guid.  I'm not sure if this is that important anyway.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://robhaupt.blogspot.com/2008/05/working-with-devices-actually-getting.html"&gt;Actually Getting to the Devices&lt;/a&gt; and &lt;a href="http://robhaupt.blogspot.com/2008/06/working-with-devices-getting-device.html"&gt;Getting Device Names&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;There are a couple of ways we can do this.  The first option is to simply specify a class.  That happens with the =&lt;class&gt; argument&lt;br /&gt;&lt;br /&gt;devcon find =net&lt;br /&gt;&lt;br /&gt;PCI\VEN_14E4&amp;amp;DEV_169D&amp;amp;SUBSYS_105E147B&amp;amp;REV_11\4&amp;amp;1B41B794&amp;amp;0&amp;amp;00E0: Broadcom NetLink (TM) Gigabit Ethernet&lt;br /&gt;ROOT\CNTX_VPCNETS2_MP\0000                                  : Linksys Wireless-G USB Network Adapter #9 - Virtual Machine Network Services Driver&lt;br /&gt;ROOT\CNTX_VPCNETS2_MP\0009                                  : Broadcom NetLink (TM) Gigabit Ethernet - Virtual Machine Network Services Driver&lt;br /&gt;ROOT\CNTX_VPCNETS2_MP\0010                                  : Linksys Wireless-G USB Network Adapter #10 - Virtual Machine Network Services Driver&lt;br /&gt;ROOT\MS_L2TPMINIPORT\0000                                   : WAN Miniport (L2TP)&lt;br /&gt;ROOT\MS_NDISWANBH\0000                                      : WAN Miniport (Network Monitor)&lt;br /&gt;ROOT\MS_PSCHEDMP\0001                                       : Broadcom NetLink (TM) Gigabit Ethernet - Packet Scheduler Miniport&lt;br /&gt;ROOT\MS_PSCHEDMP\0002                                       : Linksys Wireless-G USB Network Adapter - Packet Scheduler Miniport&lt;br /&gt;ROOT\MS_PTIMINIPORT\0000                                    : Direct Parallel&lt;br /&gt;...&lt;br /&gt;31 matching device(s) found.&lt;br /&gt;&lt;br /&gt;We can also use&lt;br /&gt;&lt;br /&gt;devcon listclass Net&lt;br /&gt;&lt;br /&gt;To find all devices, even those that aren't present, we type&lt;br /&gt;&lt;br /&gt;devcon findall =Net&lt;br /&gt;&lt;br /&gt;We can also filter based on how the device is connected.  This command will show just PCI devices in the net class&lt;br /&gt;&lt;br /&gt;devcon find =Net PCI\*&lt;br /&gt;&lt;br /&gt;You can do this without even specifying the class as well.&lt;br /&gt;&lt;br /&gt;devcon find PCI\*&lt;br /&gt;&lt;br /&gt;&lt;a href="http://robhaupt.blogspot.com/2008/06/working-with-devices-getting-status-on.html"&gt;Getting Status on a Device&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;Similar to the last set of commands we can use&lt;br /&gt;&lt;br /&gt;devcon status =Net&lt;br /&gt;&lt;br /&gt;PCI\VEN_14E4&amp;amp;DEV_169D&amp;amp;SUBSYS_105E147B&amp;amp;REV_11\4&amp;amp;1B41B794&amp;amp;0&amp;amp;00E0&lt;br /&gt;    Name: Broadcom NetLink (TM) Gigabit Ethernet&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\CNTX_VPCNETS2_MP\0000&lt;br /&gt;    Name: Linksys Wireless-G USB Network Adapter #9 - Virtual Machine Network Se&lt;br /&gt;rvices Driver&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\CNTX_VPCNETS2_MP\0009&lt;br /&gt;    Name: Broadcom NetLink (TM) Gigabit Ethernet - Virtual Machine Network Servi&lt;br /&gt;ces Driver&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\MS_L2TPMINIPORT\0000&lt;br /&gt;    Name: WAN Miniport (L2TP)&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\MS_NDISWANBH\0000&lt;br /&gt;    Name: WAN Miniport (Network Monitor)&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\MS_PSCHEDMP\0001&lt;br /&gt;    Name: Broadcom NetLink (TM) Gigabit Ethernet - Packet Scheduler Miniport&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\MS_PSCHEDMP\0002&lt;br /&gt;    Name: Linksys Wireless-G USB Network Adapter - Packet Scheduler Miniport&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\MS_PSCHEDMP\0010&lt;br /&gt;    Name: Linksys Wireless-G USB Network Adapter #7 - Packet Scheduler Miniport&lt;br /&gt;    Driver is running.&lt;br /&gt;ROOT\MS_PTIMINIPORT\0000&lt;br /&gt;    Name: Direct Parallel&lt;br /&gt;    Driver is running.&lt;br /&gt;...&lt;br /&gt;31 matching device(s) found.&lt;br /&gt;&lt;br /&gt;The same arguments as last time can be used.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://robhaupt.blogspot.com/2008/06/working-with-devices-enablingdisabling.html"&gt;Enabling/Disabling a device&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;You can use wildcards again, although I usually am very explicit with what I am enabling or disabling.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;devcon disable @"HDAUDIO\FUNC_01&amp;amp;VEN_10EC&amp;amp;DEV_0880&amp;amp;SUBSYS_147B9B01&amp;amp;REV_1008\4&amp;amp;EEB356C&amp;amp;0&amp;amp;0001"&lt;br /&gt;HDAUDIO\FUNC_01&amp;amp;VEN_10EC&amp;amp;DEV_0880&amp;amp;SUBSYS_147B9B01&amp;amp;REV_1008\4&amp;amp;EEB356C&amp;amp;0&amp;amp;0001: Disabled&lt;br /&gt;1 device(s) disabled.&lt;br /&gt;&lt;br /&gt;devcon enable @"HDAUDIO\FUNC_01&amp;amp;VEN_10EC&amp;amp;DEV_0880&amp;amp;SUBSYS_147B9B01&amp;amp;REV_1008\4&amp;amp;EEB356C&amp;amp;0&amp;amp;0001"&lt;br /&gt;HDAUDIO\FUNC_01&amp;amp;VEN_10EC&amp;amp;DEV_0880&amp;amp;SUBSYS_147B9B01&amp;amp;REV_1008\4&amp;amp;EEB356C&amp;amp;0&amp;amp;0001: Enabled&lt;br /&gt;1 device(s) enabled.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;All this works quite well in most situations.  There were a couple reasons why I eventually opted with the VB.NET way of doing things.  First, efficiency.  There is a lot of overhead to enabling and disabling a device with Devcon.  This can slow down a program, especially when enabling and disabling a device can be quite time consuming in a computers way of imagining time.  500 milliseconds can be an eternity.  2-3 seconds can be a long time for a user to look at no progress.&lt;br /&gt;&lt;br /&gt;The Second reason is just the nature of devcon.  Since it is meant to be similar to the Device Manager itself, it acts like the Device Manager.  This means devices are disabled on a per-profile basis.  So, if you diable a device in one hardware profile and then boot in a different profile, it won't continue to be disabled.  In my particular project, this wasn't ideal.&lt;br /&gt;&lt;br /&gt;If these reasons aren't compelling enough for you to code this in .NET or C++, then you should look at using Devcon to accomplish your task.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-2296480177839266832?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/2296480177839266832/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=2296480177839266832" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/2296480177839266832?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/2296480177839266832?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/NGCi6v_iF4Y/using-devcon.html" title="Using Devcon" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/07/using-devcon.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04DSHc9fip7ImA9WxRbGU0.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-429639094977971798</id><published>2008-07-14T22:08:00.007-04:00</published><updated>2008-12-10T04:39:39.966-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-10T04:39:39.966-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Using RunOnceEx</title><content type="html">Last week we figured out how to run something once per user.  This week, we will look at running something once on a computer.  I'm sure that there are fifty different ways to do this.  Personally I like this method, because of three features:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Easily able to run multiple items&lt;/li&gt;&lt;li&gt;Easily able to sequence items&lt;/li&gt;&lt;li&gt;Shows progress with a GUI&lt;/li&gt;&lt;/ol&gt;RunOnceEx provides us with all of that.  We'll start with the registry key.&lt;br /&gt;&lt;br /&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx&lt;br /&gt;&lt;br /&gt;Inside of that is a value name you will create called TITLE (REG_SZ).  This will be the title displayed on the window showing the progress of our installation.&lt;br /&gt;&lt;br /&gt;We then create keys under that.  For convenience sake most people number them.  This also will help to sequence installs.  Inside each key, the default value will be the string that will be displayed when installing items in the key.  You create values (REG_SZ), each will be ran in alphabetical/numeric order.  The data can be pretty much anything.  MSI, EXE, BAT, VBS.  I'm not sure what else you'd need, but I think its covered.&lt;br /&gt;&lt;br /&gt;Once you've populated this registry structure you can reboot/logoff.  The next login that has rights to modify the RunOnceEx registry key will execute the keys in order.  Alternatively you can execute the RunOnceEx Process anytime with the following command:&lt;br /&gt;&lt;br /&gt;rundll32.exe iernonce.dll,RunOnceExProcess&lt;br /&gt;&lt;br /&gt;Please note that the DLL used here is from Internet Explorer.  At one point this command did not work when running IE7.  I believe this issue may have been addressed.  If not, the common workaround I've seen, is the use of the original IE6 dll and simply explicitly calling its path.  Regardless, simply logging in will kick off the process.&lt;br /&gt;&lt;br /&gt;Here is a sample of the registry for RunOnceEx.  Simply copy this into a file and save with a .REG extension.&lt;br /&gt;&lt;br /&gt;&lt;sample&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:arial;"&gt;Windows Registry Editor Version 5.00&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;"TITLE"="Installing Stuff"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\1]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;@="Notepad"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;"1"="C:\\WINDOWS\\notepad.exe"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx\2]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;@="Calculator x 2"&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:arial;"&gt;"1"="C:\\WINDOWS\\System32\\calc.exe"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;"2"="C:\\WINDOWS\\System32\\calc.exe"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is what the above item will look like&lt;br /&gt;&lt;br /&gt;&lt;/sample&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_oKEGrFRDnAc/SH1x2qRxdPI/AAAAAAAAAAg/s9Yw5MqHEDM/s1600-h/RunOnceEx.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_oKEGrFRDnAc/SH1x2qRxdPI/AAAAAAAAAAg/s9Yw5MqHEDM/s400/RunOnceEx.jpg" alt="" id="BLOGGER_PHOTO_ID_5223456326695351538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;sample&gt;&lt;picture&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;What will happen with the above example is Notepad will run, followed by two calculator processes.  Each process must end, before the next process begins.&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;a href="http://unattended.msfn.org/unattended.xp/view/web/31/"&gt;MSFN&lt;/a&gt;&lt;br /&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/picture&gt;&lt;/sample&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-429639094977971798?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/429639094977971798/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=429639094977971798" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/429639094977971798?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/429639094977971798?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/i8frHd_53Xw/using-runonceex.html" title="Using RunOnceEx" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_oKEGrFRDnAc/SH1x2qRxdPI/AAAAAAAAAAg/s9Yw5MqHEDM/s72-c/RunOnceEx.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/07/using-runonceex.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYCQ3Y8eyp7ImA9WxdbGE4.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-1761598170263031810</id><published>2008-07-08T21:20:00.003-04:00</published><updated>2008-08-15T15:56:02.873-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-15T15:56:02.873-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="VBScript" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Using Active Setup</title><content type="html">On more than one occasion I've had the need to change a user setting.  These settings may be replacing a file or a registry key.&lt;br /&gt;&lt;br /&gt;Possibly the first idea in solving this problem is to simply go through each user folder in Documents and Settings and work with each folder in sequence.  By doing this, you'll likely have some permission problems and also, if working with the registry, have the overhead of loading each registry hive for each user.  I've also found that depending on your environment you may be modifying profiles that are stale or completely obsolete.&lt;br /&gt;&lt;br /&gt;What we can use instead, is Active Setup. In a nutshell, Active Setup runs when a user logs into the workstation and compares their registry with the local machine.  For each entry found missing with the user's registry, it is executed.  Normally an entry will be executed once per user and at the time the user logs in.  You'll know it is running based on a small window in the top left corner popping up when the user logs in.&lt;br /&gt;&lt;br /&gt;To get started You should add the following&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\UniqueID&lt;uniqueid&gt;]&lt;br /&gt;"Version"="&lt;version&gt;"&lt;br /&gt;"Stubpath"="&lt;command&gt;"&lt;br /&gt;@="&lt;displayname&gt;"&lt;br /&gt;&lt;br /&gt;The UniqueID is just that.  If you look you'll see this is mostly Guids, but it doesn't have to be.  Of course you'll want this to be unique.&lt;br /&gt;&lt;br /&gt;Version is the version of what you'll be running.  Typically you won't have to change this.  Where it comes in handy is if you want to update this script and run it again under the same UniqueID.  If you update the version then the entry will be ran again.&lt;br /&gt;&lt;br /&gt;The Stubpath (Command) is the command that will be executed.  I have seen MSIs, EXEs, and VBScripts all run without issue.  I've also seen RunDll calls as well.&lt;br /&gt;&lt;br /&gt;The default valuename (@) is what will be displayed when the command is being executed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;a href="http://wikidesktop.org/index.php?title=Active_Setup"&gt;Active Setup - WikiDesktop&lt;/a&gt;&lt;br /&gt;&lt;a href="http://etlengineering.com/installer/activesetup.txt"&gt;etlengineering.com&lt;/a&gt;&lt;/displayname&gt;&lt;/command&gt;&lt;/version&gt;&lt;/uniqueid&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-1761598170263031810?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/1761598170263031810/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=1761598170263031810" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1761598170263031810?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1761598170263031810?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/FEaRAbeQxDw/using-active-setup.html" title="Using Active Setup" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/07/using-active-setup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MHQ349eip7ImA9WxdWFEQ.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-6583071105560723996</id><published>2008-06-30T23:35:00.003-04:00</published><updated>2008-07-08T00:30:32.062-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-08T00:30:32.062-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="free stuff" /><title>10 Tools every Desktop Engineer should have.</title><content type="html">While working on various projects and troubleshooting more than a few problems, I have found a few tools that are an absolute necessity to perform my typical duties.  All but one of these tools are free.  I'd like to present them here in no particular order.&lt;br /&gt;&lt;br /&gt;1. &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx"&gt;Process Monitor&lt;/a&gt;&lt;br /&gt;Some people may have used FileMon or RegMon.  This tool consolidates both tools into one.  For those who haven't used either, Process Monitor adds itself as a low level device and allows you to monitor all activity on your disk and registry.  I do mean all activity.  Running this for a matter of 5 seconds can generate over fifty thousand entries easily.  Luckily for us, there are excellent filters that allow us to comb through all this data.  Also, Mark Russinovich has several &lt;a href="http://www.microsoft.com/emea/spotlight/sessionh.aspx?videoid=346"&gt;recorded sessions&lt;/a&gt; showing how to use Process Monitor.&lt;br /&gt;&lt;br /&gt;2. &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx"&gt;Process Explorer&lt;/a&gt;&lt;br /&gt;This is a task manager replacement with a ton of extra features.  You can simply check an option to actually replace the task manager.  I should point out that this tool and the above tool were created by SysInternals and were eventually acquired by Microsoft.  At the &lt;a href="http://technet.microsoft.com/en-us/sysinternals/default.aspx"&gt;SysInternals site &lt;/a&gt;you can find more tools that are just as useful as these two tools.&lt;br /&gt;&lt;br /&gt;3. &lt;a href="http://www.wireshark.org/"&gt;Wireshark&lt;/a&gt;&lt;br /&gt;Just as Process Monitor showed you events on your system.  Wireshark shows you events going across your network connection.  This application was previously called Ethereal.  You can break down every packet coming from your system and see exactly what is being sent across the wire.&lt;br /&gt;&lt;br /&gt;4. &lt;a href="http://www.scootersoftware.com/"&gt;Beyond Compare&lt;/a&gt;&lt;br /&gt;This is the only application that isn't free.  You may be able to find other applications to do this work, but this application is great.  Beyond Compare allows you to compare files and folders.  You can look line-by-line and see what is different in an individual file, or look at a folder structure looking for files that are different.&lt;br /&gt;&lt;br /&gt;5. &lt;a href="http://www.irfanview.com/"&gt;Irfanview&lt;/a&gt;&lt;br /&gt;If your work is anything like mine, you likely need to write a decent amount of documenation.   A lot of my documentation contains screenshots.  This application will help by taking a jpg screen capture anytime you hit a hotkey you define (Ctrl-F11 by default).  it saves the file in a directory.  You can save the whole screen or just the foreground window.&lt;br /&gt;&lt;br /&gt;6. &lt;a href="http://notepad-plus.sourceforge.net/uk/site.htm"&gt;Notepad++&lt;/a&gt;&lt;br /&gt;I used notepad a lot.  Until I came across this application.  It has a tabbed interface, allowing for multiple documents.  It will detect when a file is updated and prompt you to reload.  It also includes syntax highlighting for a ton of languages.  It provides Regular Expression support, but probably not as much as you may find in &lt;a href="http://www.vim.org/"&gt;vim&lt;/a&gt;.  Nevertheless, it is a good replacement for Notepad.&lt;br /&gt;&lt;br /&gt;7. &lt;a href="http://www.vmware.com/products/player/"&gt;VMWare Player&lt;/a&gt;&lt;br /&gt;Testing and retesting, is a daily routine for me.  Because of that, it is important to have something to easily test with.  VMWare solves that problem.  You may say that this only plays existing images.  That problem is easily solved with &lt;a href="http://www.easyvmx.com/"&gt;EasyVMX&lt;/a&gt;, which allows you to create VMWare disks for use in the VMWare player.  If this is more work, then you can buy the actual VMWare Workstation, but for me this works well.&lt;br /&gt;&lt;br /&gt;8. &lt;a href="http://msdn.microsoft.com/en-us/library/aa370557.aspx"&gt;Orca&lt;/a&gt;&lt;br /&gt;This is the free tool provided by Microsoft to view MSI files.  It is quick and dirty way to see MSIs and their tables.  The biggest drawback is that you have to get it off the Windows SDK in order to get the MSI to install.&lt;br /&gt;&lt;br /&gt;9. &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=01592C48-207D-4BE1-8A76-1C4099D7BBB9&amp;amp;displaylang=en"&gt;WScript Shell Documentation&lt;/a&gt;&lt;br /&gt;I make it a point with scripting and writing code in general to not memorize code.  I do this for a few reasons.  First, I have enough junk to remember that I shouldn't bother stuff that is easily found in a book or a help file.  Secondly, I should always be aware that my code can be better.  If I simply remember a way to do task X, then I'll never bother to improve that task.  For those reasons, I always have the documentation for VBScript readily available.&lt;br /&gt;&lt;br /&gt;10. &lt;a href="http://tortoisesvn.tigris.org/"&gt;TortoiseSVN&lt;/a&gt;&lt;br /&gt;Anyone who scripts should have some way at looking at where they came from with any particular script.  Too many times I've seen a script in a directory that has about 10 different types of backups for that one script.  You'll see script.vbs.  Then script2.vbs, script.old, script.bak, or scriptREALLYOLD.vbs.  Why bother when you can use free source control.  Sure you have to learn how to use Source control, but shouldn't you do that anyway? Besides, learning the basics, can be done off of &lt;a href="http://www.youtube.com/watch?v=-h6cj6O94Gs"&gt;YouTube&lt;/a&gt; if you wanted.  Personally I like &lt;a href="http://www.codinghorror.com/blog/archives/001093.html"&gt;Jeff Atwood's&lt;/a&gt; blog entry on setting up source control.&lt;br /&gt;&lt;br /&gt;So, that does it.  This is not an exhaustive list and perhaps one day I'll compose an addendum to it.  But, I really think that each of these tools are essential to a normal Desktop Engineer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-6583071105560723996?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/6583071105560723996/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=6583071105560723996" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/6583071105560723996?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/6583071105560723996?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/1XQlBZdLjAQ/10-tools-every-desktop-engineer-should.html" title="10 Tools every Desktop Engineer should have." /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/06/10-tools-every-desktop-engineer-should.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEINRXozeCp7ImA9WxdXEko.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-4879412822866179763</id><published>2008-06-23T21:53:00.003-04:00</published><updated>2008-06-23T23:03:14.480-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-23T23:03:14.480-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="security" /><title>When an exploit is not an exploit</title><content type="html">Lately, I've stumbled (&lt;a href="http://www.stumbleupon.com/"&gt;literally&lt;/a&gt;) onto sites claiming Vista's security flaws.  It seems like the post originated from the &lt;a href="http://www.avertlabs.com/research/blog/?p=218"&gt;McAfee Avert Labs Blog&lt;/a&gt;.  The claim is that an executable, sethc.exe, can be replaced and allow for system access.  The executable is associated with the &lt;a href="http://en.wikipedia.org/wiki/Sticky_keys"&gt;Sticky Keys&lt;/a&gt; feature and can be activated by pressing a modifier key five times in a row.  Once done the malicious sethc.exe file is launched. &lt;br /&gt;&lt;br /&gt;This file isn't new, it was available in 2000 and XP and it isn't an exploit. &lt;br /&gt;&lt;br /&gt;One of my favorite bloggers is Raymond Chen.  He has taken 'exploits' similar to these to task for  a while now. (&lt;a href="http://blogs.msdn.com/oldnewthing/archive/2007/10/31/5788080.aspx"&gt;1&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2008/05/16/8510192.aspx"&gt;2&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2007/08/07/4268706.aspx"&gt;3&lt;/a&gt;, and &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2006/05/08/592350.aspx"&gt;4&lt;/a&gt; for example)  I think that the &lt;a href="http://www.microsoft.com/technet/archive/community/columns/security/essays/10imlaws.mspx?mfr=true"&gt;10 Immutable Laws of Security&lt;/a&gt;, written by &lt;a href="http://www.microsoft.com/security/msrc/default.mspx"&gt;Microsoft Security Response Center&lt;/a&gt; has it put best:&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Law #1: If a bad guy can persuade you to run his program on your computer, it's not your computer anymore&lt;/h2&gt;&lt;br /&gt;If you are able to modify system files, then you have all the access that you need.  The exploit could be compared to a scenario such as this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;You have a locked room and I want inside.  So, I take your key and bring it to a friend who goes into his secret lair (or Lowes) and makes a copy of it.  Then I skydive back to you and plant the key back. I then unlock your door.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Great, so why didn't I just use the key?  Sometimes when these 'exploits' are described, the extra steps mearly obfuscate the true nature of what is going on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;I take your key.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;This is also reminds me of those &lt;a href="http://www.milaadesign.com/wizardy.html"&gt;number tricks&lt;/a&gt; relatives spam you with.  Take a number, do a bunch of confusing things to it, and end up with a number or a symbol or whatever.&lt;br /&gt;&lt;br /&gt;In the end, giving admin access to someone (whether you chose to or not) grants them administrative actions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-4879412822866179763?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/4879412822866179763/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=4879412822866179763" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/4879412822866179763?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/4879412822866179763?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/wMpBsMeG8UE/when-exploit-is-not-exploit.html" title="When an exploit is not an exploit" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/06/when-exploit-is-not-exploit.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYCQHY4eCp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-8613780369876418088</id><published>2008-06-16T21:06:00.004-04:00</published><updated>2009-03-06T08:46:01.830-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:46:01.830-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><title>Working With Devices: Enabling/Disabling a device</title><content type="html">All the code in previous blog posts leading up to this were really for one purpose.  I wanted the ability to enable and disable a device.&lt;br /&gt;&lt;br /&gt;We will use two functions to change the state of a device.  &lt;a href="http://msdn.microsoft.com/en-us/library/ms792876.aspx"&gt;SetupDiSetClassInstallParams&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms792989.aspx"&gt;SetupDiCallClassInstaller&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="font-family: courier new;"&gt;Private Declare Auto Function SetupDiSetClassInstallParams Lib "setupapi.dll" (ByVal DeviceInfoSet As IntPtr, ByVal DeviceInfoData As IntPtr, ByVal InstallParams As IntPtr, ByVal InstallParamsSize As Integer) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Declare Auto Function SetupDiCallClassInstaller Lib "setupapi.dll" (ByVal InstallFunction As Integer, ByVal DeviceInfoSet As IntPtr, ByVal DeviceInfoData As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="font-family: courier new;"&gt;Private Const DIF_PROPERTYCHANGE As Integer = &amp;amp;H12&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Const DICS_ENABLE As Integer = 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Const DICS_DISABLE As Integer = 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Const DICS_FLAG_GLOBAL As Integer = 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Const DICS_FLAG_CONFIGSPECIFIC As Integer = 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Struct for Enabling/Disabling a device&lt;/span&gt;&lt;br /&gt;    &lt;structlayout(layoutkind.sequential)&gt;&lt;span style="font-family: courier new;"&gt; Private Structure SP_PROPCHANGE_PARAMS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Public ClassInstallHeader As SP_CLASSINSTALL_HEADER&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Public StateChange As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Public Scope As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Public HwProfile As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Structure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Two actions on a device.  Just to make things simple&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Enum Change_Action&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Disable&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Enable&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Enum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   'Changes the state of a given device.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Public Function ChangeState(ByVal DevInfoSet As IntPtr, ByVal Device As Device, ByVal newState As Change_Action) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       'We make sure that the device isn't already set to the newState&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Dim DeviceEnabled As Boolean = IsDeviceEnabled(Device.DevInfo.DevInst)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       If DeviceEnabled And newState = Change_Action.Enable Then Return True&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       If Not DeviceEnabled And newState = Change_Action.Disable Then Return True&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       'We first try to set the device Globally.  If it fails then we try setting it just for the current Profile&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       'Device Manager seems to disable devices by hardware profile.  That would make since.  In our case we try disable the device Globally&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       'first.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       If ChangeDevState(DevInfoSet, Device, newState, DICS_FLAG_GLOBAL) Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           Return True&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           Return ChangeDevState(DevInfoSet, Device, newState, DICS_FLAG_CONFIGSPECIFIC)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Changes a device state&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Function ChangeDevState(ByVal DevInfoSet As IntPtr, ByVal Device As Device, ByVal newState As Change_Action, ByVal Scope As Integer) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        'Sets up the Change Structure&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Prop_Change As SP_PROPCHANGE_PARAMS = New SP_PROPCHANGE_PARAMS&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Prop_Change.ClassInstallHeader.cbSize = Marshal.SizeOf(GetType(SP_CLASSINSTALL_HEADER))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Prop_Change.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Prop_Change.StateChange = IIf(newState = Change_Action.Enable, DICS_ENABLE, DICS_DISABLE)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Prop_Change.Scope = Scope&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Prop_Change.HwProfile = 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        'We create two pointers.  One for the Change Structure and a second for the Device.  We set the Structures to their pointer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim intProp_ChangeSize As Integer = Marshal.SizeOf(Prop_Change)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim intProp_Change As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Prop_Change.ClassInstallHeader))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Marshal.StructureToPtr(Prop_Change, intProp_Change, True)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim intDevInfoSize As Integer = Marshal.SizeOf(Device.DevInfo)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim intDevInfo As IntPtr = Marshal.AllocHGlobal(intDevInfoSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Marshal.StructureToPtr(Device.DevInfo, intDevInfo, True)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        'Sets the Property Change Structure for the Device.  True is success&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Result As Boolean = SetupDiSetClassInstallParams(DevInfoSet, intDevInfo, intProp_Change, intProp_ChangeSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            'Attempts to execute the Call.  True is success&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Result = SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfoSet, intDevInfo)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            If Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                'Depending on the scope used to enable/disable the device it may not work.  So we'll check the device state.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                If newState = Change_Action.Enable Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                    Return IsDeviceEnabled(Device.DevInfo.DevInst)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                    Return Not IsDeviceEnabled(Device.DevInfo.DevInst)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                Throw New Win32Exception(Marshal.GetLastWin32Error)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                Return False&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Throw New Win32Exception(Marshal.GetLastWin32Error)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Return False&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To use this, we call the ChangeState function.  We call this with the Device Info Set and Device variables along with what we want to do.  We can Enable or Disable the device.  First thing we do, is check whether or not the device is already set correctly.  Next thing we do is attempt to enable or disable the device.  The first way we try to do this is Globally.  If, that fails then we try on the specific profile.&lt;br /&gt;&lt;br /&gt;I did this after working with enabling and disabling devices and noticed that the device manager disables a device for the profile.  In my specific case I needed devices disabled globally.  If I just enabled or disabled globally, I'd run into problems when a device is disabled for the profile and not globally.  Your use may vary, so feel free to choose one or the other, but if you ever come across a device in device manager that shows a disabled icon associated with disable in the context menu (or both enabled) then that is your problem.&lt;br /&gt;&lt;br /&gt;The ChangeDevState function actually does the changing of the state.  The code with comments will explain it as best I can.&lt;/structlayout(layoutkind.sequential)&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-8613780369876418088?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/8613780369876418088/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=8613780369876418088" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/8613780369876418088?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/8613780369876418088?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/7LsNSyV33FM/working-with-devices-enablingdisabling.html" title="Working With Devices: Enabling/Disabling a device" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/06/working-with-devices-enablingdisabling.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUCRX0_cCp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-292689257867984019</id><published>2008-06-10T23:14:00.004-04:00</published><updated>2009-03-06T08:47:44.348-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:47:44.348-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="MSI" /><category scheme="http://www.blogger.com/atom/ns#" term="WMI" /><category scheme="http://www.blogger.com/atom/ns#" term="VBScript" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><title>Troubleshooting an MSI</title><content type="html">As part of a project, we need to take a company's set of MSI's and install them all together.  Our first revision worked well.  Recently I received an update for one of the applications.  When I started testing it, the install would get nearly complete and then just sit.  It would say '0 Seconds Remaining'.  That 0 Seconds occurred for over an hour with no change to the progress or status.&lt;br /&gt;&lt;br /&gt;I had run the install using the log option, so I could see that no new log entries were being logged.&lt;br /&gt;&lt;br /&gt;I used &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx"&gt;Process Explorer&lt;/a&gt; from &lt;a href="http://technet.microsoft.com/en-us/sysinternals/default.aspx"&gt;Sysinternals&lt;/a&gt;.  I ordered the processes by CPU utilization and noticed that wmiapsrv.exe was consuming resources.  My thought was that the MSI was making a WMI Query.  I decided to kill the wmi process to see if the log would update with exactly what was going on.&lt;br /&gt;&lt;br /&gt;Lucky for me it did.  It gave me a 1720 error.  Reading the full error I saw that the error means a custom action failed.  I was even provided with a line of where the error occurred.   I looked at the custom action using &lt;a href="http://msdn.microsoft.com/en-us/library/aa370557.aspx"&gt;orca&lt;/a&gt; and found the binary that it was using and what it was calling in that binary.&lt;br /&gt;&lt;br /&gt;Orca can extract the binary, which is what I did and looked at the line referenced in the error.  I saw the below VBScript code.  (I exercised some Self-Censorship, but the code is still relevant)&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-family: courier new;"&gt;strComputer = "."&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Set objWMIService = GetObject("winmgmts:\\" &amp;amp; strComputer &amp;amp; "\root\cimv2")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Set colItems = objWMIService.ExecQuery("Select * from Win32_Account")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   For Each objItem in colItems&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Select Case objItem.SID&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       End Select&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The error occurred at the last line. ('Next')  So, now I was getting some more clarity as to the problem.  It failed at the Next command, since I killed the process that was at least partly responsible in serving up that collection.&lt;br /&gt;&lt;br /&gt;I decided to run that query once to confirm what I was thinking.  I ran wbemtest and connected to root/cimv2 and then ran the query 'Select * from &lt;a href="http://msdn.microsoft.com/en-us/library/aa394061%28VS.85%29.aspx"&gt;Win32_Account&lt;/a&gt;'.  First, I received all the accounts on my local computer.  Then, it started retrieving all the accounts on the domain.  We have many domain accounts. Easily over 50 thousand and it wouldn't be a stretch to say 100 thousand.&lt;br /&gt;&lt;br /&gt;What they actually wanted was simply some account names based on a SID.  So, 'S-1-5-32-544' would be the Administrator account.  But if you renamed the account, it would be called something else.  Here is a different way to get that info, with credit due to &lt;a href="http://www.microsoft.com/technet/scriptcenter/resources/qanda/dec04/hey1203.mspx"&gt;The Scripting Guys&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-family: courier new;"&gt;strComputer = "."&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Set objWMIService = GetObject("winmgmts:\\" &amp;amp; strComputer &amp;amp; "\root\cimv2")&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Set objAccount = objWMIService.Get("Win32_SID.SID='S-1-5-32-544'")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Administrators_Name = objAccount.AccountName&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This will accomplish the same thing, but won't go through the entire domain like the previous code.&lt;br /&gt;&lt;br /&gt;So, I explained this issue and should be receiving updated code shortly.  But, what could I do if I didn't receive the updated MSI?&lt;br /&gt;&lt;br /&gt;What we could do, is create a transform.  In the transform we replace the Binary that the custom action is calling with our version of the code.  When we run the installer we now have to call the transform with the TRANSFORMS= argument when launching the MSI.&lt;br /&gt;&lt;br /&gt;Problem solved and everyone is happy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-292689257867984019?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/292689257867984019/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=292689257867984019" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/292689257867984019?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/292689257867984019?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/iH-coetOi70/troubleshooting-msi.html" title="Troubleshooting an MSI" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/06/troubleshooting-msi.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQGSHg_fyp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-7174910581384414670</id><published>2008-06-08T22:35:00.003-04:00</published><updated>2009-03-06T08:48:49.647-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:48:49.647-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><title>Working With Devices: Getting Status on a Device</title><content type="html">&lt;span style="font-size:100%;"&gt;This time we will look at checking if a device is enabled, disabled, or has a problem.  From last time we received a device structure that contained a SP_DEVINFO_DATA structure.  Within that structure we find a DevInst integer.  With that and the use of the &lt;a href="http://msdn.microsoft.com/en-us/library/ms791144.aspx"&gt;CM_Get_DevNode_Status&lt;/a&gt; function we can get status information on a device.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Private Declare Auto Function CM_Get_DevNode_Status Lib "cfgmgr32.dll" (ByRef pulStatus As IntPtr, ByRef pulProblemNumber As IntPtr, ByVal dnDevInst As Integer, ByVal ulFlags As Long) As Integer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This function will return the status and any problem with the device given.  The last variable must be set to 0.  The Status and Problem flags can have numerous meanings, so we have two enumerations to describe all the possible values.  I've only encountered a handful of status and problem codes through normal use.&lt;br /&gt;&lt;br /&gt;   &lt;span style="font-family: courier new;"&gt;'Status Flags.  Devices can have one or more of these.  ANDing is used to determine which apply&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Enum DN_Flags&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_ROOT_ENUMERATED = &amp;amp;H1                        ' Was enumerated by ROOT&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_DRIVER_LOADED = &amp;amp;H2                          ' Has Register_Device_Driver&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_ENUM_LOADED = &amp;amp;H4                            ' Has Register_Enumerator&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_STARTED = &amp;amp;H8                                ' Is currently configured&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_MANUAL = &amp;amp;H10                                ' Manually installed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NEED_TO_ENUM = &amp;amp;H20                          ' May need reenumeration&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NOT_FIRST_TIME = &amp;amp;H40                        ' Has received a config&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_HARDWARE_ENUM = &amp;amp;H80                         ' Enum generates hardware ID&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_LIAR = &amp;amp;H100                                 ' Lied about can reconfig once&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_HAS_MARK = &amp;amp;H200                             ' Not CM_Create_DevInst lately&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_HAS_PROBLEM = &amp;amp;H400                          ' Need device installer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_FILTERED = &amp;amp;H800                             ' Is filtered&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_MOVED = &amp;amp;H1000                               ' Has been moved&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_DISABLEABLE = &amp;amp;H2000                         ' Can be disabled&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_REMOVABLE = &amp;amp;H4000                           ' Can be removed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_PRIVATE_PROBLEM = &amp;amp;H8000                     ' Has a private problem&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_MF_PARENT = &amp;amp;H10000                          ' Multi function parent&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_MF_CHILD = &amp;amp;H20000                           ' Multi function child&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_WILL_BE_REMOVED = &amp;amp;H40000                    ' DevInst is being removed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NOT_FIRST_TIMEE = &amp;amp;H80000                    ' Has received a config enumerate&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_STOP_FREE_RES = &amp;amp;H100000                     ' When child is stopped, free resources&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_REBAL_CANDIDATE = &amp;amp;H200000                   ' Don't skip during rebalance&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_BAD_PARTIAL = &amp;amp;H400000                       ' This devnode's log_confs do not have same resources&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NT_ENUMERATOR = &amp;amp;H800000                     ' This devnode's is an NT enumerator&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NT_DRIVER = &amp;amp;H1000000                        ' This devnode's is an NT driver&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NEEDS_LOCKING = &amp;amp;H2000000                    ' Devnode need lock resume processing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_ARM_WAKEUP = &amp;amp;H4000000                       ' Devnode can be the wakeup device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_APM_ENUMERATOR = &amp;amp;H8000000                   ' APM aware enumerator&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_APM_DRIVER = &amp;amp;H10000000                      ' APM aware driver&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_SILENT_INSTALL = &amp;amp;H20000000                  ' Silent install&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_NO_SHOW_IN_DM = &amp;amp;H40000000                   ' No show in device manager&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        DN_BOOT_LOG_PROB = &amp;amp;H80000000                   ' Had a problem during preassignment of boot log conf&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Enum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Problem associated with device.  A device has 0 or 1 problem associated with it.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Enum CM_PROB&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_NOT_CONFIGURED = &amp;amp;H1                    ' no config for device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DEVLOADER_FAILED = &amp;amp;H2                  ' service load failed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_OUT_OF_MEMORY = &amp;amp;H3                     ' out of memory&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_ENTRY_IS_WRONG_TYPE = &amp;amp;H4               '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_LACKED_ARBITRATOR = &amp;amp;H5                 '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_BOOT_CONFIG_CONFLICT = &amp;amp;H6              ' boot config conflict&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_FAILED_FILTER = &amp;amp;H7                     '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DEVLOADER_NOT_FOUND = &amp;amp;H8               ' Devloader not found&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_INVALID_DATA = &amp;amp;H9                      ' Invalid ID&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_FAILED_START = &amp;amp;HA                      '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_LIAR = &amp;amp;HB                              '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_NORMAL_CONFLICT = &amp;amp;HC                   ' config conflict&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_NOT_VERIFIED = &amp;amp;HD                      '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_NEED_RESTART = &amp;amp;HE                      ' requires restart&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_REENUMERATION = &amp;amp;HF                     '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_PARTIAL_LOG_CONF = &amp;amp;H10                 '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_UNKNOWN_RESOURCE = &amp;amp;H11                 ' unknown res type&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_REINSTALL = &amp;amp;H12                        '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_REGISTRY = &amp;amp;H13                         '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_VXDLDR = &amp;amp;H14                           ' WINDOWS 95 ONLY&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_WILL_BE_REMOVED = &amp;amp;H15                  ' devinst will remove&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DISABLED = &amp;amp;H16                         ' devinst is disabled&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DEVLOADER_NOT_READY = &amp;amp;H17              ' Devloader not ready&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DEVICE_NOT_THERE = &amp;amp;H18                 ' device doesn't exist&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_MOVED = &amp;amp;H19                            '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_TOO_EARLY = &amp;amp;H1A                        '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_NO_VALID_LOG_CONF = &amp;amp;H1B                ' no valid log config&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_FAILED_INSTALL = &amp;amp;H1C                   ' install failed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_HARDWARE_DISABLED = &amp;amp;H1D                ' device disabled&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_CANT_SHARE_IRQ = &amp;amp;H1E                   ' can't share IRQ&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_FAILED_ADD = &amp;amp;H1F                       ' driver failed add&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DISABLED_SERVICE = &amp;amp;H20                 ' service's Start = 4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_TRANSLATION_FAILED = &amp;amp;H21               ' resource translation failed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_NO_SOFTCONFIG = &amp;amp;H22                    ' no soft config&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_BIOS_TABLE = &amp;amp;H23                       ' device missing in BIOS table&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_IRQ_TRANSLATION_FAILED = &amp;amp;H24           ' IRQ translator failed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_FAILED_DRIVER_ENTRY = &amp;amp;H25              ' DriverEntry() failed.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD = &amp;amp;H26       ' Driver should have unloaded.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DRIVER_FAILED_LOAD = &amp;amp;H27               ' Driver load unsuccessful.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DRIVER_SERVICE_KEY_INVALID = &amp;amp;H28       ' Error accessing driver's service key&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_LEGACY_SERVICE_NO_DEVICES = &amp;amp;H29        ' Loaded legacy service created no devices&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DUPLICATE_DEVICE = &amp;amp;H2A                 ' Two devices were discovered with the same name&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_FAILED_POST_START = &amp;amp;H2B                ' The drivers set the device state to failed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_HALTED = &amp;amp;H2C                           ' This device was failed post start via usermode&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_PHANTOM = &amp;amp;H2D                          ' The devinst currently exists only in the registry&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_SYSTEM_SHUTDOWN = &amp;amp;H2E                  ' The system is shutting down&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_HELD_FOR_EJECT = &amp;amp;H2F                   ' The device is offline awaiting removal&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_DRIVER_BLOCKED = &amp;amp;H30                   ' One or more drivers is blocked from loading&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_REGISTRY_TOO_LARGE = &amp;amp;H31               ' System hive has grown too large&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        CM_PROB_SETPROPERTIES_FAILED = &amp;amp;H32             ' Failed to apply one or more registry properties  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        NUM_CM_PROB = &amp;amp;H33                              '&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Enum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Returns true if the device is enabled&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Function IsDeviceEnabled(ByVal DevInst As Integer) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Result As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Problem, Status As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Result = CM_Get_DevNode_Status(Status, Problem, DevInst, 0)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result = 13 Then Return Nothing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result &lt;&gt; 0 Then Throw New ApplicationException("Return Code From CM_Get_DevNode_Status was not 0")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Return Not Problem.ToInt32 = CM_PROB.CM_PROB_DISABLED&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Returns true if the Status Flag to hide the device is set.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Function IsDeviceHidden(ByVal DevInst As Integer) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Result As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Problem, Status As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Result = CM_Get_DevNode_Status(Status, Problem, DevInst, 0)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result &lt;&gt; 0 Then Throw New ApplicationException("Return Code From CM_Get_DevNode_Status was not 0")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Return (Status.ToInt32 And DN_Flags.DN_NO_SHOW_IN_DM) = DN_Flags.DN_NO_SHOW_IN_DM&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Gets all the Device Status Flags for a device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Function GetDeviceStatus(ByVal DevInst As Integer) As String()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Result As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Problem, Status As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Result = CM_Get_DevNode_Status(Status, Problem, DevInst, 0)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result = 13 Then Return Nothing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result &lt;&gt; 0 Then Throw New ApplicationException("Return Code From CM_Get_DevNode_Status was not 0")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Return GetBitFlags(Status, GetType(DN_Flags))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Gets a Device Problem&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Public Function GetDeviceProblem(ByVal DevInst As Integer) As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Result As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim Problem, Status As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Result = CM_Get_DevNode_Status(Status, Problem, DevInst, 0)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result = 13 Then Return Nothing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Result &lt;&gt; 0 Then Throw New ApplicationException("Return Code From CM_Get_DevNode_Status was not 0")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        If Problem.ToInt32 = 0 Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Return "No Problem"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Return CType(Problem.ToInt32, CM_PROB).ToString&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    'Returns an array of strings representing the Status Flags set for a device.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Private Function GetBitFlags(ByVal Bits As IntPtr, ByVal EnumType As Type) As String()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim arrData As New ArrayList&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        For Each TypeName As String In [Enum].GetNames(EnumType)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            Dim Number As Int32 = [Enum].Parse(EnumType, TypeName)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            If (Bits.ToInt32 And Number) = Number Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                arrData.Add(TypeName)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;            End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Next&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Dim StrData(arrData.Count) As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        arrData.CopyTo(StrData)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        Return StrData&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is how you could call this. after you retrieve a device in variable objDevice.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;If IsDeviceEnabled(objDevice.DevInfo.DevInst) Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   'Device Enabled&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   'Device Disabled&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I think that the code should be fairly straightforward to follow.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-7174910581384414670?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/7174910581384414670/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=7174910581384414670" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/7174910581384414670?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/7174910581384414670?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/HG-9Q8nT-7w/working-with-devices-getting-status-on.html" title="Working With Devices: Getting Status on a Device" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/06/working-with-devices-getting-status-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQMRHw5fyp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-6917154264438753471</id><published>2008-06-01T21:01:00.006-04:00</published><updated>2009-03-06T08:49:45.227-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:49:45.227-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working With Devices: Getting Device Names</title><content type="html">This post may be a bit longer than previous, because I'll have a bit more code to show than usual.  This post will show how to take what we have from previous posts and get the device names for a specific Device Setup or Interface class.&lt;br /&gt;&lt;br /&gt;We'll only need the use of two windows api's.  Those being &lt;a href="http://msdn.microsoft.com/en-us/library/ms792983.aspx"&gt;SetupDiEnumDeviceInfo&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms792967.aspx"&gt;SetupDiGetDeviceRegistryProperty&lt;/a&gt;.  The first function will return a SP_DEVINFO_DATA type.  Instead of just handling this, we'll add the device name itself, in order to be more clear with which device were working with.  We retrieve the device name from the second function.  We have a few different versions of this.  I've done this in order to parse the different types of registry types a bit easier.  This may be redefined a bit later.  I'll update this post if I find a better solution.&lt;br /&gt;&lt;br /&gt;First let me post the code and then I'll try to go over what each function does as best I can.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Private Declare Auto Function SetupDiEnumDeviceInfo Lib "Setupapi.dll" (ByVal DeviceInfoSet As IntPtr, ByVal MemberIndex As Integer, ByRef DeviceInfoData As SP_DEVINFO_DATA) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Declare Ansi Function SetupDiGetDeviceRegistryPropertyA Lib "Setupapi.dll" (ByVal DeviceInfoSet As IntPtr, ByVal DeviceInfoData As IntPtr, ByVal intProperty As Integer, ByRef PropertyRegDataType As IntPtr, ByVal PropertyBuffer As System.Text.StringBuilder, ByVal PropertyBufferSize As Integer, ByRef RequiredSize As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Declare Ansi Function SetupDiGetDeviceRegistryPropertyA Lib "Setupapi.dll" (ByVal DeviceInfoSet As IntPtr, ByVal DeviceInfoData As IntPtr, ByVal intProperty As Integer, ByRef PropertyRegDataType As IntPtr, ByVal PropertyBuffer() As Byte, ByVal PropertyBufferSize As Integer, ByRef RequiredSize As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Declare Ansi Function SetupDiGetDeviceRegistryPropertyA Lib "Setupapi.dll" (ByVal DeviceInfoSet As IntPtr, ByVal DeviceInfoData As IntPtr, ByVal intProperty As Integer, ByRef PropertyRegDataType As IntPtr, ByRef PropertyBuffer As IntPtr, ByVal PropertyBufferSize As Integer, ByRef RequiredSize As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'I created this structure to make it easier to pass data back to my form&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Public Structure Device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Public Name As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Public DevInfo As SP_DEVINFO_DATA&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Structure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Represents an individual device&lt;/span&gt;&lt;br /&gt; &lt;structlayout(layoutkind.sequential)&gt;&lt;span style="font-family: courier new;"&gt; Public Structure SP_DEVINFO_DATA&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Public cdSize As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Public ClassGuid As Guid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Public DevInst As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Public Reserved As UInt32&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Structure&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'All the different Registry Keys that can be read for a particular device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Public Enum DeviceRegistryValueNames&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_DEVICEDESC = &amp;amp;H0                          'DeviceDesc (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_HARDWAREID = &amp;amp;H1                          'HardwareID (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_COMPATIBLEIDS = &amp;amp;H2                       'CompatibleIDs (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_SERVICE = &amp;amp;H4                             'Service (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_CLASS = &amp;amp;H7                               'Class (R--tied to ClassGUID)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_CLASSGUID = &amp;amp;H8                           'ClassGUID (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_DRIVER = &amp;amp;H9                              'Driver (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_CONFIGFLAGS = &amp;amp;HA                         'ConfigFlags (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_MFG = &amp;amp;HB                                 'Mfg (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_FRIENDLYNAME = &amp;amp;HC                        'FriendlyName (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_LOCATION_INFORMATION = &amp;amp;HD                'LocationInformation (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = &amp;amp;HE         'PhysicalDeviceObjectName (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_CAPABILITIES = &amp;amp;HF                        'Capabilities (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_UI_NUMBER = &amp;amp;H10                          'UiNumber (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_UPPERFILTERS = &amp;amp;H11                       'UpperFilters (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_LOWERFILTERS = &amp;amp;H12                       'LowerFilters (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_BUSTYPEGUID = &amp;amp;H13                        'BusTypeGUID (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_LEGACYBUSTYPE = &amp;amp;H14                      'LegacyBusType (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_BUSNUMBER = &amp;amp;H15                          'BusNumber (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_ENUMERATOR_NAME = &amp;amp;H16                    'Enumerator Name (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_SECURITY = &amp;amp;H17                           'Security (R/W, binary form)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_SECURITY_SDS = &amp;amp;H18                       'Security (W, SDS form)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_DEVTYPE = &amp;amp;H19                            'Device Type (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_EXCLUSIVE = &amp;amp;H1A                          'Device is exclusive-access (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_CHARACTERISTICS = &amp;amp;H1B                    'Device Characteristics (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_ADDRESS = &amp;amp;H1C                            'Device Address (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_UI_NUMBER_DESC_FORMAT = &amp;amp;H1D              'UiNumberDescFormat (R/W)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_DEVICE_POWER_DATA = &amp;amp;H1E                  'Device Power Data (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_REMOVAL_POLICY = &amp;amp;H1F                     'Removal Policy (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_REMOVAL_POLICY_HW_DEFAULT = &amp;amp;H20          'Hardware Removal Policy (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_REMOVAL_POLICY_OVERRIDE = &amp;amp;H21            'Removal Policy Override (RW)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_INSTALL_STATE = &amp;amp;H22                      'Device Install State (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     SPDRP_LOCATION_PATHS = &amp;amp;H23                     'Device Location Paths (R)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Enum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Types of Registry Keys&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Enum Reg_Types&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     REG_SZ = 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     REG_BINARY = 3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     REG_DWORD = 4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     REG_MULTI_SZ = 7&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Enum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Returns an array of devices from the given Device Info Set&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Public Function GetDeviceNames(ByVal DevInfoSet As IntPtr) As Device()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     'Variables used&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim DeviceList As New ArrayList&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim TempName As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim newDevice As Device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim i As Integer = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim Result As SP_DEVINFO_DATA&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Do&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             'We will loop through until we get a 259 error (No More Items)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Result = GetDeviceInfoData(DevInfoSet, i)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Catch ex As Win32Exception When ex.NativeErrorCode = 259&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             'Ready to exit now&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Result.DevInst = -1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Catch ex As Win32Exception&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Throw&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         End Try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         i += 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         If Result.DevInst = -1 Then Exit Do&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             'Retrieve the Name for our device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             TempName = GetDeviceName(DevInfoSet, Result)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             If TempName Is Nothing Then TempName = "Name Unavailable"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             newDevice.Name = TempName&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             newDevice.DevInfo = Result&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             'Adds the device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             DeviceList.Add(newDevice)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Catch ex As Win32Exception&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             If ex.NativeErrorCode &lt;&gt; 13 Then Throw&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         End Try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Loop Until Result.DevInst = -1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     'Creates an array of devices and returns it back&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim arrDevices(DeviceList.Count - 1) As Device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     DeviceList.CopyTo(arrDevices)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Return arrDevices&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Gets the Deivce info data.  Given a Device Info Set (A Device Class), we loop through it by incrementing the MemberIndex Value&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Once we don't have any more we return -1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Function GetDeviceInfoData(ByVal DevInfoSet As IntPtr, ByVal MemberIndex As Integer) As SP_DEVINFO_DATA&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim Result As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim DeviceInfoData As SP_DEVINFO_DATA&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     DeviceInfoData = New SP_DEVINFO_DATA&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     DeviceInfoData.DevInst = 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     DeviceInfoData.Reserved = Convert.ToUInt32(0)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     DeviceInfoData.cdSize = Marshal.SizeOf(DeviceInfoData)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Result = SetupDiEnumDeviceInfo(DevInfoSet, MemberIndex, DeviceInfoData)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     If Not Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         If Marshal.GetLastWin32Error &lt;&gt; 0 Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Throw (New Win32Exception(Marshal.GetLastWin32Error))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         DeviceInfoData.DevInst = -1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Return DeviceInfoData&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Returns the Device name for the device.  This is just getting the DeviceDesc.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'We could also check the Friendly Name instead.  That setting would be used first if it were available by windows I believe.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Function GetDeviceName(ByRef DevInfoSet As IntPtr, ByRef DeviceInfoData As SP_DEVINFO_DATA) As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Return GetRegistryValue(DevInfoSet, DeviceInfoData, DeviceRegistryValueNames.SPDRP_DEVICEDESC)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Gets a registry value for a device&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'This function is a bit tricky since we have to figure out what type the Registry Value is and then handle it appropriately&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Function GetRegistryValue(ByVal DevInfoSet As IntPtr, ByVal DeviceInfoData As SP_DEVINFO_DATA, ByVal ValueName As DeviceRegistryValueNames) As Object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     'Creates our variables and creates a pointer to the DeviceInfoData structure&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim Result As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim DevInfo As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(DeviceInfoData))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Marshal.StructureToPtr(DeviceInfoData, DevInfo, False)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         'Retrieves the Value Type&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Dim ValueType As Reg_Types = GetRegistryType(DevInfoSet, DevInfo, ValueName)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         'Selects the correct course of action.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Select Case ValueType&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Case Reg_Types.REG_DWORD&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 'Just return the value as an integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Dim TempValue As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Result = SetupDiGetDeviceRegistryPropertyA(DevInfoSet, DevInfo, ValueName, IntPtr.Zero, TempValue, 1000, IntPtr.Zero)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Return TempValue.ToInt32&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Case Reg_Types.REG_MULTI_SZ, Reg_Types.REG_SZ&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 'Loop through as a byte Array and assemble it at the end.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Dim intSize As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Result = Not SetupDiGetDeviceRegistryPropertyA(DevInfoSet, DevInfo, ValueName, IntPtr.Zero, IntPtr.Zero, 0, intSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Dim TempValue(intSize.ToInt32) As Byte&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Result = SetupDiGetDeviceRegistryPropertyA(DevInfoSet, DevInfo, ValueName, IntPtr.Zero, TempValue, intSize.ToInt32, intSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Dim TempStr As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 For Each bytChr As Byte In TempValue&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                     If bytChr = 0 Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                         TempStr &amp;amp;= vbCrLf&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                     Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                         TempStr &amp;amp;= Chr(bytChr)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                     End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Next&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Return TempStr.Trim 'The end has some extra white space&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Case Reg_Types.REG_BINARY&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 'I didn't implement this.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Return "Not Reading Binary Values"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Case Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 'Who knows what happened.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 Return Nothing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         End Select&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Catch When Not Result&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         'Error&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         If Marshal.GetLastWin32Error &lt;&gt; 0 Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Throw (New Win32Exception(Marshal.GetLastWin32Error))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Return Nothing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Catch ex As Win32Exception&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Throw&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     End Try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Returns the Type of Registry key&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Private Function GetRegistryType(ByVal DevInfoSet As IntPtr, ByRef DevInfo As IntPtr, ByVal ValueName As DeviceRegistryValueNames) As Reg_Types&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim Result As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Dim IntType As IntPtr = IntPtr.Zero&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Result = SetupDiGetDeviceRegistryPropertyA(DevInfoSet, DevInfo, ValueName, IntType, New System.Text.StringBuilder(""), 0, IntPtr.Zero)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     If Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Return IntType.ToInt32&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     Else&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Dim intErrorCode = Marshal.GetLastWin32Error&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         If intErrorCode = 122 Then Return IntType.ToInt32&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         If Marshal.GetLastWin32Error &lt;&gt; 0 Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             Throw (New Win32Exception(Marshal.GetLastWin32Error))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         Return Nothing&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Function&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/structlayout(layoutkind.sequential)&gt;&lt;span style="font-size:130%;"&gt;GetDeviceNames&lt;/span&gt;&lt;br /&gt;This function takes the pointer we retrieved from our previous post.  We'll return a Device array.  We defined this Device object.  It is a Structure that contains the device 'friendly name' and the DevInfo object which we retrieve from the windows api.&lt;br /&gt;&lt;br /&gt;We'll loop through, starting at zero, retrieving the DevInfo object and then getting the Device Name.  We store each of those in an array and then return the results.  We know that we are done when the windows api call returns a 259 error code.  This means 'No More Items'.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;GetDeviceName&lt;/span&gt;&lt;br /&gt;This function will return the friendly name for a specific device.  The DevInfoSet and DevInfo variables are required and a string function is returned by using the GetRegistryValue function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;GetDeviceInfoData&lt;/span&gt;&lt;br /&gt;This function returns the DevInfo variable required by the GetDeviceNames function.  We use the SetupDiEnumDeviceInfo function to retrieve this variable.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;GetRegistryValue&lt;/span&gt;&lt;br /&gt;This function takes in the DevInfoSet and DevInfo variable along with a specific value to retieve and then retrieves the value.  For clarity all the values that we can retrieve are included in this post.  The function uses the GetRegistryType function to determine the actual registry type that we are trying to retrieve.  I did not implement the retrieval of Binary data.  This hasn't been a problem for me.  If I ever get around to implementing, I'll update this post.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;GetRegistryType&lt;/span&gt;&lt;br /&gt;This function returns the type of registry value we want to read.  This is used by the GetRegistryValue function.&lt;br /&gt;&lt;br /&gt;I realize that this post is not only long, but probably includes some more information than is actually needed to simply get the device names.  But, I think it is important to put all these functions together since they all only use a combined two windows api calls.&lt;structlayout(layoutkind.sequential)&gt;&lt;br /&gt;&lt;/structlayout(layoutkind.sequential)&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-6917154264438753471?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/6917154264438753471/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=6917154264438753471" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/6917154264438753471?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/6917154264438753471?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/5puAl7QhOgc/working-with-devices-getting-device.html" title="Working With Devices: Getting Device Names" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/06/working-with-devices-getting-device.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMARXg_fip7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-5050336093219237318</id><published>2008-05-28T21:04:00.005-04:00</published><updated>2009-03-06T08:50:44.646-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:50:44.646-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working With Devices: Actually getting to the devices</title><content type="html">Up to this point we've worked with Device Classes.   We now should get into the actual devices.  Devices are grouped into Device Information Sets.  If I understand &lt;a href="http://msdn.microsoft.com/en-us/library/ms791129.aspx"&gt;Microsoft's&lt;/a&gt; description of it, Devices are grouped by Device Setup and Device Interface Classes.  As mentioned &lt;a href="http://robhaupt.blogspot.com/2007/05/working-with-devices-general-overview.html"&gt;previously&lt;/a&gt; Setup Classes are things like Network Adapters, while Interface Classes are things like PCI connections.  These groupings can be pulled by using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms792959.aspx"&gt;SetupDiGetClassDevs&lt;/a&gt; function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Private Declare Auto Function SetupDiGetClassDevs Lib "Setupapi.dll" (ByRef ClassGuid As Guid, ByVal Enumerator As UInt32, ByVal hwndParent As IntPtr, ByVal Flags As UInt32) As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Out of the four arguments, I am only going to use the first and last.  The first argument is the Guid that I want to retrieve.  The Guid(s) we retrieved from the &lt;a href="http://robhaupt.blogspot.com/2007/07/working-with-devices-retrieving-class.html"&gt;SetupDiClassGuidsFromNames&lt;/a&gt; can be used here.  I think that Device Interface Class Guids could be used as well, I just never had a need for it.&lt;br /&gt;&lt;br /&gt;The second argument are the flags we will use.  The enumeration is defined below.  You can refer to the &lt;a href="http://msdn.microsoft.com/en-us/library/ms792959.aspx"&gt;function definition&lt;/a&gt; as to which one you want to use.  You probably want to experiment with these to see which one suits your needs.  I think that Present and Profile are your best bets if you are unsure.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   'Scope to retrieve devices&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Public Enum DeviceInfoSet_Scope&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       DIGCF_DEFAULT = &amp;amp;H1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       DIGCF_PRESENT = &amp;amp;H2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       DIGCF_ALLCLASSES = &amp;amp;H4&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       DIGCF_PROFILE = &amp;amp;H8&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       DIGCF_DEVICEINTERFACE = &amp;amp;H10&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   End Enum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here is our code.&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-family: courier new;"&gt;'Returns a Device Info Set based on Class Guid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Private Function GetDeviceInfoSet(ByVal ClassGuid As Guid, ByVal Scope As DeviceInfoSet_Scope) As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Dim Result As IntPtr = SetupDiGetClassDevs(ClassGuid, Convert.ToUInt32(0), IntPtr.Zero, Convert.ToUInt32(Scope))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Return Result&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Our result is returned as an IntPtr variable type.&lt;br /&gt;&lt;br /&gt;It is important to note that once you are done with this object you need to destroy it.  You can use the &lt;a href="http://msdn.microsoft.com/en-us/library/ms792991.aspx"&gt;SetupDiDestroyDeviceInfoList&lt;/a&gt; to destory the IntPtr's.  Here is the definition along with the code.&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-family: courier new;"&gt;Private Declare Auto Function SetupDiDestroyDeviceInfoList Lib "Setupapi.dll" (ByVal DeviceInfoSet As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;'Destroys the device Info set&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Public Sub DestroyDeviceInfoSet(ByVal DevInfoSet As IntPtr)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       SetupDiDestroyDeviceInfoList(DevInfoSet)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   End Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So the end result is a pointer to an object that will contain a list of devices.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-5050336093219237318?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/5050336093219237318/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=5050336093219237318" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/5050336093219237318?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/5050336093219237318?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/78sH6rawfJQ/working-with-devices-actually-getting.html" title="Working With Devices: Actually getting to the devices" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/05/working-with-devices-actually-getting.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMNQ3Y_fCp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-4043212160886922177</id><published>2008-05-19T21:27:00.007-04:00</published><updated>2009-03-06T08:51:32.844-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:51:32.844-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working With Devices: Getting Friendly Class Names</title><content type="html">Ok, so once again I haven't posted in a long time.  I'd like to say that I've decided to post at least once per week.  Hopefully that will stay true.  Given my past track record, your guess is as good as mine.&lt;br /&gt;&lt;br /&gt;So, this time around we are going to get the friendly names for our device classes.  Previously we may have retrieved a device class name of 'net'.  Looking in the Device Manager we only find 'Network adapters'.  That is the friendly name and the name you'll likely want to display.&lt;br /&gt;&lt;br /&gt;So here is the code using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms792960.aspx"&gt;SetupDiGetClassDescription&lt;/a&gt; function.&lt;br /&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;Private Declare Auto Function SetupDiGetClassDescription Lib "setupapi.dll" (ByRef ClassGuid As Guid, ByVal ClassDescription As System.Text.StringBuilder, ByVal ClassDescriptionSize As Integer, ByRef RequiredSize As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; 'Returns the Class Description (Friendly name for the Class is a better way to put it)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; Public Function GetClassDescription(ByVal ClassName As String) As String&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  'The First section we get the length that we need&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  Dim intSize As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  Dim ClassGuid As Guid = GetClassGuid(ClassName)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  Dim Result As Boolean = SetupDiGetClassDescription(ClassGuid, Nothing, 0, intSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  If Not Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      Dim intErrorCode As Integer = Marshal.GetLastWin32Error&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      If intErrorCode &lt;&gt; 122 Then '122 is insufficient buffer (We expect it to happen)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;          Throw New Win32Exception(intErrorCode)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; 'The Second section we instantiate an object of the given size and get the Description&lt;br /&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;Dim ClassDesc As New System.Text.StringBuilder(intSize.ToInt32)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  Result = SetupDiGetClassDescription(ClassGuid, ClassDesc, intSize.ToInt32, intSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  If Not Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      Throw New Win32Exception(Marshal.GetLastWin32Error)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  Return ClassDesc.ToString&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The above code seems to be pretty typical for these functions.  First we get the size of the Class Description and then we get the actual description and return it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-4043212160886922177?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/4043212160886922177/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=4043212160886922177" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/4043212160886922177?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/4043212160886922177?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/N3zV10zF-MU/working-with-devices-getting-friendly.html" title="Working With Devices: Getting Friendly Class Names" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2008/05/working-with-devices-getting-friendly.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUICQXw9eSp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-6036846456167639591</id><published>2007-07-29T22:29:00.003-04:00</published><updated>2009-03-06T08:52:40.261-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:52:40.261-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working with Devices: Retrieving Class Guids From Class Name</title><content type="html">Its been sometime since my last post.  I've been attending to my new job and new daughter.&lt;br /&gt;&lt;br /&gt;So, the previous post demonstrated how to get the Class Name from the Guid.  This time I want to show how to get the Class Guid from the Class Name.  You'll be using the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms792942.aspx"&gt;SetupDiClassGuidsFromName&lt;/a&gt; function. Here is how I declared it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Private Declare Auto Function SetupDiClassGuidsFromName Lib "Setupapi.dll" (ByVal ClassName As String, &lt;/span&gt;&lt;runtime.interopservices.out()&gt;&lt;span style="font-family: courier new;"&gt; ByVal ClassGuidList() As Guid, ByVal ClassGuidListSize As Integer, ByRef RequiredSize As Integer) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There are four parameters to pass into this function.   The first is the name.  Simply enough that is just a string with the non-friendly name of the class.  So for example 'Net' is the name for the Network Adapter class.  The second parameter is to retrieve the Guids. The third and fourth parameter are used to size our array.  The way it works is that we pass 0 to the third parameter meaning our Guid Array is empty and we have an array setup to receive the fourth parameter output.  What will happen is the fourth parameter (RequiredSize) will tell us how big our array should be.  We then resize our Guid Array and set the third parameter (ClassGuidListSize) to what the required size should be.&lt;br /&gt;&lt;br /&gt;Here is the code&lt;br /&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;'Returns the Class Guid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Function GetClassGuidsFromName(ByVal ClassName As String) As Guid()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Dim intSize, intReqSize As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Dim GuidList() As Guid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       If (Not SetupDiClassGuidsFromName(ClassName, GuidList, intSize, intReqSize)) Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           intSize = intReqSize&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           ReDim GuidList(intSize - 1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           If (SetupDiClassGuidsFromName(ClassName, GuidList, intSize, intReqSize)) Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               Return GuidList&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       End If&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Calling GetClassGuidsFromName("USB") will return a Guid array with , in my case two items.&lt;br /&gt;&lt;br /&gt;Next time we'll get the Class Description.  Otherwise known as the friendly name for the Class.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;*** UPDATE ***&lt;br /&gt;I previously had posted a different set of code for this post, because of my inability to code to receive multiple Guids.  That seems to be resolved with this above code and thus I've updated this post accordingly.&lt;/runtime.interopservices.out()&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-6036846456167639591?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/6036846456167639591/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=6036846456167639591" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/6036846456167639591?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/6036846456167639591?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/SzSsyIIddU0/working-with-devices-retrieving-class.html" title="Working with Devices: Retrieving Class Guids From Class Name" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/07/working-with-devices-retrieving-class.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4MQngzfip7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-8096912126429957083</id><published>2007-05-31T20:53:00.002-04:00</published><updated>2009-03-06T08:43:03.686-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:43:03.686-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working with Devices: Retrieving Device Setup Class Names</title><content type="html">We now have our GUID for the Setup Class.  Maybe we want to get the name of the class.  We can do that by using the following function:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Private Declare Ansi Function SetupDiClassNameFromGuidA Lib "setupapi.dll" (ByRef ClassGuid As Guid, ByVal ClassName As System.Text.StringBuilder, ByVal ClassNameSize As Integer, ByRef RequiredSize As IntPtr) As Boolean&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I am explicitly calling the Ansi function.  I believe that calling just the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms792972.aspx"&gt;SetupDiClassNameFromGuid&lt;/a&gt; without the 'A' should default to the correct function ('A' or 'W'),  but, I couldn't get that working correctly for some reason.&lt;br /&gt;&lt;br /&gt;Here&lt;span style="font-family: georgia;"&gt; is the functio&lt;/span&gt;n that will return the name of the device setup class.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Imports System.Runtime.InteropServices&lt;br /&gt;Imports System.ComponentModel&lt;br /&gt;&lt;br /&gt;'Returns a Class name from its Guid&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Private Function GetClassName(ByVal ClassGuid As Guid) As String&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    'We first get the Name's Length&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Dim intRequiredSize As IntPtr&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Dim Result As Boolean&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Result = SetupDiClassNameFromGuidA(ClassGuid, Nothing, 0, intRequiredSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    If Not Result Then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        Dim intErrorCode As Integer = Marshal.GetLastWin32Error()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        If intErrorCode &lt;&gt; 122 Then Throw (New Win32Exception(intErrorCode))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    End If&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    'Now we instantiate that StringBuilder with the size and get the name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Dim ClassName As New System.Text.StringBuilder(intRequiredSize.ToInt32)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Result = SetupDiClassNameFromGuidA(ClassGuid, ClassName, intRequiredSize.ToInt32, intRequiredSize)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    If Not Result Then Throw (New Win32Exception(Marshal.GetLastWin32Error))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    Return ClassName.ToString&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;End Function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When retrieving strings and such it is fairly common to see that we first call the function without providing a buffer to store the data and then provide a buffer.  The reason for this is because we will get back the required size by first calling the function as we did above.&lt;br /&gt;&lt;br /&gt;Using the code from the previous post and this code I can show you the output from my computer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;25dbce51-6c8f-4a72-8a6d-b54c2b4fc835    WCEUSBS&lt;br /&gt;36fc9e60-c465-11cf-8056-444553540000    USB&lt;br /&gt;4658ee7e-f050-11d1-b6bd-00c04fa372a7    PnpPrinters&lt;br /&gt;48721b56-6795-11d2-b1a8-0080c72e74a2    Dot4&lt;br /&gt;49ce6ac8-6f86-11d2-b1e5-0080c72e74a2    Dot4Print&lt;br /&gt;4d36e965-e325-11ce-bfc1-08002be10318    CDROM&lt;br /&gt;4d36e966-e325-11ce-bfc1-08002be10318    Computer&lt;br /&gt;4d36e967-e325-11ce-bfc1-08002be10318    DiskDrive&lt;br /&gt;4d36e968-e325-11ce-bfc1-08002be10318    Display&lt;br /&gt;4d36e969-e325-11ce-bfc1-08002be10318    fdc&lt;br /&gt;4d36e96a-e325-11ce-bfc1-08002be10318    hdc&lt;br /&gt;4d36e96b-e325-11ce-bfc1-08002be10318    Keyboard&lt;br /&gt;4d36e96c-e325-11ce-bfc1-08002be10318    MEDIA&lt;br /&gt;4d36e96d-e325-11ce-bfc1-08002be10318    Modem&lt;br /&gt;4d36e96e-e325-11ce-bfc1-08002be10318    Monitor&lt;br /&gt;4d36e96f-e325-11ce-bfc1-08002be10318    Mouse&lt;br /&gt;4d36e970-e325-11ce-bfc1-08002be10318    MTD&lt;br /&gt;4d36e971-e325-11ce-bfc1-08002be10318    MultiFunction&lt;br /&gt;4d36e972-e325-11ce-bfc1-08002be10318    Net&lt;br /&gt;4d36e973-e325-11ce-bfc1-08002be10318    NetClient&lt;br /&gt;4d36e974-e325-11ce-bfc1-08002be10318    NetService&lt;br /&gt;4d36e975-e325-11ce-bfc1-08002be10318    NetTrans&lt;br /&gt;4d36e977-e325-11ce-bfc1-08002be10318    PCMCIA&lt;br /&gt;4d36e978-e325-11ce-bfc1-08002be10318    Ports&lt;br /&gt;4d36e979-e325-11ce-bfc1-08002be10318    Printer&lt;br /&gt;4d36e97b-e325-11ce-bfc1-08002be10318    SCSIAdapter&lt;br /&gt;4d36e97d-e325-11ce-bfc1-08002be10318    System&lt;br /&gt;4d36e97e-e325-11ce-bfc1-08002be10318    Unknown&lt;br /&gt;4d36e980-e325-11ce-bfc1-08002be10318    FloppyDisk&lt;br /&gt;50127dc3-0f36-415e-a6cc-4cb3be910b65    Processor&lt;br /&gt;50906cb8-ba12-11d1-bf5d-0000f805f530    MultiPortSerial&lt;br /&gt;50dd5230-ba8a-11d1-bf5d-0000f805f530    SmartCardReader&lt;br /&gt;533c5b84-ec70-11d2-9505-00c04f79deaf    VolumeSnapshot&lt;br /&gt;66f250d6-7801-4a64-b139-eea80a450b24    1394Debug&lt;br /&gt;6bdd1fc1-810f-11d0-bec7-08002be2092f    1394&lt;br /&gt;6bdd1fc5-810f-11d0-bec7-08002be2092f    Infrared&lt;br /&gt;6bdd1fc6-810f-11d0-bec7-08002be2092f    Image&lt;br /&gt;6d807884-7d21-11cf-801c-08002be10318    TapeDrive&lt;br /&gt;71a27cdd-812a-11d0-bec7-08002be2092f    Volume&lt;br /&gt;72631e54-78a4-11d0-bcf7-00aa00b7b32a    Battery&lt;br /&gt;745a17a0-74d3-11d0-b6fe-00a0c90f57da    HIDClass&lt;br /&gt;7ebefbc0-3200-11d2-b4c2-00a0c9697d07    61883&lt;br /&gt;8ecc055d-047f-11d1-a537-0000f8753ed1    LegacyDriver&lt;br /&gt;a0a588a4-c46f-4b37-b7ea-c82fe89870c6    SDHost&lt;br /&gt;a1aa288f-bd7d-4a38-bee3-7d7cbc3674d8    UsbPcCardReader&lt;br /&gt;c06ff265-ae09-48f0-812c-16753d7cba83    Avc&lt;br /&gt;c459df55-db08-11d1-b009-00a0c9081ff6    Enum1394&lt;br /&gt;ce5939ae-ebde-11d0-b181-0000f8753ec4    MediumChanger&lt;br /&gt;d45b1c18-c8fa-11d1-9f77-0000f805f530    NtApm&lt;br /&gt;d48179be-ec20-11d1-b6b8-00c04fa372a7    SBP2&lt;br /&gt;e0cbf06c-cd8b-4647-bb8a-263b43f0f974    Bluetooth&lt;br /&gt;eec5ad98-8080-425f-922a-dabf3de3f69a    WPD&lt;br /&gt;feb8d079-0681-11d4-9531-0060089abc08    USB&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Notice that there are two GUIDs that map to the name 'USB'.  Device Setup Classes can use the same name for more than one GUID.   To tell you the truth though, I'm not sure why.  Also notice that some of these aren't standard.  For example, 'UsbPcCardReader' is a class installed by the manufacturer of a USB PCMCIA Card reader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-8096912126429957083?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/8096912126429957083/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=8096912126429957083" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/8096912126429957083?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/8096912126429957083?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/_TWSTF1VDoA/working-with-devices-retrieving-device.html" title="Working with Devices: Retrieving Device Setup Class Names" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/05/working-with-devices-retrieving-device.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEGSHw4fyp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-5458111062546024668</id><published>2007-05-27T00:39:00.002-04:00</published><updated>2009-03-06T08:53:49.237-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:53:49.237-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working with Devices: Enumerating Device Setup Classes</title><content type="html">So as promised lets enumerate through the Device Setup Classes.  Sometimes I may say Device Class.  This may be ambiguous with Device Setup Class and Device Interface Class.  Most times I mean Device Setup Class, but I will try to correct myself as I go.&lt;br /&gt;&lt;br /&gt;So the easiest way to see the device setup classes on your computer is simply to view it from the Registry.  Under HKLM\SYSTEM\CurrentControlSet\Control\Class you'll find several Subkeys.  Each subkey represents a setup class by GUID.  You can look at each one and see the name for the setup class.&lt;br /&gt;&lt;br /&gt;For example look at the GUID {4D36E972-E325-11CE-BFC1-08002bE10318}.  You should see that this correlates to the net class.  'net' translates into the friendly name 'Network adapters'.  By expanding this key you'll see more subkeys.  Each subkey represents a device that falls under the net class.&lt;br /&gt;&lt;br /&gt;You may be asking yourself "why do I have so many listed when only a handful show up in device manager?"  This is because a key is created at any time a device is added to the computer.  Even if it is removed the key will remain.  Also there is typically more than one device installed when a physical device is installed.  Another reason is that programs can install non-physical devices like VPN Adapters.  Finally many devices are simply hidden in the device manager.&lt;br /&gt;&lt;br /&gt;So we can get at this through the function &lt;a href="http://msdn2.microsoft.com/en-us/library/ms791140.aspx"&gt;CM_Enumerate_Classes&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is the declare statement that I used.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Private Declare Auto Function CM_Enumerate_Classes Lib "cfgmgr32.dll" (ByVal ClassIndex As Integer, ByRef ClassGuid As Guid, ByVal Reserved As Integer) As Integer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first argument is an index.  We'll start at 0 and then keep incrementing.  The next argument is the Guid that is outputted.  This is the Guid that is at that specific index.  The last argument is reserved and a 0 should be passed.&lt;br /&gt;&lt;br /&gt;Here is some code that will set an index at 0 and keep incrementing it until the result is not 0.  Technically, I believe an error CR_NO_SUCH_VALUE will be returned.  The Guid will be added to an array list and then that list is sorted and returned.&lt;br /&gt;&lt;br /&gt;&lt;blockquote style="font-family: courier new;"&gt;  'Returns an array of all the Class Guids on the System&lt;br /&gt;Private Function GetClassGuids() As ArrayList&lt;br /&gt;Dim i As Integer = 0&lt;br /&gt;Dim Result As Integer&lt;br /&gt;Dim ClassGuid As Guid&lt;br /&gt;Dim GuidList As New ArrayList&lt;br /&gt;Do&lt;br /&gt;   Result = CM_Enumerate_Classes(i, ClassGuid, 0)&lt;br /&gt;   i += 1&lt;br /&gt;   If Result = 0 Then GuidList.Add(ClassGuid)&lt;br /&gt;Loop Until Result &lt;&gt; 0&lt;br /&gt;GuidList.Sort()&lt;br /&gt;Return GuidList&lt;br /&gt;End Function&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So thats it.&lt;br /&gt;&lt;br /&gt;Oh, this code was written in VS.NET 2003 for .NET v1.1&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-5458111062546024668?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/5458111062546024668/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=5458111062546024668" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/5458111062546024668?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/5458111062546024668?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/sOxiH1yc4Bo/working-with-devices-enumerating-device.html" title="Working with Devices: Enumerating Device Setup Classes" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/05/working-with-devices-enumerating-device.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04MQX04cSp7ImA9WxRbGU0.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-1326721637917801189</id><published>2007-05-26T23:57:00.001-04:00</published><updated>2008-12-10T04:39:40.339-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-10T04:39:40.339-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Working with Devices: General Overview</title><content type="html">So lets take a look at what is the most common view of devices on windows&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_oKEGrFRDnAc/RlkFAs9BV3I/AAAAAAAAAAU/yL_AvbLWpGM/s1600-h/devMgr.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_oKEGrFRDnAc/RlkFAs9BV3I/AAAAAAAAAAU/yL_AvbLWpGM/s400/devMgr.JPG" alt="" id="BLOGGER_PHOTO_ID_5069088365207443314" border="0" /&gt;&lt;/a&gt;On the left you see the Device Manager.  To get to this just right click on My Computer and click Manage then click on Device Manager.  You can also add it to the mmc console like I did.&lt;br /&gt;&lt;br /&gt;It shows a tree view with your computer listed at the root and devices under neath that.&lt;br /&gt;&lt;br /&gt;Each Item under your computer is called a Device Setup Class.  Your devices are members of a Device Setup Class.&lt;br /&gt;&lt;br /&gt;So you can see the Printer Port device is a member of the Ports Setup Class.&lt;br /&gt;&lt;br /&gt;Another Class that is used is called the Device Interface Class.  This class basically defines how the device is connected to the computer.&lt;br /&gt;&lt;br /&gt;Imagine that you have two CD-ROM Drives.  One drive is connected through an IDE Cable to your motherboard and the other is connected by USB.  This means that one CD-ROM drive would be in the USB Device interface Class and the other would be in a different Device Interface Class (IDE I guess).  But, BOTH would be in the CD-ROM Setup Class.&lt;br /&gt;&lt;br /&gt;In my limited experience it seems that for interacting with devices for actions such as getting information on them and disabling/enabling then you'll be using the Device Setup Classes.  In the case of registering your application for notifications on devices being inserted and removed then you would be using the Device Interface Classes.&lt;br /&gt;&lt;br /&gt;I'll also say that the Device Interface Classes aren't defined in one single location.  I think that the issue is that the developer should know the Class that he'll be working with and therefore know things like the GUID and whatnot.&lt;br /&gt;&lt;br /&gt;By comparison, the Device Setup Classes' GUIDs are quite readily accessible in one single location.  That is what we'll be going over on the next post.&lt;br /&gt;&lt;br /&gt;For more information on the Device Classes take a look at &lt;a href="http://msdn2.microsoft.com/en-us/library/ms791126.aspx"&gt;Microsoft's MSDN Article&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-1326721637917801189?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/1326721637917801189/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=1326721637917801189" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1326721637917801189?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1326721637917801189?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/nEz2w5VrkRc/working-with-devices-general-overview.html" title="Working with Devices: General Overview" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_oKEGrFRDnAc/RlkFAs9BV3I/AAAAAAAAAAU/yL_AvbLWpGM/s72-c/devMgr.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/05/working-with-devices-general-overview.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMCR3YyeSp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-5772331126618412310</id><published>2007-05-26T22:58:00.002-04:00</published><updated>2009-03-06T08:34:26.891-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:34:26.891-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><title>Working with Devices</title><content type="html">I've written a couple programs that have used the SetupAPI and CfgMgr API.  What made it difficult for me was understanding how to create the correct declare statement and then the proper usage.  Normally the usage was given in C++.  While I could read most of it, some parts were foreign to me.&lt;br /&gt;&lt;br /&gt;So what I thought was that I would start to write on this blog a bit more and post some of the functions along with their use in some sort of sample.  I'll try to start off with the functions with the least dependencies (preferably none) and then start adding more functions that utilize previously discussed functions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-5772331126618412310?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/5772331126618412310/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=5772331126618412310" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/5772331126618412310?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/5772331126618412310?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/ksXqK_9YB9Y/working-with-devices.html" title="Working with Devices" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/05/working-with-devices.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QFRXoyeSp7ImA9WxdRFk4.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-7475856454999077616</id><published>2007-05-21T09:57:00.001-04:00</published><updated>2008-06-04T23:08:34.491-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-04T23:08:34.491-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="free stuff" /><title>Free MS Visual Studio 2005 Standard Edition</title><content type="html">By viewing two labcasts at Microsoft and filling out the review sheet you can receive a free copy of VS 2005 Standard.  I think you have to pay s&amp;amp;h.  Not bad though.&lt;br /&gt;&lt;a href="http://www.microsoft.com/business/vb2005upgrade/labcasts.mspx"&gt;&lt;br /&gt;http://www.microsoft.com/business/vb2005upgrade/labcasts.mspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-7475856454999077616?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/7475856454999077616/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=7475856454999077616" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/7475856454999077616?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/7475856454999077616?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/hZL4lCrlx6w/free-ms-visual-studio-2005-standard.html" title="Free MS Visual Studio 2005 Standard Edition" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/05/free-ms-visual-studio-2005-standard.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UNRHYzeSp7ImA9WxdRFk4.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-1762890787084269609</id><published>2007-03-08T22:05:00.001-05:00</published><updated>2008-06-04T23:08:15.881-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-04T23:08:15.881-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WIM" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="imaging" /><title>WIM Imaging Format.</title><content type="html">I have started development of an interim Vista Enterprise Image.  In doing so I have been using the WIM Imaging Format.  In case you don't know Microsoft is using this as their format for storing Images.  As opposed to Ghost or RDeploy, the WIM format is a file-based Image.  Also you can store multiple Images in one file.  But the best feature of all is that redundant files are automatically removed.  All the images will only reference one file.  So if I have several images all containing notepad.exe then it is only kept once.&lt;br /&gt;&lt;br /&gt;So how well does it work.  We create Images once per quarter and some off cycle releases as well. Mostly new apps, drivers and hotfixes, the usual.  So right now we have 7 Images.  All with Windows XP SP2 and Office 2003.  Those 7 Images equate to 20.4 GB of data stored on our Image Station.  After putting all those images into a WIM file we have one file that is 3.8 GB.  I was shocked to see such an improvement.  I wrote a VBScript that would parse out the XML produced by ImageX and map an Image to a name of the Image in the WIM file.  After that I burned a DVD with WinPE on it.  So now I have 1 DVD with all the Images released in the last year.  Very, very cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-1762890787084269609?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/1762890787084269609/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=1762890787084269609" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1762890787084269609?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/1762890787084269609?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/ofBhLXfBobI/wim-imaging-format.html" title="WIM Imaging Format." /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2007/03/wim-imaging-format.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UASXs4eSp7ImA9WxdRFk4.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-116571646049102280</id><published>2006-12-09T20:23:00.001-05:00</published><updated>2008-06-04T23:07:28.531-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-04T23:07:28.531-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="setupapi" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="drivers" /><title>Unsigned Driver Problem</title><content type="html">Well its been a while since I wrote in this thing.  Had a problem earlier this week that I was working on with the rest of the team. Drivers were being preinstalled on a workstation for use by devices that would be plugged in at a later point by a locked-down user.  These drivers weren't being used and the user is then being prompted for an Admin account to finish the install.&lt;br /&gt;&lt;br /&gt;   So we started looking into it.  I eventually made my way to the SetupAPI log file @ C:\Windows\SetupApi.log.  In it I noticed that where it was showing the driver fail to install it gave in parenthesis about a server side installation.  I thought that was odd until I found this &lt;a href="http://msdn2.microsoft.com/en-us/library/ms791105.aspx"&gt;Microsoft Article&lt;/a&gt;.  I noticed that the log had entries stating that the driver wasn't signed.&lt;br /&gt;&lt;br /&gt;   I went into VB.NET and modified a hash compute program I had.  Instead of using an MD5 Hash, I chose Sha1.  I then used it to compute the hash on the files and compared them to the tag of the inf file.  Sure enough the hash was different.  Additionally the hash on the system files was different as well.  I then noticed that other drivers that worked had hashes that matched for the inf and ini files, but failed for the sys and dll files.  More on that later.&lt;br /&gt;&lt;br /&gt;   Our team decided that we should just sign them ourself.  None of us are certain on how kosher this is, but none the less we proceeded.  We found a &lt;a href="http://www.google.com/url?sa=t&amp;amp;ct=res&amp;amp;cd=1&amp;amp;url=http%3A%2F%2Fdownload.microsoft.com%2Fdownload%2F3%2Fb%2Fa%2F3ba6d659-6e39-4cd7-b3a2-9c96482f5353%2FStep%2520by%2520Step%2520Guide%2520to%2520Device%2520Driver%2520Signing%2520and%2520Staging.doc&amp;amp;ei=MWR7Rcr-GqG6wQLmq9mUCA&amp;amp;usg=__cQu_83o_CY6eKPerm4gSpS0n51Q=&amp;amp;sig2=vzAt06K_fagnPoKQc1IGnA"&gt;Microsoft Doc&lt;/a&gt; that walked through the basics of signing a driver.  What we found was that we needed the Windows Driver Kit.  It just so happens that Microsoft has the RTM version of the Vista WDK @ &lt;a href="http://connect.microsoft.com/"&gt;Microsoft Connect&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;   To summarize how it is done:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Use MakeCert to make a certificate&lt;/li&gt;&lt;li&gt;Import that cert into the Trusted Root and Trusted Publishers sections using CertMgr&lt;/li&gt;&lt;li&gt;Use Signability to create an unsigned Catalog file.&lt;/li&gt;&lt;li&gt;Use Signtool to sign the Catalog file.&lt;/li&gt;&lt;/ol&gt;Note: all these tools we in the %WDK Directory%\bin\SelfSign\  Your results may differ.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   Now all we have to do is import that cert that we created and then pre-install the drivers.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   Everything sailed smoothly after that.  One thing I couldn't understand was why the sys and dll files came up with different Sha1 hashes then what I would compute them out to be, but they would still be considered valid by the Install process.&lt;br /&gt;&lt;br /&gt;   I cleared up my confusion by finding this &lt;a href="http://www.google.com/url?sa=t&amp;amp;ct=res&amp;amp;cd=1&amp;amp;url=http%3A%2F%2Fdownload.microsoft.com%2Fdownload%2F9%2Fc%2F5%2F9c5b2167-8017-4bae-9fde-d599bac8184a%2Fx64KMSigning.doc&amp;amp;ei=2Gl7RfOzMZa2wQLjstSTCA&amp;amp;usg=__dg1FSGVjA1IWNAFv5OoE9VHUiWM=&amp;amp;sig2=eVOcRwzZmm8l6ZIBckFn-Q"&gt;Microsoft Article&lt;/a&gt;.  It stated the following&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;                "&lt;/span&gt;&lt;span style=";font-family:Arial;font-size:10;"  &gt;&lt;span style="font-size:100%;"&gt;A flat file hash is not used for files, such as drivers, that use the portable executable (PE) file format. Instead, relevant sections such as the PE header, executable data, and authenticated attributes are selectively hashed."&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;   I next found a useful API Call, &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/cryptcatadmincalchashfromfilehandle.asp"&gt;CryptCatAdminCalcHashFromFileHandle&lt;/a&gt;.  I used this to make another VB.NET app and verified that the hash was correct for the PE file formats.&lt;br /&gt;&lt;br /&gt;Cool Stuff&lt;br /&gt;&lt;span style=";font-family:Arial;font-size:10;"  &gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-116571646049102280?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/116571646049102280/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=116571646049102280" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/116571646049102280?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/116571646049102280?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/ZjkerZgebEA/unsigned-driver-problem.html" title="Unsigned Driver Problem" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2006/12/unsigned-driver-problem.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQGQ3syfyp7ImA9WxVVE0k.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-114766244024658272</id><published>2006-05-14T22:50:00.002-04:00</published><updated>2009-03-06T08:32:02.597-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T08:32:02.597-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DOS" /><category scheme="http://www.blogger.com/atom/ns#" term="desktop engineer" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Back to DOS</title><content type="html">Well I just finished school and jumped into a little program.&lt;br /&gt;&lt;br /&gt;  Our Image Update to our recently released Image is required to be loaded onto the Image before it boots into the mini-setup of sysprep.  The problem is that the Wise Packaging team uses long file names.  By long I just mean more than eight characters.  Well we found a DOS app which would allow to show both Long File Names and the Standard 8.3 format.  So then we though we were in the clear.&lt;br /&gt;&lt;br /&gt;  Nope, the Firm command uses the 8.3 format when it recurses through the CD. The problem is that it doesn't expand those names to Long format on the destination drive.  Therefore our Image Update will fail.&lt;br /&gt;&lt;br /&gt;  Well now I have created a DOS program in C++ to handle this.  It is a bit silly how I did it, but it works.&lt;br /&gt;&lt;br /&gt;  Basically you have to run a Dir /s on the Root folder that you want to Firm into the destination drive.  This command gives a recursive directory output.  So you will see every directory expanded to show all the files.  Export this data to text file.  Now I call my program with:&lt;br /&gt;&lt;br /&gt;DirConv "&lt;span style="font-style: italic;"&gt;Dir /s Ouput&lt;/span&gt;" "&lt;span style="font-style: italic;"&gt;Output BAT File&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;  The program will take this input and process it line by line and export the correct Firm command.  The firm command will be&lt;br /&gt;&lt;br /&gt;Firm Copy "&lt;span style="font-style: italic;"&gt;Drive Letter"&lt;/span&gt;:\"Short Path"\"Short File Name" "PROD:\"Long Path"\"Long File Name"&lt;br /&gt;&lt;br /&gt;I'll be testing it tomorrow.&lt;br /&gt;&lt;output bat="" file=""&gt;&lt;drive letter=""&gt;&lt;short path=""&gt;&lt;short file="" name=""&gt;&lt;long path=""&gt;&lt;long file="" name=""&gt;&lt;br /&gt;&lt;/long&gt;&lt;/long&gt;&lt;/short&gt;&lt;/short&gt;&lt;/drive&gt;&lt;/output&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-114766244024658272?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/114766244024658272/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=114766244024658272" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/114766244024658272?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/114766244024658272?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/Id3vOFQWl-8/back-to-dos.html" title="Back to DOS" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2006/05/back-to-dos.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YHSXo-eip7ImA9WxdRFk4.&quot;"><id>tag:blogger.com,1999:blog-27669260.post-114722385876395920</id><published>2006-05-09T21:12:00.001-04:00</published><updated>2008-06-04T23:05:38.452-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-04T23:05:38.452-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vb.net" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>More Debugging</title><content type="html">I am now coming to the end of my debugging of the Network switching application.  The program looks acceptable, but it isn't as good as I would like.  This is a big government organization, so a glittery program with tons of bells and whistles is probably not a smart idea, however, some nice look should be considered.   Unfortunately I am not the most artistic person.&lt;br /&gt;&lt;br /&gt;We'll see what I come up with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/27669260-114722385876395920?l=robhaupt.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://robhaupt.blogspot.com/feeds/114722385876395920/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=27669260&amp;postID=114722385876395920" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/114722385876395920?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/27669260/posts/default/114722385876395920?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/ALKg/~3/QGjzTN0UcQo/more-debugging.html" title="More Debugging" /><author><name>Rob Haupt</name><uri>http://www.blogger.com/profile/10036934313516352322</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="25" height="32" src="http://i180.photobucket.com/albums/x184/RobHaupt28/4Blog.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://robhaupt.blogspot.com/2006/05/more-debugging.html</feedburner:origLink></entry></feed>

