<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8214613500374285541</id><updated>2011-12-01T11:09:12.952Z</updated><category term='Set default audio playback device xp'/><category term='FlashWindowEx'/><category term='Visual Studio'/><category term='Results'/><category term='ReadProcessMemory'/><category term='.Net'/><category term='Get usb flash drive serial'/><category term='Rotated Rectangle Collision'/><category term='IUpdateHistoryEntry'/><category term='FieldOffset'/><category term='DRVM_MAPPER_PREFERRED_SET'/><category term='M362'/><category term='SD Card'/><category term='x86'/><category term='RNGCryptoServiceProvider'/><category term='live spaces'/><category term='C++'/><category term='dell'/><category term='SD Card CSD'/><category term='Rotated Rectangle Overlap'/><category term='P/Invoke'/><category term='WriteFile'/><category term='MCQ'/><category term='hard disk'/><category term='SetClipBoardViewer'/><category term='Macro'/><category term='jo0ls&apos; stuff'/><category term='datastore.edb'/><category term='DRVM_MAPPER_PREFERRED_GET'/><category term='IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER'/><category term='xp'/><category term='x64'/><category term='wuapi.dll'/><category term='paste as html'/><category term='M450 Project choice'/><category term='Open university first class server address'/><category term='shuffle'/><category term='exam'/><category term='field offset'/><category term='VirtualAllocEx'/><category term='walsh western'/><category term='B29'/><category term='windows update history'/><category term='enumerate system tray icons'/><category term='enable disable device'/><category term='C++ Invoke'/><category term='live writer'/><category term='M256'/><category term='shuffle cards'/><category term='Open University'/><category term='M366'/><category term='yates fisher'/><category term='API'/><category term='windows update api'/><category term='M256/S'/><category term='SD Card CID'/><category term='C#'/><category term='Create bootable flash disk'/><category term='PhysicalDrive'/><category term='syncreon'/><category term='blogger'/><category term='call lock out'/><category term='StructLayout'/><category term='setup api'/><category term='remove double space lines'/><category term='IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS'/><category term='structure'/><category term='B29 Calculator'/><category term='M450'/><category term='structures'/><category term='VB.Net'/><category term='WDK'/><category term='guid shuffle'/><category term='read serial number'/><category term='global keyboard hook'/><category term='FilterBar'/><category term='ufd serial'/><category term='Pack'/><title type='text'>jo0ls' .Net stuff</title><subtitle type='html'>.Net programming, c#, vb.net, ...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-4287516614719187928</id><published>2011-10-09T20:34:00.001+01:00</published><updated>2011-10-09T20:34:27.723+01:00</updated><title type='text'>Reading CD-Text with VB.Net (3)</title><content type='html'>&lt;p&gt;Last time we had retrieved a big blob of data that holds the CD-Text. The mmc3 document tells us the blob is a series of CD-TEXT Pack Data, which we can call packs for short. All the information is contained in these packs, but the packs themselves describe a more complicated data structure that we need to recreate. I used the mmc document, &lt;a href="http://www.patentstorm.us/patents/6519676/fulltext.html"&gt;patent application&lt;/a&gt; and open source projects to understand this structure. &lt;/p&gt;  &lt;p&gt;All the text is stored in one Text Group, which is what we have retrieved. The text group contains up to 8 Blocks numbered 0 to 7. It is possible for a CD to have text in multiple languages, each Block contains text in one language only. Each Block is made up of Packs. A block can contain up to 255 Packs, each pack in a block will have a unique Sequence Number 0-255. If the text is particularly large then it may need multiple blocks to fit it all in. (One block contains text for one language only, one language may require multiple blocks.)&lt;/p&gt;  &lt;p&gt;Each pack is 18 bytes in size and has three sections – a 4 byte header, 12 bytes of data and 2 bytes for a CRC. The header of a pack contains it’s block number. The header has one byte to hold the sequence number. The header also contains a number that identifies the type of data that the pack stores. For example the pack type &amp;amp;H80 means the data portion of the pack contains text data forming part of the album or track titles. As it’s only 12 bytes of data in a pack, you might need several packs to describe, say, the title of track 3. The track number is also stored in the header, track number 0 is special and means the data relates to the CD as a whole rather than a particular track. For the Title pack type, for example, track number 0 is the title of the album.&lt;/p&gt;  &lt;p&gt;An important pack type is the size pack type. Each block has 3 size packs. These do not contain text data, instead the bytes map to various counts and other numerical information. The size packs describe a block’s: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;character code - how the text data in the pack types that store text is encoded. E.g. ASCII &lt;/li&gt;    &lt;li&gt;first track number, last track number &lt;/li&gt;    &lt;li&gt;copy protection info &lt;/li&gt;    &lt;li&gt;number of packs of each pack type in the block &lt;/li&gt;    &lt;li&gt;last sequence number of each block (0 if the block number is not used, this information must be repeated in each block as it’s not specific to the block that contains the size packs) &lt;/li&gt;    &lt;li&gt;&lt;a href="http://books.google.co.uk/books?id=bw85Fbf0TzsC&amp;amp;lpg=PP1&amp;amp;dq=%22Standard%20handbook%20of%20audio%20and%20radio%20engineering%22&amp;amp;pg=SA7-PA76#v=onepage&amp;amp;q&amp;amp;f=false"&gt;language code&lt;/a&gt; – this tells us which language the block is for e.g. English, Afrikaans, French etc. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Most of the packs contain text information for the tracks or album. If we have an imaginary CD which has 3 tracks with title data for each track and the album, e.g:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Album title = “Hello World Album” (Track 0) &lt;/li&gt;    &lt;li&gt;Track 1 = “I’m the urban spaceman” &lt;/li&gt;    &lt;li&gt;Track 2 = “The intro and the outro” &lt;/li&gt;    &lt;li&gt;Track 3 = “Poisoning pigeons in the park” &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Then we would split each string up into chars and append a Chr(0) to indicate the end of that string. We chop it into 12 byte sections and make a pack for each section. This table shows the 18 bytes of a pack, 4 (H)eader bytes, 12 (D)ata bytes and 2 (C)rc bytes. /0 indicates a Chr(0). The first header byte is the pack type – for us &amp;amp;H80. The second header byte contains 7 bits identifying the track number (there’s another bit which we are going to say isn’t set). As the data might contain sections of information from multiple tracks, the track number identifies which track the first byte of track data belongs to. The block sequence number is in the third header byte – let’s imagine that these packs happened to start at block sequence number &amp;amp;H10. The eight bits of information in the fourth header byte encode three things – whether the text uses 1 byte or two per character, the block number (0 – 7) and the position that the first character in the data takes in it’s string. The character position isn’t useful to us (maybe it is useful in C or ASM). Let’s ignore this byte, and the Crc bytes, and just assume it’s all in one block.&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2" width="392"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="25"&gt;&lt;font face="Courier New"&gt;H &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;H &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="25"&gt;&lt;font face="Courier New"&gt;H&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;H &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="25"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="25"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="25"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="25"&gt;&lt;font face="Courier New"&gt;D &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;C &lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;C &lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;10&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;H&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;l&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;l&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;W&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;r&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;l&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;d&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;11&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;A&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;l&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;b&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;u&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;m&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;/0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;I&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;‘&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;m&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;t&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;h&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;1&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;12&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;u&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;r&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;b&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;a&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;s&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;p&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;a&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;c&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;1&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;13&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;m&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;a&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;/0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;T&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;h&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;i&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;t&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;2&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;14&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;r&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;a&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;d&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;t&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;h&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;2&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;15&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;u&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;t&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;r&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;/0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;P&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;i&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;s&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;i&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;3&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;16&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;g&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;p&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;i&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;g&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;o&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;s&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;i&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;80&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;3&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="26"&gt;&lt;font face="Courier New"&gt;17&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;n&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;t&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;h&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="27"&gt;&lt;font face="Courier New"&gt;e&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="27"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;p&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;a&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;r&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;k&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="27"&gt;&lt;font face="Courier New"&gt;/0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="27"&gt;&lt;font face="Courier New"&gt;/0&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;        &lt;td valign="top" width="20"&gt;&lt;font face="Courier New"&gt;&lt;/font&gt;&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;There are various pack types like this – for the title, performer, songwriter, composer, arranger, messages. There are also other pack types which contain other types of information, like the size pack type. For example, there are pack types for CD Information, Toc information and Genre information. These are always encoded in ASCII, and they are not encoded individually for each language on a multi-language CD.&lt;/p&gt;  &lt;p&gt;I imagine that multi-language CDs don’t exist in the wild. When testing burning apps I found none of them would use multiple blocks either. It seems most CDs then will just have 1 block, 1 language and use ASCII, which makes it pretty easy to decode a CD. I’m not exactly sure what happens if you have to split a language over blocks. I guess it just picks up where the last one left off.&lt;/p&gt;  &lt;p&gt;In .Net we can have some class CdText to store the properties that apply to the cd as a whole. Then it’s probably easiest to shove the language based information into a datatable. Here we have a primary key of (Language, Track No), and columns for things like Title, Performer, … etc. We can stick some helper properties onto the main class to list the available languages etc.&lt;/p&gt;  &lt;p&gt;&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/CD%20Text/CdText3.zip?cid=862dee3ec267cb5c&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-4287516614719187928?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/4287516614719187928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/10/reading-cd-text-with-vbnet-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4287516614719187928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4287516614719187928'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/10/reading-cd-text-with-vbnet-3.html' title='Reading CD-Text with VB.Net (3)'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3778983502390203054</id><published>2011-09-17T00:32:00.001+01:00</published><updated>2011-09-17T00:32:54.400+01:00</updated><title type='text'>Reading CD-Text with VB.Net (2)</title><content type='html'>&lt;p&gt;&lt;font size="3"&gt;I mentioned, in the &lt;a href="http://jo0ls-dotnet-stuff.blogspot.com/2011/09/reading-cd-text-with-vbnet-1.html" target="_blank"&gt;first part&lt;/a&gt;, that there are two control codes that you can send to get the CD-Text bytes back. We’ve used &lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;a style="color: rgb(128,0,128); text-decoration: none" href="http://msdn.microsoft.com/en-us/library/ff559367(v=VS.85).aspx"&gt;&lt;font size="3" face="Courier New"&gt;IOCTL_CDROM_READ_TOC_EX&lt;/font&gt;&lt;/a&gt;&lt;span class="Apple-converted-space"&gt; and now it’s the turn of the slightly trickier &lt;a href="http://msdn.microsoft.com/en-us/library/ff560521(v=vs.85).aspx" target="_blank"&gt;&lt;font size="3" face="Courier New"&gt;IOCTL_SCSI_PASS_THROUGH_DIRECT&lt;/font&gt;&lt;/a&gt;. &lt;font size="3"&gt;This one lets us send any message we like to the device. To learn about the messages that you can send, you need to get your hands on a copy of the standard specification that defines them all. Hardware manufacturers are supposed to conform to the standard so that all the devices understand the same commands. &lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;The standards of interest are the ones for &lt;/font&gt;&lt;a href="http://www.t10.org/scsi-3.htm" target="_blank"&gt;&lt;font size="3"&gt;scsi devices&lt;/font&gt;&lt;/a&gt;&lt;font size="3"&gt;. You have to pay for access to the latest standards, and it looks like access to the ftp for draft standards is now restricted. The old standards are available on the internet in various places though. I still have my copies of mmc3r10g.pdf and spc2r20.pdf. It has some information that will come in handy later about the format of the bytes we have been retrieving. You can find yet more information on this format by looking at open source projects such as &lt;/font&gt;&lt;a href="http://cdrdao.sourceforge.net/" target="_blank"&gt;&lt;font size="3"&gt;cdrdao&lt;/font&gt;&lt;/a&gt;&lt;font size="3"&gt;, the &lt;/font&gt;&lt;a href="http://www.patentstorm.us/patents/6519676/fulltext.html" target="_blank"&gt;&lt;font size="3"&gt;original patent application&lt;/font&gt;&lt;/a&gt;&lt;font size="3"&gt; by Sony and various other projects. The real standard is the &lt;/font&gt;&lt;a href="http://en.wikipedia.org/wiki/Red_Book_(CD_standard)" target="_blank"&gt;&lt;font size="3"&gt;Red Book&lt;/font&gt;&lt;/a&gt;&lt;font size="3"&gt;&lt;font face="Verdana"&gt; (IEC 60908), but that costs £200 to access.&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;Anyway, we have to call &lt;font face="Courier New"&gt;DeviceIoControl&lt;/font&gt; with this other command code. We send it a structure that will contain a cdb (command data block) along with a buffer to contain the bytes that are coming back, and another buffer for so called sense-information. Sense information is helpful as it contains error information – and there are many things that can go wrong – tray out, no cd, DVD inserted, drive not ready, etc. This is probably the only reason to use this message over the other one – you can get back the sense information. It’s also useful to know how to send any command as there are a lot of them in the specification, and they don’t all have an equivalent “friendly” IOCTL code.&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;The command we are sending is the READ TOC command, the cdb is just 10 bytes in size. It contains one byte for the command code (&amp;amp;H43). Then a byte we can ignore. Then there’s a byte that holds the format. This is the same thing as the format we send with &lt;font face="Courier New"&gt;IOCTL_READ_TOC_EX&lt;/font&gt; – we can specify different values to get different TOC information. Again, we want to set this to 5 to retrieve CD-Text (see the spec). After that there are reserved, and inapplicable bytes (given the format). At the end there are two bytes to say how big our buffer is, and finally a control byte.&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;The cdb and a pointer to the databuffer go into a &lt;font face="Courier New"&gt;SCSI_PASS_THROUGH_DIRECT&lt;/font&gt; structure. This structure is then placed inside another structure that also holds the sense buffer. &lt;font face="Courier New"&gt;SCSI_PASS_THROUGH_DIRECT&lt;/font&gt; looks like this:&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Friend&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt; SCSI_PASS_THROUGH_DIRECT                           &lt;span class="rem"&gt;' x86   x64&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; Length &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Short&lt;/span&gt;                                          &lt;span class="rem"&gt;'  0      0&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; ScsiStatus &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                       &lt;span class="rem"&gt;'  2      2&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; PathId &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                           &lt;span class="rem"&gt;'  3      3&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; TargetId &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                         &lt;span class="rem"&gt;'  4      4&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; Lun &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                              &lt;span class="rem"&gt;'  5      5&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; CdbLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                        &lt;span class="rem"&gt;'  6      6&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; SenseInfoLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                  &lt;span class="rem"&gt;'  7      7&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataIn &lt;span class="kwrd"&gt;As&lt;/span&gt; CommandDirection                               &lt;span class="rem"&gt;'  8      8&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataTransferLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;                            &lt;span class="rem"&gt;' 12     12 &lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; TimeOutValue &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;                                  &lt;span class="rem"&gt;' 16     16&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataBuffer &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr                                     &lt;span class="rem"&gt;' 20     24&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; SenseInfoOffset &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;                               &lt;span class="rem"&gt;' 24     32&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &amp;lt;MarshalAs(UnmanagedType.ByValArray, SizeConst:=16)&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; Cdb() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;                                            &lt;span class="rem"&gt;' 28     36&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="rem"&gt;'                                                        Size     44     56&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; GetSize() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Return&lt;/span&gt; Marshal.SizeOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(SCSI_PASS_THROUGH_DIRECT))&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Structure&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;I’ve got the offsets/sizes that I calculated in C in the comments. You can see that the &lt;font face="Courier New"&gt;IntPtr&lt;/font&gt; field is larger on x64. Here the cdb array is marshalled as a &lt;font face="Courier New"&gt;ByValArray&lt;/font&gt; which tells the marshaller to stick the bytes directly into the memory of the structure. The alternative is for the bytes to live elsewhere and for the field in the structure to be a pointer to them. We have to fill in this structure, which means we have to know what the &lt;font face="Courier New"&gt;PathId&lt;/font&gt;, &lt;font face="Courier New"&gt;TargetId&lt;/font&gt; and &lt;font face="Courier New"&gt;Lun&lt;/font&gt; of the CD drive are. We can get those with &lt;font face="Courier New"&gt;IOCTL_SCSI_GET_ADDRESS&lt;/font&gt;. The &lt;font face="Courier New"&gt;SenseInfoLength&lt;/font&gt; is 32. The &lt;font face="Courier New"&gt;SenseInfoOffset&lt;/font&gt; can be calculated at runtime using &lt;font face="Courier New"&gt;Marshal.OffsetOf&lt;/font&gt; to get the offset of the sense buffer in the outer structure (see attached project) – it will vary on x86 and x64.&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;As before, we’ll call once with a data buffer of size 2. On return, our data buffer will contain the size of the data (excluding the field that holds the size itself). So we can then allocate precisely as much memory as is required to hold the whole CD-Text. &lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Option&lt;/span&gt; Strict &lt;span class="kwrd"&gt;On&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Option&lt;/span&gt; Explicit &lt;span class="kwrd"&gt;On&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; CdTextIoCtl.NativeMethods&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; Microsoft.Win32.SafeHandles&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.ComponentModel&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.IO&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Runtime.InteropServices&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Text&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt; CdTextRetriever&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; GetCdText(driveInfo &lt;span class="kwrd"&gt;As&lt;/span&gt; DriveInfo) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; cdText &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt; = &lt;span class="kwrd"&gt;Nothing&lt;/span&gt; &lt;span class="rem"&gt;' don't know what the return will look like yet.&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; devicePath &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="kwrd"&gt;String&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;\\.\{0}:&amp;quot;&lt;/span&gt;, driveInfo.Name(0))&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FILE_ATTRIBUTE_NORMAL &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H80&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GENERIC_READ &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H80000000UI&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GENERIC_WRITE &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H40000000&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FILE_SHARE_READ &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = 1&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FILE_SHARE_WRITE &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = 2&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; OPEN_EXISTING &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = 3&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        Using hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle = NativeMethods.CreateFile(devicePath,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                GENERIC_READ &lt;span class="kwrd"&gt;Or&lt;/span&gt; GENERIC_WRITE,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                FILE_SHARE_READ &lt;span class="kwrd"&gt;Or&lt;/span&gt; FILE_SHARE_WRITE,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                IntPtr.Zero, OPEN_EXISTING,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;If&lt;/span&gt; hDevice.IsInvalid &lt;span class="kwrd"&gt;OrElse&lt;/span&gt; hDevice.IsClosed &lt;span class="kwrd"&gt;Then&lt;/span&gt; &lt;span class="kwrd"&gt;Throw&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            ReadCdText(hDevice)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; Using&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Return&lt;/span&gt; cdText&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; ReadCdText(hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; address &lt;span class="kwrd"&gt;As&lt;/span&gt; SCSI_ADDRESS = GetScsiAddress(hDevice)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="rem"&gt;' like in the other program...get the length&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytes(1) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        GetCdTextBytes(hDevice, address, bytes)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="rem"&gt;' again we add 2 for the length parameter itself so it's length - 1 + 2 to size the array&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        bytes = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;((&lt;span class="kwrd"&gt;CType&lt;/span&gt;(bytes(0), &lt;span class="kwrd"&gt;Integer&lt;/span&gt;) &amp;lt;&amp;lt; 8) &lt;span class="kwrd"&gt;Or&lt;/span&gt; bytes(1) + 1) {}&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        GetCdTextBytes(hDevice, address, bytes)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; sb &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; StringBuilder&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;For&lt;/span&gt; i &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 4 &lt;span class="kwrd"&gt;To&lt;/span&gt; bytes.Length - 19 &lt;span class="kwrd"&gt;Step&lt;/span&gt; 18&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;For&lt;/span&gt; j &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 0 &lt;span class="kwrd"&gt;To&lt;/span&gt; 17&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                sb.Append(bytes(i + j).ToString(&lt;span class="str"&gt;&amp;quot;X2&amp;quot;&lt;/span&gt;))&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                &lt;span class="kwrd"&gt;If&lt;/span&gt; i = 3 &lt;span class="kwrd"&gt;OrElse&lt;/span&gt; i = 16 &lt;span class="kwrd"&gt;Then&lt;/span&gt; sb.Append(&lt;span class="str"&gt;&amp;quot;  &amp;quot;&lt;/span&gt;)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Next&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            sb.AppendLine()&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Next&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        My.Computer.FileSystem.WriteAllText(IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyDocuments, IO.Path.GetRandomFileName), sb.ToString, &lt;span class="kwrd"&gt;False&lt;/span&gt;)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; GetScsiAddress(hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle) &lt;span class="kwrd"&gt;As&lt;/span&gt; SCSI_ADDRESS&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; address &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; SCSI_ADDRESS&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; IOCTL_SCSI_GET_ADDRESS &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H41018&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt; = NativeMethods.DeviceIoControl(hDevice,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                IOCTL_SCSI_GET_ADDRESS, IntPtr.Zero, 0, address,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                SCSI_ADDRESS.GetSize, bytesReturned, IntPtr.Zero)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;If&lt;/span&gt; result = &lt;span class="kwrd"&gt;False&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt; &lt;span class="kwrd"&gt;Throw&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; GetCdTextBytes(hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle, address &lt;span class="kwrd"&gt;As&lt;/span&gt; SCSI_ADDRESS, bytes() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; sptdwb &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; pinnedBytesHandle &lt;span class="kwrd"&gt;As&lt;/span&gt; GCHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.cdb = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;(15) {} &lt;span class="rem"&gt;' The cdb as described in the standard&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.SenseBuffer = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;(31) {}&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.Length = &lt;span class="kwrd"&gt;CShort&lt;/span&gt;(SCSI_PASS_THROUGH_DIRECT.GetSize)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.CdbLength = 10&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.DataIn = CommandDirection.SCSI_IOCTL_DATA_IN&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.DataTransferLength = bytes.Length&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.DataBuffer = pinnedBytesHandle.AddrOfPinnedObject&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.TimeOutValue = 10&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.SenseInfoOffset = Marshal.OffsetOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), &lt;span class="str"&gt;&amp;quot;SenseBuffer&amp;quot;&lt;/span&gt;).ToInt32&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.SenseInfoLength = 24&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.PathId = address.PathId&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.TargetId = address.TargetId&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.Lun = address.Lun&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="rem"&gt;' CDB is set with the READ_TOC command&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.cdb(0) = &amp;amp;H43&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.cdb(2) = 5&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.cdb(7) = &lt;span class="kwrd"&gt;CByte&lt;/span&gt;((bytes.Length &amp;gt;&amp;gt; 8) &lt;span class="kwrd"&gt;And&lt;/span&gt; &amp;amp;HFF)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        sptdwb.ScsiPassThroughDirect.cdb(8) = &lt;span class="kwrd"&gt;CByte&lt;/span&gt;(bytes.Length &lt;span class="kwrd"&gt;And&lt;/span&gt; &amp;amp;HFF)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Try&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Const&lt;/span&gt; IOCTL_SCSI_PASS_THROUGH_DIRECT &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H4D014&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt; = NativeMethods.DeviceIoControl(hDevice,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;               IOCTL_SCSI_PASS_THROUGH_DIRECT,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;               sptdwb,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;               Marshal.SizeOf(sptdwb),&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;               sptdwb,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;               Marshal.SizeOf(sptdwb),&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;               bytesReturned,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;               IntPtr.Zero)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;If&lt;/span&gt; result = &lt;span class="kwrd"&gt;False&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt; &lt;span class="kwrd"&gt;Throw&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Finally&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            pinnedBytesHandle.Free()&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;So, that’s another way to read the same bytes. I’ve told this one to save a file with a dump of the bytes into MyDocuments. It splits the data into lines with 18 bytes on each. It starts at byte 4 to skip the length and two other bytes which appear before the Pack Data. Pack Data contains 12 bytes of information each with a header describing the information and a 2 byte CRC code at the end. Most of the information will be ascii text, although some packs don’t contain text. The header contains a pack type code which has things like Title, Songwriter, etc. It also has values to identify the track number that the data is for. It’s quite a simple format, but tricky to decode without a precise definition of the format! These projects are a bit naff – I’ve not used VS2010 much and it’s messing up my solution with 2 projects in. I can’t seem to get it so that you can switch easily between x86 and AnyCpu builds, so it ends up in mixed mode. You can just start a new empty solution and add the relevant bits if it wont build and run.&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style="widows: 2; text-transform: none; background-color: rgb(255,255,255); text-indent: 0px; letter-spacing: normal; font: 14px verdana, sans-serif; white-space: normal; orphans: 2; color: rgb(0,0,0); word-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"&gt;&lt;span class="Apple-converted-space"&gt;&lt;font size="3"&gt;Next time I’ll decode the bytes, check the crcs and the sense information. I’ve found that occasionally I get some corrupt data coming in the first time it reads – hopefully the CRC will fail and I can retry.&lt;/font&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/CD%20Text/CdTextIoCtl.zip?cid=862dee3ec267cb5c&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/p&gt;

&lt;p&gt;&lt;font size="3"&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;font size="3"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3778983502390203054?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3778983502390203054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/09/reading-cd-text-with-vbnet-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3778983502390203054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3778983502390203054'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/09/reading-cd-text-with-vbnet-2.html' title='Reading CD-Text with VB.Net (2)'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-835516281995910293</id><published>2011-09-11T21:44:00.001+01:00</published><updated>2011-09-14T20:40:56.467+01:00</updated><title type='text'>Reading CD-Text with VB.Net (1)</title><content type='html'>&lt;p&gt;&lt;font size="2"&gt;Note: most commercial CDs &lt;strong&gt;do not have any CD Text&lt;/strong&gt; on them.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;There are probably a few ways to read the CD Text. I’m going to look at using the windows api function &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa363216(v=vs.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;DeviceIOControl&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; function. The steps are (1) Get a device handle (2) Prepare a message (3) Send the message to the device (4) Decode the results.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;To get a device handle, you call &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;CreateFile&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; sending the drive letter of the drive &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx#win32_device_namespaces"&gt;&lt;font size="2"&gt;formatted as a device path&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt;. You also have to specify the minimum permissions you will be needing for the operations you will be performing. If you fail to ask for a handle with sufficient permissions then you will get errors later on when you are calling &lt;font face="Courier New"&gt;DeviceIOControl&lt;/font&gt;. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;In .Net you can pick &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ac7ay120.aspx"&gt;&lt;font size="2"&gt;various types to represent handles&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt;. I’ve seen people use &lt;font face="Courier New"&gt;Integer&lt;/font&gt; – which isn’t good as &lt;font face="Courier New"&gt;Integer&lt;/font&gt; is always 32 bits whereas handles may be 64 bits. &lt;font face="Courier New"&gt;IntPtr&lt;/font&gt; is a better choice as it will match the size of the C &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;HANDLE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; type it is representing. &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.handleref.aspx"&gt;&lt;font size="2" face="Courier New"&gt;HandleRef&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is another good choice, this is used to prevent the garbage collector from destroying your handle before a call ends – which would be embarrassing. &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx"&gt;&lt;font size="2" face="Courier New"&gt;SafeHandle&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is the best choice to use as it ensures that the handle will be closed in certain unusual circumstances. &lt;font face="Courier New"&gt;SafeHandle&lt;/font&gt; is an abstract class, there are various concrete implementations. For a device handle we can use the &lt;font face="Courier New"&gt;SafeFileHandle&lt;/font&gt;. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;The &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff559367(v=VS.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;IOCTL_CDROM_READ_TOC_EX&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; control code can be used to get the CD-Text back from the drive. Another alternative is to use a less specific control code such as&lt;font face="Courier New"&gt;&amp;#160; &lt;/font&gt;&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff560519(v=vs.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;IOCTL_SCSI_PASS_THROUGH&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; which lets you send any command to the drive, it’s a bit more involved – I’ll show how to use that later. When you are working from scratch, and trying to figure this stuff out for yourself, it helps to have a C++ project that you can use to dump out the values of the constants, size of structures, and offsets of structure fields. A bit of work in C++ can save a lot of time searching the internet with vague error messages like “A call to PInvoke function xyz has unbalanced the stack”. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;If you want to set up a C++ project then the steps are:      &lt;br /&gt;1) Download and install the WDK. It’s a big download. The bit you need are the “Build Environments”, as selecting this will ensure that the header files are installed.       &lt;br /&gt;2) Start visual studio 2010 and a new C++ CLR Console application project called, say, StructSizes       &lt;br /&gt;3) Right click the project name in the solution explorer, click References, Add New Reference and add System.Windows.Forms.       &lt;br /&gt;4) Right click the project name in the solution explorer, click Properties, Drill down to Configuration Properties/VC++ Directories and then select Include Directories. Edit the string to include the path to the wdk header files. This will involve adding a “;” and then the path. Mine looks like this after the edit: &lt;font face="Courier New"&gt;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;C:\WinDDK\7600.16385.1\inc\api&lt;/font&gt;       &lt;br /&gt;5) As an example lets dump out the value of the IOCTL command and some info about a structure. This goes into the cpp file with the same name as the project, so StructSizes.cpp. &lt;/font&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;#include &lt;span class="str"&gt;&amp;quot;stdafx.h&amp;quot;&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;#include &amp;lt;Windows.h&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;#include &amp;lt;winioctl.h&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;#include &amp;lt;ntddcdrm.h&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;#include &amp;lt;ntddscsi.h&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;#include &amp;lt;stddef.h&amp;gt; &lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; System;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; System::Text;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; System::Windows::Forms;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;[STAThread()] &lt;span class="rem"&gt;// to make the clipboard happy.&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; main(array&amp;lt;System::String ^&amp;gt; ^args)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;{&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    StringBuilder ^sb = gcnew System::Text::StringBuilder();&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine(L&lt;span class="str"&gt;&amp;quot;IOCTL_CDROM_READ_TOC_EX: &amp;quot;&lt;/span&gt; + (IOCTL_CDROM_READ_TOC_EX).ToString(L&lt;span class="str"&gt;&amp;quot;x2&amp;quot;&lt;/span&gt;));&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine(L&lt;span class="str"&gt;&amp;quot;SCSI_PASS_THROUGH offsets + size:&amp;quot;&lt;/span&gt;);    &lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::Length)).ToString() + L&lt;span class="str"&gt;&amp;quot; Length&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::ScsiStatus)).ToString() + L&lt;span class="str"&gt;&amp;quot; ScsiStatus&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::PathId)).ToString() + L&lt;span class="str"&gt;&amp;quot; PathId&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::TargetId)).ToString() + L&lt;span class="str"&gt;&amp;quot; TargetId&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::Lun)).ToString() + L&lt;span class="str"&gt;&amp;quot; Lun&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::CdbLength)).ToString() + L&lt;span class="str"&gt;&amp;quot; CdbLength&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::SenseInfoLength)).ToString() + L&lt;span class="str"&gt;&amp;quot; SenseInfoLength&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::DataIn)).ToString() + L&lt;span class="str"&gt;&amp;quot; DataIn&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::DataTransferLength)).ToString() + L&lt;span class="str"&gt;&amp;quot; DataTransferLength&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::TimeOutValue)).ToString() + L&lt;span class="str"&gt;&amp;quot; TimeOutValue&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::DataBufferOffset)).ToString() + L&lt;span class="str"&gt;&amp;quot; DataBufferOffset&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::SenseInfoOffset)).ToString() + L&lt;span class="str"&gt;&amp;quot; SenseInfoOffset&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine((offsetof(SCSI_PASS_THROUGH, SCSI_PASS_THROUGH::Cdb[0])).ToString() + L&lt;span class="str"&gt;&amp;quot; Cdb[0]&amp;quot;&lt;/span&gt;);&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine(L&lt;span class="str"&gt;&amp;quot;**TOTAL SIZE: &amp;quot;&lt;/span&gt; + (&lt;span class="kwrd"&gt;sizeof&lt;/span&gt;(SCSI_PASS_THROUGH)).ToString());&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine();&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    sb-&amp;gt;AppendLine();&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    Console::WriteLine(sb-&amp;gt;ToString());&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    Clipboard::SetText(sb-&amp;gt;ToString());&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    Console::ReadKey();&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;}&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;font size="2"&gt;6) It should build and run. It sets the clipboard with the text. You can’t dump out the offset of bit fields, like you get in the &lt;font face="Courier New"&gt;CDROM_READ_TOC_EX&lt;/font&gt; structure. You should dump out x86 and x64 versions so that you can check your .Net structures match on both.&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;font size="2"&gt;Let’s say you’ve made your .Net structure, called ScsiPassThrough, and want to see the offset of the Length field and the size. You would use the &lt;font face="Courier New"&gt;SizeOf&lt;/font&gt; and &lt;font face="Courier New"&gt;OffsetOf&lt;/font&gt; methods of the &lt;font face="Courier New"&gt;Marshal&lt;/font&gt; class which is in the &lt;font face="Courier New"&gt;System.Runtime.InteropServices&lt;/font&gt; namespace. e.g.:&lt;/font&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;Console.WriteLine(Marshal.OffsetOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ScsiPassThrough), &lt;span class="str"&gt;&amp;quot;Length&amp;quot;&lt;/span&gt;).ToString)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;Console.WriteLine(Marshal.SizeOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ScsiPassThrough)))&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;font size="2"&gt;Ok, back to the task in hand. We want to send &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff559367(v=VS.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;IOCTL_CDROM_READ_TOC_EX&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; which has the value &amp;amp;H24054. The documentation says we have to send a structure &lt;font face="Courier New"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff551366(v=VS.85).aspx"&gt;CDROM_READ_TOC_EX&lt;/a&gt;&lt;/font&gt; to specify what exactly we want to get back from the TOC.&lt;/font&gt; &lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;typedef &lt;span class="kwrd"&gt;struct&lt;/span&gt; _CDROM_READ_TOC_EX {&lt;/pre&gt;

  &lt;pre&gt;    UCHAR Format    : 4;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    UCHAR Reserved1 : 3; &lt;span class="rem"&gt;// future expansion&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;    UCHAR Msf       : 1;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    UCHAR SessionTrack;&lt;/pre&gt;

  &lt;pre&gt;    UCHAR Reserved2;     &lt;span class="rem"&gt;// future expansion&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    UCHAR Reserved3;     &lt;span class="rem"&gt;// future expansion&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;font size="2"&gt;This structure has a size of 4 bytes on x86 and x64. We need to set the &lt;font face="Courier New"&gt;Format&lt;/font&gt; field to &lt;font face="Courier New"&gt;CDROM_READ_TOC_EX_FORMAT_CDTEXT&lt;/font&gt; (value 5) to say we want to retrieve CD Text. All the others will be 0. The structure is made up of 4 bytes. &lt;font face="Courier New"&gt;SessionTrack&lt;/font&gt;, &lt;font face="Courier New"&gt;Reserved2&lt;/font&gt; and &lt;font face="Courier New"&gt;Reserved3&lt;/font&gt; get a byte each. The other byte is divided up into 3 fields – &lt;font face="Courier New"&gt;Format&lt;/font&gt;, &lt;font face="Courier New"&gt;Reserved1&lt;/font&gt; and &lt;font face="Courier New"&gt;Msf&lt;/font&gt;. &lt;font face="Courier New"&gt;Format&lt;/font&gt; takes the lo 4 bits of the byte. &lt;font face="Courier New"&gt;Reserved&lt;/font&gt; takes the next 3 and &lt;font face="Courier New"&gt;Msf&lt;/font&gt; takes the hi bit. We can’t split fields up in .Net like that. We can either declare a structure that has 4 byte fields, and expose the three bit fields with properties, or, as we just want to set the one field, we could also just send an integer with the correct bit pattern - an integer has the same size and all the dll that we are calling cares about is that it gets 4 bytes with the correct bits set. I came up with this:&lt;/font&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Friend&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt; CDROM_READ_TOC_EX&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; FormatReservedMsf &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; SessionTrack &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; Reserved2 &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; Reserved3 &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="rem"&gt;' properties will just read the public fields without contributing to the size of the structure.&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;ReadOnly&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt; Format &lt;span class="kwrd"&gt;As&lt;/span&gt; ReadTocExFormat&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Return&lt;/span&gt; &lt;span class="kwrd"&gt;CType&lt;/span&gt;(FormatReservedMsf &lt;span class="kwrd"&gt;And&lt;/span&gt; &amp;amp;HF, ReadTocExFormat)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;ReadOnly&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt; Reserved1 &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Return&lt;/span&gt; (FormatReservedMsf &amp;gt;&amp;gt; 4) &lt;span class="kwrd"&gt;And&lt;/span&gt; &amp;amp;H7&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;ReadOnly&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt; Msf &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Return&lt;/span&gt; (FormatReservedMsf &lt;span class="kwrd"&gt;And&lt;/span&gt; &amp;amp;H80) = &amp;amp;H80&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; SetFormatReservedMsf(format &lt;span class="kwrd"&gt;As&lt;/span&gt; ReadTocExFormat, msf &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt;)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        FormatReservedMsf = &lt;span class="kwrd"&gt;CByte&lt;/span&gt;(format &lt;span class="kwrd"&gt;Or&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;(msf, &amp;amp;H80, 0))&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;ReadOnly&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt; Size &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;Return&lt;/span&gt; 4&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Get&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Property&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Structure&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;font size="2"&gt;The documentation says that when we send the message we should also send a buffer. On return the buffer will contain a &lt;font face="Courier New"&gt;CDROM_TOC_CD_TEXT_DATA&lt;/font&gt; structure, followed by an array of&lt;font face="Courier New"&gt; &lt;/font&gt;&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ff551382(v=vs.85).aspx"&gt;&lt;font size="2" face="Courier New"&gt;CDROM_TOC_CD_TEXT_DATA_BLOCK&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; structures. So – how big should the buffer be to hold all this? The answer is that we don’t know. We can either create a huge buffer that will be big enough, or we can call once to read the &lt;font face="Courier New"&gt;CDROM_TOC_CD_TEXT_DATA.Length&lt;/font&gt; field and use that to size the buffer. The buffer can be an array of bytes – they are easy to marshal if one of the parameters states the size of the array. &lt;font face="Courier New"&gt;DeviceIOControl&lt;/font&gt; will look like this:&lt;/font&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;lt;DllImport(&lt;span class="str"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span class="kwrd"&gt;True&lt;/span&gt;)&amp;gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; DeviceIoControl(hVol &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle, controlCode &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;   &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; inbuffer &lt;span class="kwrd"&gt;As&lt;/span&gt; CDROM_READ_TOC_EX, inBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;   &amp;lt;MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=6)&amp;gt; &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; outBuffer() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;   outBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;   &amp;lt;Out()&amp;gt; &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, ovelapped &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Function&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;font size="2"&gt;Note the structure goes &lt;font face="Courier New"&gt;ByRef&lt;/font&gt; – it’s a value type and we don’t want to send the whole structure to the function as it is expecting a pointer to the structure. Passing it &lt;font face="Courier New"&gt;ByRef&lt;/font&gt; tells the marshaller to send a pointer. The array, being a reference type, goes &lt;font face="Courier New"&gt;ByValue&lt;/font&gt;. &lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;font size="2"&gt;So the first time we call it we want to just get the &lt;font face="Courier New"&gt;Length&lt;/font&gt; field which is a &lt;font face="Courier New"&gt;WORD&lt;/font&gt; field, 2 bytes. Then we can call it again with a byte array that is this &lt;font face="Courier New"&gt;Length&lt;/font&gt; field + 2 as the value of the &lt;font face="Courier New"&gt;Length&lt;/font&gt; field is the size not including itself. The bytes are the wrong way round to read as a &lt;font face="Courier New"&gt;UShort&lt;/font&gt; with the &lt;font face="Courier New"&gt;BitConverter&lt;/font&gt;. I guess you could reverse the array. At this point my program gets the bytes and doesn’t do anything with them…&lt;/font&gt;&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.IO&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Runtime.InteropServices&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt; CdTextRetriever&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Const&lt;/span&gt; IOCTL_CDROM_READ_TOC_EX &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H24054&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; GetCdText(driveInfo &lt;span class="kwrd"&gt;As&lt;/span&gt; DriveInfo) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; cdText &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt; = &lt;span class="kwrd"&gt;Nothing&lt;/span&gt; &lt;span class="rem"&gt;' don't know what the return will look like yet.&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; devicePath &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="kwrd"&gt;String&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;\\.\{0}:&amp;quot;&lt;/span&gt;, driveInfo.Name(0))&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FILE_ATTRIBUTE_NORMAL &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H80&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GENERIC_READ &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H80000000UI&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GENERIC_WRITE &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = &amp;amp;H40000000&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FILE_SHARE_READ &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = 1&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FILE_SHARE_WRITE &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = 2&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; OPEN_EXISTING &lt;span class="kwrd"&gt;As&lt;/span&gt; UInteger = 3&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        Using hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle = NativeMethods.CreateFile(devicePath,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                GENERIC_READ &lt;span class="kwrd"&gt;Or&lt;/span&gt; GENERIC_WRITE,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                FILE_SHARE_READ &lt;span class="kwrd"&gt;Or&lt;/span&gt; FILE_SHARE_WRITE,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                IntPtr.Zero, OPEN_EXISTING,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;            &lt;span class="kwrd"&gt;If&lt;/span&gt; hDevice.IsInvalid &lt;span class="kwrd"&gt;OrElse&lt;/span&gt; hDevice.IsClosed &lt;span class="kwrd"&gt;Then&lt;/span&gt; &lt;span class="kwrd"&gt;Throw&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;            ReadCdText(hDevice)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; Using&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Return&lt;/span&gt; cdText&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; ReadCdText(hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; size &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = GetCdTextSize(hDevice)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytes(size - 1) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        ReadCdText(hDevice, bytes)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        Debugger.Break()&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="rem"&gt;' TODO: Decode the bytes!&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; GetCdTextSize(hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytes(1) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt; &lt;span class="rem"&gt;' 2 bytes to read the size of the buffer required&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        ReadCdText(hDevice, bytes)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Return&lt;/span&gt; (&lt;span class="kwrd"&gt;CType&lt;/span&gt;(bytes(0), &lt;span class="kwrd"&gt;Integer&lt;/span&gt;) &amp;lt;&amp;lt; 8) &lt;span class="kwrd"&gt;Or&lt;/span&gt; bytes(1) + 2&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; ReadCdText(hDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle, bytes() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; request &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; CDROM_READ_TOC_EX&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        request.SetFormatReservedMsf(ReadTocExFormat.CDROM_READ_TOC_EX_FORMAT_CDTEXT, &lt;span class="kwrd"&gt;False&lt;/span&gt;)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; returned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 0&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt; = DeviceIoControl(hDevice, IOCTL_CDROM_READ_TOC_EX, request,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;                                                 request.Size, bytes, bytes.Length,&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;                                                 returned, IntPtr.Zero)&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;        &lt;span class="kwrd"&gt;If&lt;/span&gt; result = &lt;span class="kwrd"&gt;False&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt; &lt;span class="kwrd"&gt;Throw&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;font face="Courier New"&gt;&amp;#160;&lt;/font&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Class&lt;/font&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/CD%20Text?cid=862dee3ec267cb5c&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;style type="text/css"&gt;

&lt;br /&gt;
&lt;br /&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-835516281995910293?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/835516281995910293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/09/reading-cd-text-with-vbnet-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/835516281995910293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/835516281995910293'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/09/reading-cd-text-with-vbnet-1.html' title='Reading CD-Text with VB.Net (1)'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-1813339344025450062</id><published>2011-02-12T12:25:00.001Z</published><updated>2011-02-12T12:25:55.618Z</updated><title type='text'>Sending the SCSI INQUIRY command with DeviceIOControl</title><content type='html'>&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Option&lt;/span&gt; Strict &lt;span class="kwrd"&gt;On&lt;/span&gt;
&lt;span class="kwrd"&gt;Option&lt;/span&gt; Explicit &lt;span class="kwrd"&gt;On&lt;/span&gt;

&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Runtime.InteropServices
&lt;span class="kwrd"&gt;Imports&lt;/span&gt; Microsoft.Win32.SafeHandles
&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Security
&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.ComponentModel
&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Text

&lt;span class="kwrd"&gt;Module&lt;/span&gt; Module1

    &amp;lt;SuppressUnmanagedCodeSecurity()&amp;gt; _
    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt; NativeMethods
        &amp;lt;DllImport(&lt;span class="str"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span class="kwrd"&gt;True&lt;/span&gt;)&amp;gt; _
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; CreateFile( _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; FileName &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;, _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; DesiredAccess &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; ShareMode &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; SecurityAttributes &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr, _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; CreationDisposition &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; FlagsAndAttributes &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; hTemplateFile &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr) &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;

        &amp;lt;DllImport(&lt;span class="str"&gt;&amp;quot;kernel32.dll&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span class="kwrd"&gt;True&lt;/span&gt;)&amp;gt; _
        &lt;span class="kwrd"&gt;Friend&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; DeviceIoControl( _
            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; deviceHandle &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle, _
            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; controlCode &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
            &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; inBuffer &lt;span class="kwrd"&gt;As&lt;/span&gt; ScsiPassThroughWithBuffers, _
            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; inBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
            &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; outBuffer &lt;span class="kwrd"&gt;As&lt;/span&gt; ScsiPassThroughWithBuffers, _
            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; outBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
            &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _
            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; overlapped1 &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt;
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt;

    &amp;lt;StructLayout(LayoutKind.Sequential, pack:=8)&amp;gt; _
    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt; ScsiPassThrough
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Length &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Short&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; ScsiStatus &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; PathId &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;          &lt;span class="rem"&gt;' port / bus&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; TargetId &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;        &lt;span class="rem"&gt;' controller&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Lun &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;             &lt;span class="rem"&gt;' Lun&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; CdbLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; SenseInfoLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataIn &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataTransferLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; TimeOutValue &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataBufferOffset &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; SenseInfoOffset &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;
        &amp;lt;MarshalAs(UnmanagedType.ByValArray, SizeConst:=16)&amp;gt; _
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Cdb() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; Init()
            &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Length = &lt;span class="kwrd"&gt;CShort&lt;/span&gt;(Marshal.SizeOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ScsiPassThrough)))
            CdbLength = 6                   &lt;span class="rem"&gt;' Size of our command structure&lt;/span&gt;
            SenseInfoLength = 32            &lt;span class="rem"&gt;' Size of our buffer that may be filled with error/status info&lt;/span&gt;
            DataIn = 1                      &lt;span class="rem"&gt;' SCSI_IOCTL_DATA_IN &lt;/span&gt;
            DataTransferLength = 128        &lt;span class="rem"&gt;' Size of our buffer that gets filled with informaion&lt;/span&gt;
            TimeOutValue = 10
            &lt;span class="rem"&gt;' TargetId, PathId and Lun are filled on return. Don't mean anything on the way out.&lt;/span&gt;
            DataBufferOffset = Marshal.OffsetOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ScsiPassThroughWithBuffers), &lt;span class="str"&gt;&amp;quot;Data&amp;quot;&lt;/span&gt;)
            SenseInfoOffset = Marshal.OffsetOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ScsiPassThroughWithBuffers), &lt;span class="str"&gt;&amp;quot;Sense&amp;quot;&lt;/span&gt;).ToInt32
            Cdb = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;(15) {}
            Cdb(0) = &amp;amp;H12
            Cdb(4) = 128
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt;

    &amp;lt;StructLayout(LayoutKind.Sequential, pack:=8)&amp;gt; _
    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt; ScsiPassThroughWithBuffers
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Spt &lt;span class="kwrd"&gt;As&lt;/span&gt; ScsiPassThrough
        &amp;lt;MarshalAs(UnmanagedType.ByValArray, SizeConst:=32)&amp;gt; _
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Sense() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &amp;lt;MarshalAs(UnmanagedType.ByValArray, SizeConst:=128)&amp;gt; _
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Data() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;
        &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; Init()
            Sense = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;(31) {}
            Data = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;(127) {}
            Spt = &lt;span class="kwrd"&gt;New&lt;/span&gt; ScsiPassThrough
            Spt.Init()
        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt;

    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Enum&lt;/span&gt; PeripheralDeviceType
        Sbc2 = 0 &lt;span class="rem"&gt;' direct access block device (disk)&lt;/span&gt;
        Ssc2 = 1 &lt;span class="rem"&gt;' sequential access block device (tape)&lt;/span&gt;
        Ssc = 2  &lt;span class="rem"&gt;' Printer&lt;/span&gt;
        Spc2 = 3 &lt;span class="rem"&gt;' Processor&lt;/span&gt;
        Sbc = 4  &lt;span class="rem"&gt;' Write once&lt;/span&gt;
        Mmc = 5  &lt;span class="rem"&gt;' CD/DVD etc&lt;/span&gt;
        SbcOptical = 7 &lt;span class="rem"&gt;' Optical memory device&lt;/span&gt;
        Smc2 = 8 &lt;span class="rem"&gt;' Medium changer&lt;/span&gt;
        scc2 = &amp;amp;HC &lt;span class="rem"&gt;' storage array controller (raid)&lt;/span&gt;
        Ses = &amp;amp;HD  &lt;span class="rem"&gt;' enclosure services device&lt;/span&gt;
        Rbc = &amp;amp;HE  &lt;span class="rem"&gt;' simple direct access device&lt;/span&gt;
        Ocrw = &amp;amp;HF &lt;span class="rem"&gt;' optical card reader&lt;/span&gt;
        Bcc = &amp;amp;H10 &lt;span class="rem"&gt;' bridge controller &lt;/span&gt;
        Osd = &amp;amp;H11 &lt;span class="rem"&gt;' object based storage device&lt;/span&gt;
        Adc = &amp;amp;H12 &lt;span class="rem"&gt;' automation / drive interface&lt;/span&gt;
        WellKnown = &amp;amp;H1E
        Unknown = &amp;amp;H1F
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Enum&lt;/span&gt;

    &lt;span class="kwrd"&gt;Sub&lt;/span&gt; Main()
        Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Enter a drive letter&amp;quot;&lt;/span&gt;)
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; letter &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Char&lt;/span&gt; = Console.ReadKey.KeyChar
        Console.WriteLine()
        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GenericRead &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H80000000
        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GenericWrite &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H40000000
        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FileShareRead &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 1
        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FileShareWrite &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 2
        &lt;span class="kwrd"&gt;Const&lt;/span&gt; OpenExisting &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 3
        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; drivePath &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="kwrd"&gt;String&lt;/span&gt;.Concat(&lt;span class="str"&gt;&amp;quot;\\.\&amp;quot;&lt;/span&gt; &amp;amp; letter &amp;amp; &lt;span class="str"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;)
        Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Trying path: &amp;quot;&lt;/span&gt; &amp;amp; drivePath)
        Using driveHandle &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle = NativeMethods.CreateFile( _
         drivePath, _
         GenericRead &lt;span class="kwrd"&gt;Or&lt;/span&gt; GenericWrite, _
         FileShareRead &lt;span class="kwrd"&gt;Or&lt;/span&gt; FileShareWrite, _
         IntPtr.Zero, _
         OpenExisting, _
         0, _
         IntPtr.Zero)
            &lt;span class="kwrd"&gt;If&lt;/span&gt; driveHandle.IsInvalid &lt;span class="kwrd"&gt;Then&lt;/span&gt;
                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;CreateFile ERROR: &amp;quot;&lt;/span&gt; &amp;amp; (&lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception).Message)
                Console.ReadKey()
                &lt;span class="kwrd"&gt;Return&lt;/span&gt;
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; sptwb &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; ScsiPassThroughWithBuffers
            sptwb.Init()

            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; inBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = Marshal.SizeOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ScsiPassThroughWithBuffers))
            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;
            &lt;span class="kwrd"&gt;Const&lt;/span&gt; IOCTL_SCSI_PASS_THROUGH &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H4D004
            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt; = NativeMethods.DeviceIoControl(driveHandle, IOCTL_SCSI_PASS_THROUGH, _
                sptwb, inBufferSize, sptwb, inBufferSize, bytesReturned, IntPtr.Zero)
            &lt;span class="kwrd"&gt;If&lt;/span&gt; result = &lt;span class="kwrd"&gt;False&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;DeviceIOControl ERROR: {0} {1}&amp;quot;&lt;/span&gt;, Marshal.GetLastWin32Error.ToString(&lt;span class="str"&gt;&amp;quot;x&amp;quot;&lt;/span&gt;), (&lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception).Message)
                Console.ReadKey()
                &lt;span class="kwrd"&gt;Return&lt;/span&gt;
            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytes() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt; = sptwb.Data
            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; peripheralQualifier &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = bytes(0) &amp;gt;&amp;gt; 5
            &lt;span class="kwrd"&gt;If&lt;/span&gt; peripheralQualifier = 1 &lt;span class="kwrd"&gt;Then&lt;/span&gt; Console.WriteLine(&lt;span class="str"&gt;&amp;quot;No peripheral is attached to the device&amp;quot;&lt;/span&gt;)
            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; peripheralDevice &lt;span class="kwrd"&gt;As&lt;/span&gt; PeripheralDeviceType = &lt;span class="kwrd"&gt;CType&lt;/span&gt;(bytes(0) &lt;span class="kwrd"&gt;And&lt;/span&gt; &amp;amp;H1F, PeripheralDeviceType)
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Peripheral device type: &amp;quot;&lt;/span&gt; &amp;amp; peripheralDevice.ToString)
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Version of the standard:&amp;quot;&lt;/span&gt; &amp;amp; sptwb.Data(2))
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Additional Length: &amp;quot;&lt;/span&gt; &amp;amp; sptwb.Data(4))
            DumpString(&lt;span class="str"&gt;&amp;quot;Vendor Id: &amp;quot;&lt;/span&gt;, sptwb.Data, 8, 8)
            DumpString(&lt;span class="str"&gt;&amp;quot;Product Id: &amp;quot;&lt;/span&gt;, sptwb.Data, 16, 16)
            DumpString(&lt;span class="str"&gt;&amp;quot;Product Revision Level: &amp;quot;&lt;/span&gt;, sptwb.Data, 32, 4)
            DumpString(&lt;span class="str"&gt;&amp;quot;Serial no: &amp;quot;&lt;/span&gt;, sptwb.Data, 36, 8)
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Press any key&amp;quot;&lt;/span&gt;)
            Console.ReadKey()
        &lt;span class="kwrd"&gt;End&lt;/span&gt; Using
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;

    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; DumpString(msg &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;, bytes() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;, offset &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, length &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;)
        Console.WriteLine(&lt;span class="kwrd"&gt;String&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;{0} :'{1}'&amp;quot;&lt;/span&gt;, msg, ASCIIEncoding.ASCII.GetString(bytes, offset, length)))
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;

&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Module&lt;/span&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;&lt;/pre&gt;

&lt;p&gt;The serial number is unreliable. The peripheral device type tells you which standard the device is using. I’m trying to work out how to get the serial no of my raided or USB drives. This command is getting back the serial number of my controller card for my raid array when I ask it for &lt;a href="file://\\.\C"&gt;\\.\C&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;Enter a drive letter
    &lt;br /&gt;c

    &lt;br /&gt;Trying path: \\.\c:

    &lt;br /&gt;Peripheral device type: Sbc2

    &lt;br /&gt;Version of the standard:4

    &lt;br /&gt;Additional Length: 43

    &lt;br /&gt;Vendor Id:&amp;#160; :'AMD&amp;#160;&amp;#160;&amp;#160;&amp;#160; '

    &lt;br /&gt;Product Id:&amp;#160; :'2+0 Stripe/RAID0'

    &lt;br /&gt;Product Revision Level:&amp;#160; :'1.10'

    &lt;br /&gt;Serial no:&amp;#160; :'98031612'

    &lt;br /&gt;Press any key

    &lt;br /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-1813339344025450062?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/1813339344025450062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/02/sending-scsi-inquiry-command-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/1813339344025450062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/1813339344025450062'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/02/sending-scsi-inquiry-command-with.html' title='Sending the SCSI INQUIRY command with DeviceIOControl'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-1404771386509125946</id><published>2011-02-12T01:06:00.002Z</published><updated>2011-02-12T01:53:17.871Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='hard disk'/><category scheme='http://www.blogger.com/atom/ns#' term='read serial number'/><title type='text'>Getting Hard disk drive info with DeviceIOControl</title><content type='html'>&lt;p&gt;It’s a pretty popular question on forums – how do I get the serial number for a hard disk drive. The serial number is then used for some form of homebrew security. The consensus amongst those who’ve been programming a while is that it is a waste of time and effort, unreliable and not particularly good at securing your programs…&lt;/p&gt;  &lt;p&gt;Anyway, as a fun challenge I had a go at getting the serial number from my laptops ATA-attached drive, by using DeviceIOControl to send the IDENTIFY DEVICE ATA command, as defined in the ATA spec. This won’t work on SCSI drives, or raid or …,… ,…, so it’s not reliable and isn’t the answer for those of you looking for a unique id (there isn’t a reliable unique id).&lt;/p&gt;  &lt;p&gt;&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: consolas, "Courier New", courier, monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Runtime.InteropServices&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; Microsoft.Win32.SafeHandles&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Security&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.ComponentModel&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Imports&lt;/span&gt; System.Text&lt;/pre&gt;

  &lt;pre&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;Module&lt;/span&gt; Module1&lt;/pre&gt;

  &lt;pre&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &amp;lt;SuppressUnmanagedCodeSecurity()&amp;gt; _&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt; NativeMethods&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &amp;lt;DllImport(&lt;span class="str"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span class="kwrd"&gt;True&lt;/span&gt;)&amp;gt; _&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; CreateFile( _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; FileName &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; DesiredAccess &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; ShareMode &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; SecurityAttributes &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; CreationDisposition &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; FlagsAndAttributes &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; hTemplateFile &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr) &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;        &amp;lt;DllImport(&lt;span class="str"&gt;&amp;quot;kernel32.dll&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span class="kwrd"&gt;True&lt;/span&gt;)&amp;gt; _&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Friend&lt;/span&gt; &lt;span class="kwrd"&gt;Shared&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt; DeviceIoControl( _&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; deviceHandle &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; controlCode &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; inBuffer &lt;span class="kwrd"&gt;As&lt;/span&gt; ATA_PASS_THROUGH_EX_WITH_BUFFERS, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; inBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; outBuffer &lt;span class="kwrd"&gt;As&lt;/span&gt; ATA_PASS_THROUGH_EX_WITH_BUFFERS, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; outBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;ByRef&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;ByVal&lt;/span&gt; overlapped1 &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr) &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Function&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt; ATA_PASS_THROUGH_EX&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Length &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Short&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; AtaFlags &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Short&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; PathId &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; TargetId &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Lun &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; ReservedAsUchar &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataTransferLength &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; TimeOutValue &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; ReservedAsUlong &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; DataBufferOffset &lt;span class="kwrd"&gt;As&lt;/span&gt; IntPtr&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &amp;lt;MarshalAs(UnmanagedType.ByValArray, sizeconst:=8)&amp;gt; _&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; PreviousTaskFile() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &amp;lt;MarshalAs(UnmanagedType.ByValArray, sizeconst:=8)&amp;gt; _&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; CurrentTaskFile() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre class="alt"&gt;    &amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt; ATA_PASS_THROUGH_EX_WITH_BUFFERS&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Apt &lt;span class="kwrd"&gt;As&lt;/span&gt; ATA_PASS_THROUGH_EX&lt;/pre&gt;

  &lt;pre&gt;        &amp;lt;MarshalAs(UnmanagedType.ByValArray, sizeconst:=512)&amp;gt; _&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Public&lt;/span&gt; Data() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Structure&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;Sub&lt;/span&gt; Main()&lt;/pre&gt;

  &lt;pre class="alt"&gt;        Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Enter a drive letter&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; letter &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Char&lt;/span&gt; = Console.ReadKey.KeyChar&lt;/pre&gt;

  &lt;pre class="alt"&gt;        Console.WriteLine()&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GenericRead &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H80000000&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; GenericWrite &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H40000000&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FileShareRead &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 1&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; FileShareWrite &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 2&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;Const&lt;/span&gt; OpenExisting &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = 3&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; drivePath &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="kwrd"&gt;String&lt;/span&gt;.Concat(&lt;span class="str"&gt;&amp;quot;\\.\&amp;quot;&lt;/span&gt; &amp;amp; letter &amp;amp; &lt;span class="str"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre&gt;        Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Trying path: &amp;quot;&lt;/span&gt; &amp;amp; drivePath)&lt;/pre&gt;

  &lt;pre class="alt"&gt;        Using driveHandle &lt;span class="kwrd"&gt;As&lt;/span&gt; SafeFileHandle = NativeMethods.CreateFile( _&lt;/pre&gt;

  &lt;pre&gt;         drivePath, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         GenericRead &lt;span class="kwrd"&gt;Or&lt;/span&gt; GenericWrite, _&lt;/pre&gt;

  &lt;pre&gt;         FileShareRead &lt;span class="kwrd"&gt;Or&lt;/span&gt; FileShareWrite, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         IntPtr.Zero, _&lt;/pre&gt;

  &lt;pre&gt;         OpenExisting, _&lt;/pre&gt;

  &lt;pre class="alt"&gt;         0, _&lt;/pre&gt;

  &lt;pre&gt;         IntPtr.Zero)&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;If&lt;/span&gt; driveHandle.IsInvalid &lt;span class="kwrd"&gt;Then&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;CreateFile ERROR: &amp;quot;&lt;/span&gt; &amp;amp; (&lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception).Message)&lt;/pre&gt;

  &lt;pre class="alt"&gt;                Console.ReadKey()&lt;/pre&gt;

  &lt;pre&gt;                &lt;span class="kwrd"&gt;Return&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; apex &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; ATA_PASS_THROUGH_EX&lt;/pre&gt;

  &lt;pre class="alt"&gt;            apex.Length = Marshal.SizeOf(apex)&lt;/pre&gt;

  &lt;pre&gt;            apex.AtaFlags = 2 &lt;span class="rem"&gt;' ATA_FLAGS_DATA_IN&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;            apex.DataTransferLength = 512 &lt;span class="rem"&gt;' The command returns a 512 byte package of info.&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;            apex.TimeOutValue = 10 &lt;span class="rem"&gt;' 10 second timeout.&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;            apex.DataBufferOffset = Marshal.OffsetOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ATA_PASS_THROUGH_EX_WITH_BUFFERS), &lt;span class="str"&gt;&amp;quot;Data&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre&gt;            apex.CurrentTaskFile = &lt;span class="kwrd"&gt;New&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;(7) {} &lt;span class="rem"&gt;' This contains the command we are requesting.&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;            apex.CurrentTaskFile(6) = &amp;amp;HEC        &lt;span class="rem"&gt;' &amp;lt;-- the command &amp;quot;IDENTIFY DEVICE&amp;quot;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; apexb &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; ATA_PASS_THROUGH_EX_WITH_BUFFERS&lt;/pre&gt;

  &lt;pre class="alt"&gt;            apexb.Apt = apex&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; inBufferSize &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = Marshal.SizeOf(&lt;span class="kwrd"&gt;GetType&lt;/span&gt;(ATA_PASS_THROUGH_EX_WITH_BUFFERS))&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; bytesReturned &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;            &lt;span class="kwrd"&gt;Const&lt;/span&gt; IOCTL_ATA_PASS_THROUGH &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = &amp;amp;H4D02C&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;Dim&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Boolean&lt;/span&gt; = NativeMethods.DeviceIoControl(driveHandle, IOCTL_ATA_PASS_THROUGH, _&lt;/pre&gt;

  &lt;pre&gt;                apexb, inBufferSize, apexb, inBufferSize, bytesReturned, IntPtr.Zero)&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;If&lt;/span&gt; result = &lt;span class="kwrd"&gt;False&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;                Console.WriteLine(&lt;span class="str"&gt;&amp;quot;DeviceIOControl ERROR: &amp;quot;&lt;/span&gt; &amp;amp; (&lt;span class="kwrd"&gt;New&lt;/span&gt; Win32Exception).Message)&lt;/pre&gt;

  &lt;pre class="alt"&gt;                Console.ReadKey()&lt;/pre&gt;

  &lt;pre&gt;                &lt;span class="kwrd"&gt;Return&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;            DumpString(&lt;span class="str"&gt;&amp;quot;S/N: &amp;quot;&lt;/span&gt;, apexb.Data, 20, 20)&lt;/pre&gt;

  &lt;pre class="alt"&gt;            DumpString(&lt;span class="str"&gt;&amp;quot;Firmware: &amp;quot;&lt;/span&gt;, apexb.Data, 46, 8)&lt;/pre&gt;

  &lt;pre&gt;            DumpString(&lt;span class="str"&gt;&amp;quot;Model: &amp;quot;&lt;/span&gt;, apexb.Data, 54, 40)&lt;/pre&gt;

  &lt;pre class="alt"&gt;            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Press any key&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre&gt;            Console.ReadKey()&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;End&lt;/span&gt; Using&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; DumpString(msg &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;, bytes() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Byte&lt;/span&gt;, offset &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;, length &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="rem"&gt;' The strings are slightly weird - endianness? If you use ASCII.GetBytes then each character &lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="rem"&gt;' pair is reversed.&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Dim&lt;/span&gt; sb &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; StringBuilder(msg &amp;amp; &lt;span class="str"&gt;&amp;quot; '&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

  &lt;pre&gt;        &lt;span class="kwrd"&gt;For&lt;/span&gt; i &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = offset &lt;span class="kwrd"&gt;To&lt;/span&gt; offset + length - 1 &lt;span class="kwrd"&gt;Step&lt;/span&gt; 2&lt;/pre&gt;

  &lt;pre class="alt"&gt;            sb.Append(Chr(bytes(i + 1)))&lt;/pre&gt;

  &lt;pre&gt;            sb.Append(Chr(bytes(i)))&lt;/pre&gt;

  &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;Next&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;        sb.Append(&lt;span class="str"&gt;&amp;quot;'&amp;quot;&lt;/span&gt;c)&lt;/pre&gt;

  &lt;pre class="alt"&gt;        Console.WriteLine(sb.ToString)&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;/pre&gt;

  &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Module&lt;/pre&gt;
&lt;/div&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Output on my laptop:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;Enter a drive letter
    &lt;br /&gt;c

    &lt;br /&gt;Trying path: \\.\c:

    &lt;br /&gt;S/N:&amp;#160; '&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 5TG077W9'

    &lt;br /&gt;Firmware:&amp;#160; 'DE14&amp;#160;&amp;#160;&amp;#160; '

    &lt;br /&gt;Model:&amp;#160; 'ST9160411ASG&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; '

    &lt;br /&gt;Press any key&lt;/font&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-1404771386509125946?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/1404771386509125946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/02/getting-hard-disk-drive-info-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/1404771386509125946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/1404771386509125946'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2011/02/getting-hard-disk-drive-info-with.html' title='Getting Hard disk drive info with DeviceIOControl'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-465977642918393845</id><published>2010-06-15T01:06:00.001+01:00</published><updated>2010-06-15T01:34:00.492+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='FilterBar'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>HDS_FILTERBAR</title><content type='html'>&lt;p&gt;There’s a &lt;a href="http://www.codeproject.com/KB/list/listviewfilter.aspx"&gt;ListViewFilter control&lt;/a&gt; in C# on codeproject from 2003. It displays a filter bar in the column headers by setting &lt;font face="Courier"&gt;HDS_FILTERBAR&lt;/font&gt;. &lt;/p&gt;  &lt;p&gt;If we start off with a ListView showing some random data in a few columns:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_qnUNSzxixDU/TBbD6jATR4I/AAAAAAAAAIs/8oeZA3lW9hA/s1600-h/Filterbar33.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Filterbar3" border="0" alt="Filterbar3" src="http://lh3.ggpht.com/_qnUNSzxixDU/TBbD7K1AqRI/AAAAAAAAAIw/BZZoNUoncnw/Filterbar3_thumb1.png?imgmax=800" width="310" height="48" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;And set the HDS_FILTERBAR style, then it will display the filter bar:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_qnUNSzxixDU/TBbD7bGZ5lI/AAAAAAAAAI0/OSIOWOFi96I/s1600-h/Filterbar27.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Filterbar2" border="0" alt="Filterbar2" src="http://lh5.ggpht.com/_qnUNSzxixDU/TBbD71rTwbI/AAAAAAAAAI4/xJGsKllMzI8/Filterbar2_thumb3.png?imgmax=800" width="309" height="48" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;But there’s a problem – it hasn’t resized the header controls – they need to be taller to fit the text in properly. The codeproject code makes the column resize using a hack. Here’s how it shows the filter bar:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: green"&gt;// set/reset the flag for the filterbar
&lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;( hdr_filter ) style |= HDS_FILTR;
&lt;span style="color: blue"&gt;else &lt;/span&gt;style ^= HDS_FILTR;
SetWindowLong( Handle, W32_GWL.GWL_STYLE, style );&lt;/pre&gt;

&lt;p&gt;And here’s the self-confessed kludge that gets it to resize:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// now we have to resize this control.  we do this by sending
// a set item message to column 0 to change it's size.  this
// is a kludge but the invalidate and others just don't work.
&lt;/span&gt;hdr_hditem.mask = W32_HDI.HDI_HEIGHT;
SendMessage( Handle, W32_HDM.HDM_GETITEMW, 0, &lt;span style="color: blue"&gt;ref &lt;/span&gt;hdr_hditem );
hdr_hditem.cxy += ( hdr_filter ) ? 1 : -1;
SendMessage( Handle, W32_HDM.HDM_SETITEMW, 0, &lt;span style="color: blue"&gt;ref &lt;/span&gt;hdr_hditem );&lt;/pre&gt;

&lt;p&gt;It’s sending a message to alter a property of the header – using HDI_HEIGHT. If we look at the windows header files to see how it’s defined:&lt;/p&gt;

&lt;pre&gt;#define HDI_WIDTH               0x0001
#define HDI_HEIGHT              HDI_WIDTH&lt;/pre&gt;

&lt;p&gt;It’s actually the same as the width. The kludge increases the width of the column header by 1 when the filter is shown, and decreases it when the filter is not shown. Altering the width must be enough to make windows resize the control.&lt;/p&gt;

&lt;p&gt;Searching for alternate solutions I found one that mentions using MoveWindow to resize the header control, so I tried that. Unfortunately when you resize the header it then overlaps the parent listview, hiding one or two of the ListViewItems by overlapping them.&lt;/p&gt;

&lt;p&gt;The info needed to do it properly is in the “&lt;a href="http://msdn.microsoft.com/en-us/library/bb775238(v=VS.85).aspx"&gt;Header Controls&lt;/a&gt;” topic in the MSDN library, in the “header control size and position” paragraph. We have to send the HDM_LAYOUT message to the control, specifying the bounds of the parent. On return we get a WINDOWPOS structure which tells us the best bounds for the header so that it will sit in the bounds of the parent. All we then have to do is to resize the header control using SetWindowPos, and alter the bounds of the parent control so that its top lies below the header and its height isn’t too big.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;HDLAYOUT &lt;/span&gt;layout = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HDLAYOUT&lt;/span&gt;();
&lt;span style="color: #2b91af"&gt;RECT &lt;/span&gt;rect = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RECT&lt;/span&gt;();
rect.Right = parent.ClientSize.Width;
rect.Bottom = parent.ClientSize.Height;
layout.prc = &lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.AllocHGlobal(&lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.SizeOf(rect));
&lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.StructureToPtr(rect, layout.prc, &lt;span style="color: blue"&gt;true&lt;/span&gt;);
layout.pwpos = &lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.AllocHGlobal(&lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.SizeOf(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;WINDOWPOS&lt;/span&gt;)));
lresult = &lt;span style="color: #2b91af"&gt;NativeMethods&lt;/span&gt;.SendMessage(Handle, HDM_LAYOUT, &lt;span style="color: #2b91af"&gt;IntPtr&lt;/span&gt;.Zero, &lt;span style="color: blue"&gt;ref &lt;/span&gt;layout);
&lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.FreeHGlobal(layout.prc);
&lt;span style="color: #2b91af"&gt;WINDOWPOS &lt;/span&gt;pos = (&lt;span style="color: #2b91af"&gt;WINDOWPOS&lt;/span&gt;)&lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.PtrToStructure(layout.pwpos, &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;WINDOWPOS&lt;/span&gt;));
&lt;span style="color: #2b91af"&gt;Marshal&lt;/span&gt;.FreeHGlobal(layout.pwpos);
&lt;span style="color: blue"&gt;bool &lt;/span&gt;res = &lt;span style="color: #2b91af"&gt;NativeMethods&lt;/span&gt;.SetWindowPos(Handle, &lt;span style="color: #2b91af"&gt;IntPtr&lt;/span&gt;.Zero, pos.X, pos.Y, pos.Width, pos.Height, 
    &lt;span style="color: #2b91af"&gt;SetWindowPosFlags&lt;/span&gt;.NoMove | &lt;span style="color: #2b91af"&gt;SetWindowPosFlags&lt;/span&gt;.NoZOrder | &lt;span style="color: #2b91af"&gt;SetWindowPosFlags&lt;/span&gt;.FrameChanged);
res = &lt;span style="color: #2b91af"&gt;NativeMethods&lt;/span&gt;.SetWindowPos(parent.Handle, &lt;span style="color: #2b91af"&gt;IntPtr&lt;/span&gt;.Zero, 0, pos.Height, parent.Width, parent.Height - pos.Height, 
    &lt;span style="color: #2b91af"&gt;SetWindowPosFlags&lt;/span&gt;.NoMove | &lt;span style="color: #2b91af"&gt;SetWindowPosFlags&lt;/span&gt;.NoZOrder | &lt;span style="color: #2b91af"&gt;SetWindowPosFlags&lt;/span&gt;.FrameChanged);
ClearAllFilters();  &lt;/pre&gt;

&lt;p&gt;Now the filterbar is shown with the correct size, it doesn’t overlap the top of the parent listview, and it resizes correctly when the filter bar is removed.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_qnUNSzxixDU/TBbD8F_UoXI/AAAAAAAAAI8/Lpm9JEQYuC4/s1600-h/Filterbar1%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Filterbar1" border="0" alt="Filterbar1" src="http://lh4.ggpht.com/_qnUNSzxixDU/TBbD8omnAeI/AAAAAAAAAJA/L0Z5mcXEjgA/Filterbar1_thumb%5B1%5D.png?imgmax=800" width="311" height="68" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-465977642918393845?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/465977642918393845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2010/06/hdsfilterbar.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/465977642918393845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/465977642918393845'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2010/06/hdsfilterbar.html' title='HDS_FILTERBAR'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_qnUNSzxixDU/TBbD7K1AqRI/AAAAAAAAAIw/BZZoNUoncnw/s72-c/Filterbar3_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-5042462172341885318</id><published>2009-10-09T23:49:00.001+01:00</published><updated>2009-10-09T23:49:39.702+01:00</updated><title type='text'>Cloudy Jelly</title><content type='html'>&lt;p&gt;The usual advice is to stick the boiled up fruit in a bag and leave to drip. Don’t squeeze the bag, or it will be cloudy. Well, my investigations have found that it’s not really the lack of bag squeezing the helps to get clear jelly. It’s the leaving it overnight. You then take the liquor off any sediment that’s fallen to the bottom of the bucket. &lt;/p&gt;  &lt;p&gt;I just did my annual crab apple jelly. 8lbs of crab apples. For one batch I let it drip into a bucket, didn’t squeeze and made the jam immediately. The result was pretty cloudy. For the other, I squeezed that first bag and strained through a bit more, which also got a really good squeeze. I then left it in the fridge for a day, because I was tired of making jelly. The bits all settled to the bottom, and the result is perfectly clear. So – you can squeeze the bag, so long as you leave it to settle. &lt;/p&gt;  &lt;p&gt;Oh, and crab apple and haw jelly isn’t great. The haws smell like sardines whilst cooking, and make a very sharp jelly. Maybe I stuck too many in. Still, it’s not ruined, just not really worth the bother when the straight stuff tastes so good.&lt;/p&gt;  &lt;p&gt;There, a dumb entry to get this thing going again. I’ve been busy, and not programmed much.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-5042462172341885318?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/5042462172341885318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/10/cloudy-jelly.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/5042462172341885318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/5042462172341885318'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/10/cloudy-jelly.html' title='Cloudy Jelly'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-2586254633379616510</id><published>2009-02-12T06:44:00.003Z</published><updated>2009-02-12T12:22:13.525Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='shuffle cards'/><category scheme='http://www.blogger.com/atom/ns#' term='guid shuffle'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='yates fisher'/><category scheme='http://www.blogger.com/atom/ns#' term='RNGCryptoServiceProvider'/><category scheme='http://www.blogger.com/atom/ns#' term='shuffle'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Shuffle things in .Net</title><content type='html'>&lt;p&gt;Shuffling is complicated. There are two nice pages on CodingHorror:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.codinghorror.com/blog/archives/001008.html"&gt;http://www.codinghorror.com/blog/archives/001008.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.codinghorror.com/blog/archives/001015.html" href="http://www.codinghorror.com/blog/archives/001015.html"&gt;http://www.codinghorror.com/blog/archives/001015.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The second link shows a chart of the counts of the different possible draws from a&amp;#160; card pack when you do it a few hundred thousand times. This detects the bias of an algorithm.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h5&gt;&lt;u&gt;How not to shuffle # 1&lt;/u&gt;&lt;/h5&gt;  &lt;p&gt;Here we go for the approach of picking a number at random, seeing if we have selected it already, adding it to the selected numbers if we haven't, and picking another if we have.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color: blue"&gt;Private Shared &lt;/span&gt;rand &lt;span style="color: blue"&gt;As New &lt;/span&gt;Random
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;dic &lt;span style="color: blue"&gt;As New &lt;/span&gt;Dictionary(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;, &lt;span style="color: blue"&gt;Integer&lt;/span&gt;)
    &lt;span style="color: blue"&gt;Dim &lt;/span&gt;tb &lt;span style="color: blue"&gt;As New &lt;/span&gt;TextBox &lt;span style="color: blue"&gt;With &lt;/span&gt;{.Dock = DockStyle.Fill, .Multiline = &lt;span style="color: blue"&gt;True&lt;/span&gt;}

    &lt;span style="color: blue"&gt;Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.Load
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sw &lt;span style="color: blue"&gt;As &lt;/span&gt;Stopwatch = Stopwatch.StartNew
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;shuffled(9999999)() &lt;span style="color: blue"&gt;As Integer
        For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;shuffled.GetUpperBound(0)
            shuffled(i) = GetShuffledDeck(4)
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;sw.Stop()
        &lt;span style="color: blue"&gt;For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;shuffled.GetUpperBound(0)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;key &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= shuffled(i)(0) + shuffled(i)(1) * 10 + shuffled(i)(2) * 100 + shuffled(i)(3) * 1000
            &lt;span style="color: blue"&gt;If &lt;/span&gt;dic.ContainsKey(key) &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;dic(key) = dic(key) + 1
            &lt;span style="color: blue"&gt;Else
                &lt;/span&gt;dic.Add(key, 1)
            &lt;span style="color: blue"&gt;End If
        Next
        Dim &lt;/span&gt;sb &lt;span style="color: blue"&gt;As New &lt;/span&gt;System.Text.StringBuilder
        sb.AppendLine(sw.ElapsedMilliseconds.ToString &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;ms.&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;For Each &lt;/span&gt;kvp &lt;span style="color: blue"&gt;As &lt;/span&gt;KeyValuePair(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;, &lt;span style="color: blue"&gt;Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;In &lt;/span&gt;dic
            sb.Append(kvp.ToString &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot; &amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;tb.Text = sb.ToString
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Controls.Add(tb)
    &lt;span style="color: blue"&gt;End Sub

    Function &lt;/span&gt;GetShuffledDeck(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;numCards &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;()
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;cards(numCards - 1) &lt;span style="color: blue"&gt;As Integer
        For &lt;/span&gt;index &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;cards.Length - 1 &lt;span style="color: green"&gt;' BTW (cards.Length - 1) will be optimized.
            &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;card &lt;span style="color: blue"&gt;As Integer
            Do
                &lt;/span&gt;&lt;span style="color: green"&gt;' We don't want two identical cards.
                &lt;/span&gt;card = rand.Next(1, numCards + 1)
            &lt;span style="color: blue"&gt;Loop While &lt;/span&gt;cards.Contains(card)
            cards(index) = card
        &lt;span style="color: blue"&gt;Next
        Return &lt;/span&gt;cards
    &lt;span style="color: blue"&gt;End Function

End Class&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/pre&gt;

&lt;p&gt;This is slow, (O(n^2). My results:&lt;/p&gt;

&lt;p&gt;29400ms.
  &lt;br /&gt;[4312, 416350] [3241, 417266] [4231, 417358] [3214, 416887] 

  &lt;br /&gt;[2134, 416303] [3421, 416548] [4321, 415916] [1324, 415585] 

  &lt;br /&gt;[1234, 417627] [3412, 416762] [4132, 415979] [1432, 416423] 

  &lt;br /&gt;[2143, 416603] [3142, 416542] [1423, 417515] [2314, 416934] 

  &lt;br /&gt;[2341, 417028] [1243, 416388] [2431, 415852] [1342, 417022] 

  &lt;br /&gt;[2413, 416309] [4213, 418019] [3124, 417387] [4123, 415397] &lt;/p&gt;

&lt;p&gt;They don't &lt;em&gt;look&lt;/em&gt; biased. &lt;a href="http://kevindaly.spaces.live.com/blog/cns!EDA3C1275909727A!416.entry"&gt;Standard deviation from the mean&lt;/a&gt; is 653.

  &lt;br /&gt;Certainly not as much as those on the codinghorror site. Let's redo that one...&lt;/p&gt;

&lt;h5&gt;&lt;u&gt;How not to shuffle # 2&lt;/u&gt;&lt;/h5&gt;

&lt;p&gt;Using the same code with a different shuffle function:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Function &lt;/span&gt;GetShuffledDeck(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;numCards &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;()
    &lt;span style="color: blue"&gt;Dim &lt;/span&gt;cards(numCards - 1) &lt;span style="color: blue"&gt;As Integer
    For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;cards.Length - 1
        cards(i) = i + 1
    &lt;span style="color: blue"&gt;Next
    For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;cards.Length - 1
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;n &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= rand.Next(cards.Length)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;temp &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= cards(i)
        cards(i) = cards(n)
        cards(n) = temp
    &lt;span style="color: blue"&gt;Next
    Return &lt;/span&gt;cards
&lt;span style="color: blue"&gt;End Function&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;3618ms.
  &lt;br /&gt;[1234, 390450] [1243, 390582] [1324, 312355] [1342, 429289] 

  &lt;br /&gt;[1423, 429646] [1432, 547601] [2134, 390203] [2143, 429178] 

  &lt;br /&gt;[2314, 351753] [2341, 351524] [2413, 429756] [2431, 545840] 

  &lt;br /&gt;[3124, 350694] [3142, 430600] [3214, 312704] [3241, 430164] 

  &lt;br /&gt;[3412, 586053] [3421, 391312] [4123, 351567] [4132, 546387] 

  &lt;br /&gt;[4213, 429804] [4231, 391291] [4312, 390192] [4321, 391055] &lt;/p&gt;

&lt;p&gt;There's bias there. s.d. = 71880!!!&lt;/p&gt;

&lt;h5&gt;&lt;u&gt;How to shuffle # 1 - Knuth shuffle / Fisher-Yates&lt;/u&gt;&lt;/h5&gt;

&lt;p&gt;Here I initialize the Random object with a cryptographically strong seed. Bit better than the default? The default uses the Environment.TickCount, which could be used to work out likely starting seed values.... Not likely to actually happen....
  &lt;br /&gt;The main difference is the algorithm though, which no longer introduces bias.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Security.Cryptography

&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color: blue"&gt;Private Shared &lt;/span&gt;rand &lt;span style="color: blue"&gt;As &lt;/span&gt;Random
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;dic &lt;span style="color: blue"&gt;As New &lt;/span&gt;Dictionary(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;, &lt;span style="color: blue"&gt;Integer&lt;/span&gt;)
    &lt;span style="color: blue"&gt;Dim &lt;/span&gt;tb &lt;span style="color: blue"&gt;As New &lt;/span&gt;TextBox &lt;span style="color: blue"&gt;With &lt;/span&gt;{.Dock = DockStyle.Fill, .Multiline = &lt;span style="color: blue"&gt;True&lt;/span&gt;}

    &lt;span style="color: blue"&gt;Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.Load
        &lt;span style="color: green"&gt;' get a random seed rather than using the default Random constructor, which
        ' just uses the Environment.TickCount
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;rng &lt;span style="color: blue"&gt;As New &lt;/span&gt;RNGCryptoServiceProvider
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;seedBytes(3) &lt;span style="color: blue"&gt;As Byte
        &lt;/span&gt;rng.GetBytes(seedBytes)
        rand = &lt;span style="color: blue"&gt;New &lt;/span&gt;Random(BitConverter.ToInt32(seedBytes, 0))
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sw &lt;span style="color: blue"&gt;As &lt;/span&gt;Stopwatch = Stopwatch.StartNew
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;shuffled(9999999)() &lt;span style="color: blue"&gt;As Integer
        For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;shuffled.GetUpperBound(0)
            shuffled(i) = GetShuffledDeck(4)
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;sw.Stop()
        &lt;span style="color: blue"&gt;For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;shuffled.GetUpperBound(0)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;key &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= shuffled(i)(0) + shuffled(i)(1) * 10 + shuffled(i)(2) * 100 + shuffled(i)(3) * 1000
            &lt;span style="color: blue"&gt;If &lt;/span&gt;dic.ContainsKey(key) &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;dic(key) = dic(key) + 1
            &lt;span style="color: blue"&gt;Else
                &lt;/span&gt;dic.Add(key, 1)
            &lt;span style="color: blue"&gt;End If
        Next
        Dim &lt;/span&gt;sb &lt;span style="color: blue"&gt;As New &lt;/span&gt;System.Text.StringBuilder
        sb.AppendLine(sw.ElapsedMilliseconds.ToString &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;ms.&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;keys &lt;span style="color: blue"&gt;As New &lt;/span&gt;List(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;)(dic.Keys)
        keys.Sort()
        &lt;span style="color: blue"&gt;For Each &lt;/span&gt;key &lt;span style="color: blue"&gt;As Integer In &lt;/span&gt;keys
            sb.AppendFormat(&lt;span style="color: #a31515"&gt;&amp;quot;[{0}, {1}] &amp;quot;&lt;/span&gt;, key, dic(key))
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;tb.Text = sb.ToString
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Controls.Add(tb)
    &lt;span style="color: blue"&gt;End Sub

    Function &lt;/span&gt;GetShuffledDeck(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;numCards &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;()
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;cards(numCards - 1) &lt;span style="color: blue"&gt;As Integer
        For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;cards.Length - 1
            cards(i) = i + 1
        &lt;span style="color: blue"&gt;Next
        For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= cards.Length - 1 &lt;span style="color: blue"&gt;To &lt;/span&gt;0 Step -1
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;n &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= rand.Next(i + 1)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;temp &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= cards(i)
            cards(i) = cards(n)
            cards(n) = temp
        &lt;span style="color: blue"&gt;Next
        Return &lt;/span&gt;cards
    &lt;span style="color: blue"&gt;End Function

End Class&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;3564ms.
  &lt;br /&gt;[1234, 417700] [1243, 416060] [1324, 416157] [1342, 416886] 

  &lt;br /&gt;[1423, 416348] [1432, 416439] [2134, 416352] [2143, 417366]

  &lt;br /&gt; [2314, 416459] [2341, 417555] [2413, 417086] [2431, 416996]

  &lt;br /&gt; [3124, 415841] [3142, 417191] [3214, 416693] [3241, 416009]

  &lt;br /&gt; [3412, 416599] [3421, 416026] [4123, 416222] [4132, 416616]

  &lt;br /&gt; [4213, 416332] [4231, 417548] [4312, 417035] [4321, 416484] &lt;/p&gt;

&lt;p&gt;Bias free. s.d. = 526&lt;/p&gt;

&lt;h5&gt;&lt;u&gt;How to shuffle # 2 - Sorting with a GUID&lt;/u&gt;&lt;/h5&gt;

&lt;p&gt;Again we can just alter the function:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Function &lt;/span&gt;GetShuffledDeck(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;numCards &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;()
    &lt;span style="color: blue"&gt;Dim &lt;/span&gt;cards = Enumerable.Range(1, numCards)
    cards = cards.OrderBy(&lt;span style="color: blue"&gt;Function&lt;/span&gt;(x) Guid.NewGuid)
    &lt;span style="color: blue"&gt;Return &lt;/span&gt;cards.ToArray
&lt;span style="color: blue"&gt;End Function&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;20129ms.
  &lt;br /&gt;[1234, 417906] [1243, 416614] [1324, 416582] [1342, 416302] 

  &lt;br /&gt;[1423, 416529] [1432, 416558] [2134, 416695] [2143, 416061] 

  &lt;br /&gt;[2314, 417049] [2341, 415870] [2413, 416690] [2431, 417183] 

  &lt;br /&gt;[3124, 415954] [3142, 416735] [3214, 415955] [3241, 415697] 

  &lt;br /&gt;[3412, 417235] [3421, 416427] [4123, 417626] [4132, 417726] 

  &lt;br /&gt;[4213, 417010] [4231, 415691] [4312, 418397] [4321, 415508] &lt;/p&gt;

&lt;p&gt;Slow again. s.d. = 733&lt;/p&gt;

&lt;h5&gt;&lt;u&gt;How to shuffle # 2 - Sorting with a load of random Doubles&lt;/u&gt;&lt;/h5&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Option Infer On

Imports &lt;/span&gt;System.Security.Cryptography

&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color: blue"&gt;Private Shared &lt;/span&gt;rand &lt;span style="color: blue"&gt;As &lt;/span&gt;Random
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;dic &lt;span style="color: blue"&gt;As New &lt;/span&gt;Dictionary(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;, &lt;span style="color: blue"&gt;Integer&lt;/span&gt;)
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;tb &lt;span style="color: blue"&gt;As New &lt;/span&gt;TextBox &lt;span style="color: blue"&gt;With &lt;/span&gt;{.Dock = DockStyle.Fill, .Multiline = &lt;span style="color: blue"&gt;True&lt;/span&gt;}
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;rng &lt;span style="color: blue"&gt;As New &lt;/span&gt;RNGCryptoServiceProvider

    &lt;span style="color: blue"&gt;Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.Load
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sw &lt;span style="color: blue"&gt;As &lt;/span&gt;Stopwatch = Stopwatch.StartNew
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;shuffled(9999999)() &lt;span style="color: blue"&gt;As Integer
        For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;shuffled.GetUpperBound(0)
            shuffled(i) = GetShuffledDeck(4)
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;sw.Stop()
        &lt;span style="color: blue"&gt;For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;shuffled.GetUpperBound(0)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;key &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= shuffled(i)(0) + shuffled(i)(1) * 10 + shuffled(i)(2) * 100 + shuffled(i)(3) * 1000
            &lt;span style="color: blue"&gt;If &lt;/span&gt;dic.ContainsKey(key) &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;dic(key) = dic(key) + 1
            &lt;span style="color: blue"&gt;Else
                &lt;/span&gt;dic.Add(key, 1)
            &lt;span style="color: blue"&gt;End If
        Next
        Dim &lt;/span&gt;sb &lt;span style="color: blue"&gt;As New &lt;/span&gt;System.Text.StringBuilder
        sb.AppendLine(sw.ElapsedMilliseconds.ToString &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;ms.&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;keys &lt;span style="color: blue"&gt;As New &lt;/span&gt;List(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;)(dic.Keys)
        keys.Sort()
        &lt;span style="color: blue"&gt;For Each &lt;/span&gt;key &lt;span style="color: blue"&gt;As Integer In &lt;/span&gt;keys
            sb.AppendFormat(&lt;span style="color: #a31515"&gt;&amp;quot;[{0}, {1}] &amp;quot;&lt;/span&gt;, key, dic(key))
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;tb.Text = sb.ToString
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Controls.Add(tb)
    &lt;span style="color: blue"&gt;End Sub

    Function &lt;/span&gt;GetShuffledDeck(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;numCards &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;()
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;cards = Enumerable.Range(1, numCards)
        cards = cards.OrderBy(&lt;span style="color: blue"&gt;Function&lt;/span&gt;(x) RandomDouble(x))
        &lt;span style="color: blue"&gt;Return &lt;/span&gt;cards.ToArray
    &lt;span style="color: blue"&gt;End Function

    &lt;/span&gt;&lt;span style="color: green"&gt;' This returns a function that creates a random double. The Integer bit is just ignored. 
    &lt;/span&gt;&lt;span style="color: blue"&gt;Private Function &lt;/span&gt;RandomDouble() &lt;span style="color: blue"&gt;As &lt;/span&gt;Func(&lt;span style="color: blue"&gt;Of Integer&lt;/span&gt;, &lt;span style="color: blue"&gt;Double&lt;/span&gt;)
        &lt;span style="color: green"&gt;' 8 bytes for the double. 
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;bytes(7) &lt;span style="color: blue"&gt;As Byte
        &lt;/span&gt;&lt;span style="color: green"&gt;' Get cryptographically strong random bytes into the array.       
        &lt;/span&gt;rng.GetBytes(bytes)
        &lt;span style="color: green"&gt;' The function uses the bytes to create a double. x is ignored. 
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;getDouble = &lt;span style="color: blue"&gt;Function&lt;/span&gt;(x &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) BitConverter.ToDouble(bytes, 0)
        &lt;span style="color: blue"&gt;Return &lt;/span&gt;getDouble
    &lt;span style="color: blue"&gt;End Function

End Class
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;137380ms.
  &lt;br /&gt;[1234, 416945] [1243, 416314] [1324, 416742] 

  &lt;br /&gt;[1342, 416652] [1423, 417382] [1432, 416208] 

  &lt;br /&gt;[2134, 417577] [2143, 416464] [2314, 415925] 

  &lt;br /&gt;[2341, 416543] [2413, 416615] [2431, 418076] 

  &lt;br /&gt;[3124, 416493] [3142, 415963] [3214, 417219] 

  &lt;br /&gt;[3241, 415923] [3412, 416774] [3421, 417394] 

  &lt;br /&gt;[4123, 416466] [4132, 416706] [4213, 415900] 

  &lt;br /&gt;[4231, 416736] [4312, 415534] [4321, 417449] &lt;/p&gt;

&lt;p&gt;Slooooooooooooooooooooooooooooooow. - The cryptographic random numbers are very expensive!&lt;/p&gt;

&lt;p&gt;s.d. = 605&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;So there you go. But, it's interesting to note &lt;a href="http://www.xtremevbtalk.com/showthread.php?t=292591&amp;amp;highlight=random+shuffle"&gt;atma's comments&lt;/a&gt; about experienced card players - they don't like their cards shuffled by the computer, they prefer human shuffled cards and can tell the difference.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-2586254633379616510?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/2586254633379616510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/02/shuffle-things-in-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2586254633379616510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2586254633379616510'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/02/shuffle-things-in-net.html' title='Shuffle things in .Net'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-2674884759542715666</id><published>2009-02-09T23:23:00.003Z</published><updated>2009-02-10T10:35:26.699Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Rotated Rectangle Collision'/><category scheme='http://www.blogger.com/atom/ns#' term='Rotated Rectangle Overlap'/><title type='text'>Rotated Rectangle Collision – VB.Net</title><content type='html'>&lt;p&gt;I translated &lt;a href="http://www.ragestorm.net/tutorial?id=22"&gt;some C code by Oren Becker&lt;/a&gt; that determines if two rotated RectangleFs are overlapping. The rectangles are defined by their centre, size and angle of rotation. In the original code the size was actually (Width / 2, Height / 2) which was confusing.&lt;/p&gt; &lt;iframe style="border-right: #dde5e9 1px solid; padding-right: 0px; border-top: #dde5e9 1px solid; padding-left: 0px; padding-bottom: 0px; margin: 3px; border-left: #dde5e9 1px solid; width: 240px; padding-top: 0px; border-bottom: #dde5e9 1px solid; height: 66px; background-color: #ffffff" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/RotatedRectangles.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;h5&gt;&lt;u&gt;RotatedRectangleF.vb&lt;/u&gt;&lt;/h5&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Public Structure &lt;/span&gt;RotatedRectangleF

    &lt;span style="color: blue"&gt;Public Const &lt;/span&gt;Pi &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= &lt;span style="color: blue"&gt;CType&lt;/span&gt;(Math.PI, &lt;span style="color: blue"&gt;Single&lt;/span&gt;)

    &lt;span style="color: blue"&gt;Private &lt;/span&gt;m_centre &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF
    &lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Gets or sets the coordinates of the centre of this RotatedRectangleF structure.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;    
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' A System.Drawing.PointF that represents the centre of this RotatedRectangleF structure.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;Public Property &lt;/span&gt;Centre() &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF
        &lt;span style="color: blue"&gt;Get
            Return &lt;/span&gt;m_centre
        &lt;span style="color: blue"&gt;End Get
        Set&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;value &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF)
            m_centre = value
        &lt;span style="color: blue"&gt;End Set
    End Property

    Private &lt;/span&gt;m_size &lt;span style="color: blue"&gt;As &lt;/span&gt;SizeF
    &lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Gets or sets the size of this RotatedRectangleF.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;    
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' A System.Drawing.SizeF that represents the width and height of this RotatedRectangleF structure.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;Public Property &lt;/span&gt;Size() &lt;span style="color: blue"&gt;As &lt;/span&gt;SizeF
        &lt;span style="color: blue"&gt;Get
            Return &lt;/span&gt;m_size
        &lt;span style="color: blue"&gt;End Get
        Set&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;value &lt;span style="color: blue"&gt;As &lt;/span&gt;SizeF)
            m_size = value
        &lt;span style="color: blue"&gt;End Set
    End Property

    Private &lt;/span&gt;m_angle &lt;span style="color: blue"&gt;As Single
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Gets or sets the angle in degrees measured clockwise from the x-axis that this RotatedRectangleF structure is rotated.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' A Single representing the angle in degrees measured clockwise from the x-axis that this RotatedRectangleF structure is rotated.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;Public Property &lt;/span&gt;Angle() &lt;span style="color: blue"&gt;As Single
        Get
            Return &lt;/span&gt;m_angle
        &lt;span style="color: blue"&gt;End Get
        Set&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;value &lt;span style="color: blue"&gt;As Single&lt;/span&gt;)
            m_angle = value
        &lt;span style="color: blue"&gt;End Set
    End Property

    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Initializes a new instance of the RotatedRectangleF stucture with the specified centre, size and angle.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param name=&amp;quot;centre&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The centre of the RotatedRectangleF instance.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param name=&amp;quot;size&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The size of the RotatedRectangleF instance.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param name=&amp;quot;angle&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The angle in degrees clockwise from the x-axis that this RotatedRectangleF is rotated.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;remarks&amp;gt;&amp;lt;/remarks&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;Sub New&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;centre &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;size &lt;span style="color: blue"&gt;As &lt;/span&gt;SizeF, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;angle &lt;span style="color: blue"&gt;As Single&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Centre = centre
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Size = size
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Angle = angle
    &lt;span style="color: blue"&gt;End Sub

    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Render this RotatedRectangle using the provided System.Drawing.Graphics object.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param name=&amp;quot;g&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The System.Drawing.Graphics object with which to draw the RotatedRectangleF.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;    
    &lt;/span&gt;&lt;span style="color: blue"&gt;Public Sub &lt;/span&gt;Render(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;g &lt;span style="color: blue"&gt;As &lt;/span&gt;Graphics, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;p &lt;span style="color: blue"&gt;As &lt;/span&gt;Pen)
        g.TranslateTransform(&lt;span style="color: blue"&gt;Me&lt;/span&gt;.Centre.X, &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Centre.Y)
        g.RotateTransform(&lt;span style="color: blue"&gt;Me&lt;/span&gt;.Angle)
        g.DrawRectangle(p, -&lt;span style="color: blue"&gt;Me&lt;/span&gt;.Size.Width / 2.0F, -&lt;span style="color: blue"&gt;Me&lt;/span&gt;.Size.Height / 2.0F, &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Size.Width, &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Size.Height)
        g.ResetTransform()
    &lt;span style="color: blue"&gt;End Sub

    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Determines whether two RotatedRectangleF structures intersect.
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param name=&amp;quot;rr1&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The first RotatedRectangleF structure.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param name=&amp;quot;rr2&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;The second RotatedRectangleF structure.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: green"&gt;True if the two RotatedRectangleF structures intersect, False otherwise.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;remarks&amp;gt;
    &lt;/span&gt;&lt;span style="color: green"&gt;''' Conversion of code by Oren Becker, 2001
    ''' http://www.ragestorm.net/tutorial?id=22
    ''' &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/remarks&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;Intersect(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;rr1 &lt;span style="color: blue"&gt;As &lt;/span&gt;RotatedRectangleF, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;rr2 &lt;span style="color: blue"&gt;As &lt;/span&gt;RotatedRectangleF) &lt;span style="color: blue"&gt;As Boolean

        &lt;/span&gt;&lt;span style="color: green"&gt;' Change our structure to match the one in the other code.
        ' Angle in radians, size is (width / 2, height / 2)
        &lt;/span&gt;rr1 = &lt;span style="color: blue"&gt;New &lt;/span&gt;RotatedRectangleF(rr1.Centre, &lt;span style="color: blue"&gt;New &lt;/span&gt;SizeF(rr1.Size.Width / 2, rr1.Size.Height / 2), DegreesToRadians(rr1.Angle))
        rr2 = &lt;span style="color: blue"&gt;New &lt;/span&gt;RotatedRectangleF(rr2.Centre, &lt;span style="color: blue"&gt;New &lt;/span&gt;SizeF(rr2.Size.Width / 2, rr2.Size.Height / 2), DegreesToRadians(rr2.Angle))

        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;ang &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= rr1.Angle - rr2.Angle &lt;span style="color: green"&gt;' orientation of rotated rr1
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;cosA &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= &lt;span style="color: blue"&gt;CType&lt;/span&gt;(Math.Cos(ang), &lt;span style="color: blue"&gt;Single&lt;/span&gt;) &lt;span style="color: green"&gt;' precalculated trigonometic -
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;sinA &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= &lt;span style="color: blue"&gt;CType&lt;/span&gt;(Math.Sin(ang), &lt;span style="color: blue"&gt;Single&lt;/span&gt;) &lt;span style="color: green"&gt;' - values for repeated use

        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;x, a1 &lt;span style="color: blue"&gt;As Single &lt;/span&gt;&lt;span style="color: green"&gt;' temporary variables for various uses 
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;dx &lt;span style="color: blue"&gt;As Single &lt;/span&gt;&lt;span style="color: green"&gt;' deltaX for linear equations
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;ext1, ext2 &lt;span style="color: blue"&gt;As Single &lt;/span&gt;&lt;span style="color: green"&gt;' // min/max vertical values

        ' move rr2 to make rr1 cannonic        
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;C &lt;span style="color: blue"&gt;As New &lt;/span&gt;PointF(rr2.Centre.X - rr1.Centre.X, rr2.Centre.Y - rr1.Centre.Y)

        &lt;span style="color: green"&gt;' rotate rr2 clockwise by rr2-&amp;gt;ang to make rr2 axis-aligned
        &lt;/span&gt;RotatePointFClockwise(C, rr2.Angle)        

        &lt;span style="color: green"&gt;' calculate vertices of (moved and axis-aligned := 'ma') rr2
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;BL &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF = C - rr2.Size        
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;TR &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF = C + rr2.Size

        &lt;span style="color: green"&gt;' calculate vertices of (rotated := 'r') rr1
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;A, B &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF &lt;span style="color: green"&gt;' vertices of rr2   
        &lt;/span&gt;A.X = -rr1.Size.Height * sinA
        B.X = A.X
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;temp1 &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= rr1.Size.Width * cosA
        A.X = A.X + temp1
        B.X = B.X - temp1

        A.Y = rr1.Size.Height * cosA
        B.Y = A.Y
        temp1 = rr1.Size.Width * sinA
        A.Y = A.Y + temp1
        B.Y = B.Y - temp1

        temp1 = sinA * cosA

        &lt;span style="color: green"&gt;' verify that A is vertical min/max, B is horizontal min/max
        &lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;temp1 &amp;lt; 0 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;temp1 = A.X
            A.X = B.X
            B.X = temp1
            temp1 = A.Y
            A.Y = B.Y
            B.Y = temp1
        &lt;span style="color: blue"&gt;End If

        &lt;/span&gt;&lt;span style="color: green"&gt;' verify that B is horizontal minimum (leftest-vertex)
        &lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;sinA &amp;lt; 0 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;B.X = -B.X
            B.Y = -B.Y
        &lt;span style="color: blue"&gt;End If

        &lt;/span&gt;&lt;span style="color: green"&gt;' if rr2(ma) isn't in the horizontal range of
        ' colliding with rr1(r), collision is impossible
        &lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;(B.X &amp;gt; TR.X) &lt;span style="color: blue"&gt;OrElse &lt;/span&gt;(B.X &amp;gt; -BL.X) &lt;span style="color: blue"&gt;Then Return False

        &lt;/span&gt;&lt;span style="color: green"&gt;' if rr1(r) is axis-aligned, vertical min/max are easy to get
        &lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;(temp1 = 0) &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;ext1 = A.Y
            ext2 = -ext1
        &lt;span style="color: blue"&gt;Else
            &lt;/span&gt;&lt;span style="color: green"&gt;' else, find vertical min/max in the range [BL.x, TR.x]
            &lt;/span&gt;x = BL.X - A.X
            a1 = TR.X - A.X
            ext1 = A.Y
            &lt;span style="color: green"&gt;' if the first vertical min/max isn't in (BL.x, TR.x), then
            ' find the vertical min/max on BL.x or on TR.x
            &lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;a1 * x &amp;gt; 0 &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;dx = A.X
                &lt;span style="color: blue"&gt;If &lt;/span&gt;x &amp;lt; 0 &lt;span style="color: blue"&gt;Then
                    &lt;/span&gt;dx -= B.X
                    ext1 -= B.Y
                    x = a1
                &lt;span style="color: blue"&gt;Else
                    &lt;/span&gt;dx += B.X
                    ext1 += B.Y
                &lt;span style="color: blue"&gt;End If
                &lt;/span&gt;ext1 *= x
                ext1 /= dx
                ext1 += A.Y
            &lt;span style="color: blue"&gt;End If

            &lt;/span&gt;x = BL.X + A.X
            a1 = TR.X + A.X
            ext2 = -A.Y
            &lt;span style="color: green"&gt;' if the second vertical min/max isn't in (BL.x, TR.x), then
            ' find the local vertical min/max on BL.x or on TR.x
            &lt;/span&gt;&lt;span style="color: blue"&gt;If &lt;/span&gt;a1 * x &amp;gt; 0 &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;dx = -A.X
                &lt;span style="color: blue"&gt;If &lt;/span&gt;x &amp;lt; 0 &lt;span style="color: blue"&gt;Then
                    &lt;/span&gt;dx -= B.X
                    ext2 -= B.Y
                    x = a1
                &lt;span style="color: blue"&gt;Else
                    &lt;/span&gt;dx += B.X
                    ext2 += B.Y
                &lt;span style="color: blue"&gt;End If
                &lt;/span&gt;ext2 *= x
                ext2 /= dx
                ext2 -= A.Y
            &lt;span style="color: blue"&gt;End If
        End If

        &lt;/span&gt;&lt;span style="color: green"&gt;' check whether rr2(ma) is in the vertical range of colliding with rr1(r)
        ' (for the horizontal range of rr2)
        &lt;/span&gt;&lt;span style="color: blue"&gt;Return Not &lt;/span&gt;((ext1 &amp;lt; BL.Y &lt;span style="color: blue"&gt;AndAlso &lt;/span&gt;ext2 &amp;lt; BL.Y) &lt;span style="color: blue"&gt;OrElse &lt;/span&gt;(ext1 &amp;gt; TR.Y &lt;span style="color: blue"&gt;AndAlso &lt;/span&gt;ext2 &amp;gt; TR.Y))
    &lt;span style="color: blue"&gt;End Function

    Private Shared Function &lt;/span&gt;DegreesToRadians(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;degrees &lt;span style="color: blue"&gt;As Single&lt;/span&gt;) &lt;span style="color: blue"&gt;As Single
        Return &lt;/span&gt;degrees * Pi / 180
    &lt;span style="color: blue"&gt;End Function

    Private Shared Sub &lt;/span&gt;RotatePointFClockwise(&lt;span style="color: blue"&gt;ByRef &lt;/span&gt;point &lt;span style="color: blue"&gt;As &lt;/span&gt;PointF, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;radians &lt;span style="color: blue"&gt;As Single&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;temp &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= point.X
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;cosAngle &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= &lt;span style="color: blue"&gt;CType&lt;/span&gt;(Math.Cos(radians), &lt;span style="color: blue"&gt;Single&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sinAngle &lt;span style="color: blue"&gt;As Single &lt;/span&gt;= &lt;span style="color: blue"&gt;CType&lt;/span&gt;(Math.Sin(radians), &lt;span style="color: blue"&gt;Single&lt;/span&gt;)
        point.X = temp * cosAngle + point.Y * sinAngle
        point.Y = -temp * sinAngle + point.Y * cosAngle
    &lt;span style="color: blue"&gt;End Sub

    Public Shared Operator &lt;/span&gt;=(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;rr1 &lt;span style="color: blue"&gt;As &lt;/span&gt;RotatedRectangleF, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;rr2 &lt;span style="color: blue"&gt;As &lt;/span&gt;RotatedRectangleF) &lt;span style="color: blue"&gt;As Boolean
        Return &lt;/span&gt;(rr1.Centre = rr2.Centre) &lt;span style="color: blue"&gt;AndAlso &lt;/span&gt;(rr1.Angle = rr2.Angle) &lt;span style="color: blue"&gt;AndAlso &lt;/span&gt;(rr1.Size = rr2.Size)
    &lt;span style="color: blue"&gt;End Operator

    Public Shared Operator &lt;/span&gt;&amp;lt;&amp;gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;rr1 &lt;span style="color: blue"&gt;As &lt;/span&gt;RotatedRectangleF, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;rr2 &lt;span style="color: blue"&gt;As &lt;/span&gt;RotatedRectangleF) &lt;span style="color: blue"&gt;As Boolean
        Return Not &lt;/span&gt;(rr1 = rr2)
    &lt;span style="color: blue"&gt;End Operator

End Structure
&lt;/span&gt;&lt;/pre&gt;

&lt;h5&gt;&lt;font face="Courier New" color="#666666"&gt;&lt;u&gt;And a Form1.vb to demonstrate it:&lt;/u&gt;&lt;/font&gt;&lt;/h5&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Drawing.Drawing2D

&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color: blue"&gt;Private &lt;/span&gt;selected &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 1
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;rec1 &lt;span style="color: blue"&gt;As New &lt;/span&gt;RotatedRectangleF(&lt;span style="color: blue"&gt;New &lt;/span&gt;PointF(50, -150), &lt;span style="color: blue"&gt;New &lt;/span&gt;SizeF(100, 100), 10)
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;rec2 &lt;span style="color: blue"&gt;As New &lt;/span&gt;RotatedRectangleF(&lt;span style="color: blue"&gt;New &lt;/span&gt;Point(50, -200), &lt;span style="color: blue"&gt;New &lt;/span&gt;SizeF(25, 100), 55)
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;message &lt;span style="color: blue"&gt;As String
    Private &lt;/span&gt;messageFont &lt;span style="color: blue"&gt;As New &lt;/span&gt;Font(&lt;span style="color: #a31515"&gt;&amp;quot;Courier New&amp;quot;&lt;/span&gt;, 10, FontStyle.Regular)
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;selectedRectanglePen &lt;span style="color: blue"&gt;As &lt;/span&gt;Pen = Pens.Red
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;unselectedRectanglePen &lt;span style="color: blue"&gt;As &lt;/span&gt;Pen = Pens.Black

    &lt;span style="color: blue"&gt;Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.Load
        message = &lt;span style="color: #a31515"&gt;&amp;quot;Arrow keys / mouse down to move&amp;quot; &lt;/span&gt;&amp;amp; vbCrLf
        message &amp;amp;= &lt;span style="color: #a31515"&gt;&amp;quot;Space to select other rectangle.&amp;quot; &lt;/span&gt;&amp;amp; vbCrLf
        message &amp;amp;= &lt;span style="color: #a31515"&gt;&amp;quot;z x / mouse wheel to rotate.&amp;quot;
        &lt;/span&gt;&lt;span style="color: blue"&gt;Me&lt;/span&gt;.DoubleBuffered = &lt;span style="color: blue"&gt;True
        Me&lt;/span&gt;.ClientSize = &lt;span style="color: blue"&gt;New &lt;/span&gt;Size(800, 800)
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Text = RotatedRectangleF.Intersect(rec1, rec2).ToString
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;Form1_KeyDown(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.Windows.Forms.KeyEventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.KeyDown
        &lt;span style="color: blue"&gt;Select Case &lt;/span&gt;e.KeyData
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.Left
                MoveSelectedHorizontally(-1)
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.Right
                MoveSelectedHorizontally(1)
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.Up
                MoveSelectedVertically(-1)
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.Down
                MoveSelectedVertically(1)
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.Z
                RotateSelected(-1)
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.X
                RotateSelected(1)
            &lt;span style="color: blue"&gt;Case &lt;/span&gt;Keys.Space
                &lt;span style="color: blue"&gt;If &lt;/span&gt;selected = 1 &lt;span style="color: blue"&gt;Then
                    &lt;/span&gt;selected = 2
                &lt;span style="color: blue"&gt;Else
                    &lt;/span&gt;selected = 1
                &lt;span style="color: blue"&gt;End If
                Me&lt;/span&gt;.Refresh()
        &lt;span style="color: blue"&gt;End Select
    End Sub

    Private Sub &lt;/span&gt;MouseDidSomething(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;MouseEventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.MouseMove, &lt;span style="color: blue"&gt;Me&lt;/span&gt;.MouseDown
        &lt;span style="color: blue"&gt;If &lt;/span&gt;e.Button = Windows.Forms.MouseButtons.Left &lt;span style="color: blue"&gt;Then
            Dim &lt;/span&gt;pos &lt;span style="color: blue"&gt;As New &lt;/span&gt;PointF(&lt;span style="color: blue"&gt;CSng&lt;/span&gt;(e.X - &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Width / 2), &lt;span style="color: blue"&gt;CSng&lt;/span&gt;(e.Y - &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Height / 2))
            &lt;span style="color: blue"&gt;If &lt;/span&gt;selected = 1 &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;rec1.Centre = pos
            &lt;span style="color: blue"&gt;Else
                &lt;/span&gt;rec2.Centre = pos
            &lt;span style="color: blue"&gt;End If
            Me&lt;/span&gt;.Refresh()
            &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Text = RotatedRectangleF.Intersect(rec1, rec2).ToString
        &lt;span style="color: blue"&gt;End If
    End Sub

    Private Sub &lt;/span&gt;Form1_MouseWheel(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.Windows.Forms.MouseEventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.MouseWheel
        &lt;span style="color: blue"&gt;If &lt;/span&gt;e.Delta &amp;gt; 0 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;RotateSelected(1)
        &lt;span style="color: blue"&gt;Else
            &lt;/span&gt;RotateSelected(-1)
        &lt;span style="color: blue"&gt;End If
    End Sub

    Private Sub &lt;/span&gt;RotateSelected(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;change &lt;span style="color: blue"&gt;As Single&lt;/span&gt;)
        &lt;span style="color: blue"&gt;If &lt;/span&gt;selected = 1 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;rec1.Angle += change
        &lt;span style="color: blue"&gt;Else
            &lt;/span&gt;rec2.Angle += change
        &lt;span style="color: blue"&gt;End If
        Me&lt;/span&gt;.Refresh()
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Text = RotatedRectangleF.Intersect(rec1, rec2).ToString
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;MoveSelectedHorizontally(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;change &lt;span style="color: blue"&gt;As Single&lt;/span&gt;)
        &lt;span style="color: blue"&gt;If &lt;/span&gt;selected = 1 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;rec1.Centre = &lt;span style="color: blue"&gt;New &lt;/span&gt;PointF(rec1.Centre.X + change, rec1.Centre.Y)
        &lt;span style="color: blue"&gt;Else
            &lt;/span&gt;rec2.Centre = &lt;span style="color: blue"&gt;New &lt;/span&gt;PointF(rec2.Centre.X + change, rec2.Centre.Y)
        &lt;span style="color: blue"&gt;End If
        Me&lt;/span&gt;.Refresh()
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Text = RotatedRectangleF.Intersect(rec1, rec2).ToString
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;MoveSelectedVertically(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;change &lt;span style="color: blue"&gt;As Single&lt;/span&gt;)
        &lt;span style="color: blue"&gt;If &lt;/span&gt;selected = 1 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;rec1.Centre = &lt;span style="color: blue"&gt;New &lt;/span&gt;PointF(rec1.Centre.X, rec1.Centre.Y + change)
        &lt;span style="color: blue"&gt;Else
            &lt;/span&gt;rec2.Centre = &lt;span style="color: blue"&gt;New &lt;/span&gt;PointF(rec2.Centre.X, rec2.Centre.Y + change)
        &lt;span style="color: blue"&gt;End If
        Me&lt;/span&gt;.Refresh()
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.Text = RotatedRectangleF.Intersect(rec1, rec2).ToString
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;Form1_Paint(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.Windows.Forms.PaintEventArgs) &lt;span style="color: blue"&gt;Handles Me&lt;/span&gt;.Paint
        e.Graphics.DrawString(message, messageFont, Brushes.Gray, 10, 10)
        e.Graphics.TranslateTransform(&lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Width \ 2, &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Height \ 2)
        e.Graphics.DrawLine(Pens.Gray, -&lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Width \ 2, 0, &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Width \ 2, 0)
        e.Graphics.DrawLine(Pens.Gray, 0, -&lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Height \ 2, 0, +&lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Height \ 2)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;store &lt;span style="color: blue"&gt;As &lt;/span&gt;Matrix = e.Graphics.Transform
        &lt;span style="color: blue"&gt;If &lt;/span&gt;selected = 1 &lt;span style="color: blue"&gt;Then
            &lt;/span&gt;rec2.Render(e.Graphics, unselectedRectanglePen)
            e.Graphics.Transform = store
            rec1.Render(e.Graphics, selectedRectanglePen)
        &lt;span style="color: blue"&gt;Else
            &lt;/span&gt;rec1.Render(e.Graphics, unselectedRectanglePen)
            e.Graphics.Transform = store
            rec2.Render(e.Graphics, selectedRectanglePen)
        &lt;span style="color: blue"&gt;End If
    End Sub

    

End Class
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;font face="Courier New" color="#666666"&gt;&lt;/font&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-2674884759542715666?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/2674884759542715666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/02/rotated-rectangle-collision-vbnet.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2674884759542715666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2674884759542715666'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/02/rotated-rectangle-collision-vbnet.html' title='Rotated Rectangle Collision – VB.Net'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-8875372549993931950</id><published>2009-02-02T04:10:00.006Z</published><updated>2009-02-02T04:46:54.583Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows update api'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='wuapi.dll'/><category scheme='http://www.blogger.com/atom/ns#' term='windows update history'/><category scheme='http://www.blogger.com/atom/ns#' term='datastore.edb'/><category scheme='http://www.blogger.com/atom/ns#' term='IUpdateHistoryEntry'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>VB.Net - Enumerate the windows update history using the windows update api</title><content type='html'>&lt;p&gt;Someone in the forum wanted to get the Description for each windows update, and WMI/the registry were no help. They were going to try to dig the information out of &amp;quot;C:\Windows\SoftwareDistribution\DataStore\DataStore.edb&amp;quot;, which is undocumented. Some people say it is a Jet database, but I'm not sure. Exchange server uses that extension too.
  &lt;br /&gt;

  &lt;br /&gt;Anyway the windows update api will do it. This pic shows the interfaces involved:

  &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_qnUNSzxixDU/SYZyHY2BzGI/AAAAAAAAADQ/pZ83_jaw7g8/s1600-h/updateApi%5B3%5D.gif"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="218" alt="updateApi" src="http://lh6.ggpht.com/_qnUNSzxixDU/SYZyHlu5YiI/AAAAAAAAADU/46_ExTn_o40/updateApi_thumb%5B1%5D.gif?imgmax=800" width="453" border="0" /&gt;&lt;/a&gt;&amp;#160; &lt;br /&gt;

  &lt;br /&gt;First you need to get an &lt;a href="http://msdn.microsoft.com/en-us/library/aa386854(VS.85).aspx"&gt;IUpdateSession&lt;/a&gt;. That has a &lt;a href="http://msdn.microsoft.com/en-us/library/aa386865(VS.85).aspx"&gt;CreateUpdateSearcher&lt;/a&gt; method to get an &lt;a href="http://msdn.microsoft.com/en-us/library/aa386515(VS.85).aspx"&gt;IUpdateSearcher&lt;/a&gt;. That has &lt;a href="http://msdn.microsoft.com/en-us/library/aa386524(VS.85).aspx"&gt;GetTotalHistoryCount&lt;/a&gt; to get the number of &lt;a href="http://msdn.microsoft.com/en-us/library/aa386400(VS.85).aspx"&gt;IUpdateHistoryEntry&lt;/a&gt; items inside the &lt;a href="http://msdn.microsoft.com/en-us/library/aa386409(VS.85).aspx"&gt;IUpdateHistoryCollection&lt;/a&gt;. To get the collection you call &lt;a href="http://msdn.microsoft.com/en-us/library/aa386532(VS.85).aspx"&gt;QueryHistory&lt;/a&gt; on the IUpdateSearcher, passing in the count from before. Each IUpdateHistoryEntry has a bunch of properties, some of which have custom types, but they are all simple to retrieve. To get your hands on the interfaces, the easiest way is to use tlbimp from the Visual studio command line (or the one with the platform sdk, or the one with the framework sdk). Copy the wuapi.dll file from .../Windows/System32 to some directory of your choice, navigate there and run...

  &lt;br /&gt;&lt;font face="Fixedsys" size="3"&gt;tlbimp.exe wuapi.dll /out=WUApiInterop.dll
    &lt;br /&gt;

    &lt;br /&gt;&lt;/font&gt;This creates managed signatures for all the COM interfaces in wuapi.dll and sticks them in WuApiInterop.dll. You can&amp;#160; then create a windows forms project, add a reference to WuApiInterop.dll and get your paws on all the interfaces. I made a .Net dll that has a friendly version of the IUpdateHistoryEntry object, and a method to return a collection of them. This is the code that gets the information.&lt;/p&gt;

&lt;pre class="code"&gt;    &amp;lt;SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)&amp;gt; _
    &lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;GetHistory() &lt;span style="color: blue"&gt;As &lt;/span&gt;ReadOnlyCollection(&lt;span style="color: blue"&gt;Of &lt;/span&gt;HistoryItem)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;session &lt;span style="color: blue"&gt;As &lt;/span&gt;UpdateSession = &lt;span style="color: blue"&gt;Nothing
        Dim &lt;/span&gt;searcher &lt;span style="color: blue"&gt;As &lt;/span&gt;IUpdateSearcher = &lt;span style="color: blue"&gt;Nothing
        Try
            &lt;/span&gt;session = &lt;span style="color: blue"&gt;New &lt;/span&gt;UpdateSession
            &lt;span style="color: blue"&gt;If &lt;/span&gt;session &lt;span style="color: blue"&gt;Is Nothing Then Throw New &lt;/span&gt;InvalidOperationException(&lt;span style="color: #a31515"&gt;&amp;quot;Couln't create an IUpdateSearcher.&amp;quot;&lt;/span&gt;)
            searcher = session.CreateUpdateSearcher
        &lt;span style="color: blue"&gt;Finally
            If &lt;/span&gt;session &lt;span style="color: blue"&gt;IsNot Nothing Then &lt;/span&gt;Marshal.ReleaseComObject(session)
        &lt;span style="color: blue"&gt;End Try
        If &lt;/span&gt;searcher &lt;span style="color: blue"&gt;Is Nothing Then Throw New &lt;/span&gt;InvalidOperationException(&lt;span style="color: #a31515"&gt;&amp;quot;Couldn't create an IUpdateSession.&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;count &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= searcher.GetTotalHistoryCount
        &lt;span style="color: blue"&gt;If &lt;/span&gt;count = 0 &lt;span style="color: blue"&gt;Then
            Return New &lt;/span&gt;ReadOnlyCollection(&lt;span style="color: blue"&gt;Of &lt;/span&gt;HistoryItem)(&lt;span style="color: blue"&gt;Nothing&lt;/span&gt;)
        &lt;span style="color: blue"&gt;End If
        Dim &lt;/span&gt;historyCollection &lt;span style="color: blue"&gt;As &lt;/span&gt;IUpdateHistoryEntryCollection = &lt;span style="color: blue"&gt;Nothing
        Try
            &lt;/span&gt;historyCollection = searcher.QueryHistory(0, count)
        &lt;span style="color: blue"&gt;Finally
            &lt;/span&gt;Marshal.ReleaseComObject(searcher)
        &lt;span style="color: blue"&gt;End Try
        If &lt;/span&gt;historyCollection &lt;span style="color: blue"&gt;Is Nothing Then Throw New &lt;/span&gt;InvalidOperationException(&lt;span style="color: #a31515"&gt;&amp;quot;Couldn't get an IUpdateHistoryEntryCollection.&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;items &lt;span style="color: blue"&gt;As New &lt;/span&gt;List(&lt;span style="color: blue"&gt;Of &lt;/span&gt;HistoryItem)(count)
        &lt;span style="color: blue"&gt;Try
            For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;count - 1
                &lt;span style="color: blue"&gt;Dim &lt;/span&gt;item &lt;span style="color: blue"&gt;As &lt;/span&gt;IUpdateHistoryEntry = historyCollection.Item(i)
                &lt;span style="color: blue"&gt;Dim &lt;/span&gt;friendlyItem &lt;span style="color: blue"&gt;As New &lt;/span&gt;HistoryItem
                &lt;span style="color: blue"&gt;With &lt;/span&gt;friendlyItem
                    .ClientApplicationId = item.ClientApplicationID
                    .Date = item.Date
                    .Description = item.Description
                    .HResult = item.HResult
                    &lt;span style="color: blue"&gt;Select Case &lt;/span&gt;item.Operation
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.UpdateOperation.uoInstallation
                            .Operation = UpdateOperation.Installation
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.UpdateOperation.uoUninstallation
                            .Operation = UpdateOperation.Uninstallation
                    &lt;span style="color: blue"&gt;End Select
                    Select Case &lt;/span&gt;item.ResultCode
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.OperationResultCode.orcAborted
                            .ResultCode = OperationResultCode.Aborted
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.OperationResultCode.orcFailed
                            .ResultCode = OperationResultCode.Failed
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.OperationResultCode.orcInProgress
                            .ResultCode = OperationResultCode.InProgress
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.OperationResultCode.orcNotStarted
                            .ResultCode = OperationResultCode.NotStarted
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.OperationResultCode.orcSucceeded
                            .ResultCode = OperationResultCode.Succeeded
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.OperationResultCode.orcSucceededWithErrors
                            .ResultCode = OperationResultCode.SucceededWithErrors
                    &lt;span style="color: blue"&gt;End Select
                    Select Case &lt;/span&gt;item.ServerSelection
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.ServerSelection.ssDefault
                            .ServerSelection = ServerSelection.Default
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.ServerSelection.ssManagedServer
                            .ServerSelection = ServerSelection.ManagedServer
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.ServerSelection.ssOthers
                            .ServerSelection = ServerSelection.Others
                        &lt;span style="color: blue"&gt;Case &lt;/span&gt;WUApiInterop.ServerSelection.ssWindowsUpdate
                            .ServerSelection = ServerSelection.WindowsUpdate
                    &lt;span style="color: blue"&gt;End Select
                    &lt;/span&gt;.ServiceId = item.ServiceID
                    Uri.TryCreate(item.SupportUrl, UriKind.Absolute, .SupportUrl)
                    .Title = item.Title
                    .UninstallationNotes = item.UninstallationNotes
                    .UninstallationSteps = &lt;span style="color: blue"&gt;New &lt;/span&gt;System.Collections.Specialized.StringCollection
                    &lt;span style="color: blue"&gt;For &lt;/span&gt;j &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;item.UninstallationSteps.Count - 1
                        .UninstallationSteps.Add(item.UninstallationSteps(j))
                    &lt;span style="color: blue"&gt;Next
                    &lt;/span&gt;.UnmappedResultCode = item.UnmappedResultCode
                    &lt;span style="color: blue"&gt;Dim &lt;/span&gt;identity &lt;span style="color: blue"&gt;As New &lt;/span&gt;UpdateIdentity(item.UpdateIdentity.RevisionNumber, item.UpdateIdentity.UpdateID)
                    .UpdateIdentity = identity
                &lt;span style="color: blue"&gt;End With
                &lt;/span&gt;items.Add(friendlyItem)
            &lt;span style="color: blue"&gt;Next
        Finally
            &lt;/span&gt;Marshal.ReleaseComObject(historyCollection)
        &lt;span style="color: blue"&gt;End Try
        Return New &lt;/span&gt;ReadOnlyCollection(&lt;span style="color: blue"&gt;Of &lt;/span&gt;HistoryItem)(items)
    &lt;span style="color: blue"&gt;End Function
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Attached is an example project:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;iframe style="border-right: #dde5e9 1px solid; padding-right: 0px; border-top: #dde5e9 1px solid; padding-left: 0px; padding-bottom: 0px; margin: 3px; border-left: #dde5e9 1px solid; width: 240px; padding-top: 0px; border-bottom: #dde5e9 1px solid; height: 66px; background-color: #ffffff" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/Windows%20Update%20API.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-8875372549993931950?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/8875372549993931950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/02/vbnet-enumerate-windows-update-history.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/8875372549993931950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/8875372549993931950'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/02/vbnet-enumerate-windows-update-history.html' title='VB.Net - Enumerate the windows update history using the windows update api'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_qnUNSzxixDU/SYZyHlu5YiI/AAAAAAAAADU/46_ExTn_o40/s72-c/updateApi_thumb%5B1%5D.gif?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-4990448209362234462</id><published>2009-01-23T16:05:00.003Z</published><updated>2009-01-23T16:09:37.409Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='DRVM_MAPPER_PREFERRED_GET'/><category scheme='http://www.blogger.com/atom/ns#' term='DRVM_MAPPER_PREFERRED_SET'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='xp'/><category scheme='http://www.blogger.com/atom/ns#' term='Set default audio playback device xp'/><title type='text'>Set default Wave Out Audio Device - VB.Net / DRVM_MAPPER_PREFERRED_SET</title><content type='html'>&lt;p&gt;You can set the default audio playback device in windows 2000, Me, and XP with the DRVM_MAPPER_PREFERRED_SET message, which is sent with waveOutMessage(). &lt;/p&gt;

&lt;p&gt;It doesn't work on vista - you get &lt;span class="srcSentence" id="src18"&gt;MMSYSERR_NOTSUPPORTED (8), returned. 
    &lt;br /&gt;You can do it in Vista - see &lt;a href="http://vachanger.sourceforge.net/"&gt;http://vachanger.sourceforge.net/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="srcSentence"&gt;Anyway, the code uses the &lt;a href="http://windowsmedianet.sourceforge.net/"&gt;Windows Media .Net library&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;span style="color: blue"&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;MultiMedia &lt;span style="color: green"&gt;' http://windowsmedianet.sourceforge.net/
&lt;/span&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Runtime.InteropServices
&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.ComponentModel

&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color: blue"&gt;Private &lt;/span&gt;DevicesComboBox &lt;span style="color: blue"&gt;As New &lt;/span&gt;ComboBox
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;DefaultDeviceLabel &lt;span style="color: blue"&gt;As New &lt;/span&gt;Label
    &lt;span style="color: blue"&gt;Private WithEvents &lt;/span&gt;SetDefaultButton &lt;span style="color: blue"&gt;As New &lt;/span&gt;Button
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;DRVM_MAPPER_PREFERRED_GET &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= &amp;amp;H2015
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;DRVM_MAPPER_PREFERRED_SET &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= &amp;amp;H2016
    &lt;span style="color: blue"&gt;Private &lt;/span&gt;WAVE_MAPPER &lt;span style="color: blue"&gt;As New &lt;/span&gt;IntPtr(-1)

    &lt;span style="color: green"&gt;' This just brings together a device ID and a WaveOutCaps so 
    ' that we can store them in a combobox.
    &lt;/span&gt;&lt;span style="color: blue"&gt;Private Structure &lt;/span&gt;WaveOutDevice

        &lt;span style="color: blue"&gt;Private &lt;/span&gt;m_id &lt;span style="color: blue"&gt;As Integer
        Public Property &lt;/span&gt;Id() &lt;span style="color: blue"&gt;As Integer
            Get
                Return &lt;/span&gt;m_id
            &lt;span style="color: blue"&gt;End Get
            Set&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;value &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;)
                m_id = value
            &lt;span style="color: blue"&gt;End Set
        End Property

        Private &lt;/span&gt;m_caps &lt;span style="color: blue"&gt;As &lt;/span&gt;WaveOutCaps
        &lt;span style="color: blue"&gt;Public Property &lt;/span&gt;WaveOutCaps() &lt;span style="color: blue"&gt;As &lt;/span&gt;WaveOutCaps
            &lt;span style="color: blue"&gt;Get
                Return &lt;/span&gt;m_caps
            &lt;span style="color: blue"&gt;End Get
            Set&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;value &lt;span style="color: blue"&gt;As &lt;/span&gt;WaveOutCaps)
                m_caps = value
            &lt;span style="color: blue"&gt;End Set
        End Property

        Sub New&lt;/span&gt;(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;id &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;caps &lt;span style="color: blue"&gt;As &lt;/span&gt;WaveOutCaps)
            m_id = id
            m_caps = caps
        &lt;span style="color: blue"&gt;End Sub

        Public Overrides Function &lt;/span&gt;ToString() &lt;span style="color: blue"&gt;As String
            Return &lt;/span&gt;WaveOutCaps.szPname
        &lt;span style="color: blue"&gt;End Function

    End Structure

    Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As &lt;/span&gt;System.Object, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color: blue"&gt;Handles MyBase&lt;/span&gt;.Load
        &lt;span style="color: green"&gt;' I do use the IDE for this stuff normally... (in case anyone is wondering)
        &lt;/span&gt;&lt;span style="color: blue"&gt;Me&lt;/span&gt;.Controls.AddRange(&lt;span style="color: blue"&gt;New &lt;/span&gt;Control() {DevicesComboBox, DefaultDeviceLabel, SetDefaultButton})
        DevicesComboBox.Location = &lt;span style="color: blue"&gt;New &lt;/span&gt;Point(5, 5)
        DevicesComboBox.DropDownStyle = ComboBoxStyle.DropDownList
        DevicesComboBox.Width = &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ClientSize.Width - 10
        DevicesComboBox.Anchor = AnchorStyles.Left &lt;span style="color: blue"&gt;Or &lt;/span&gt;AnchorStyles.Right
        DefaultDeviceLabel.Location = &lt;span style="color: blue"&gt;New &lt;/span&gt;Point(DevicesComboBox.Left, DevicesComboBox.Bottom + 5)
        DefaultDeviceLabel.AutoSize = &lt;span style="color: blue"&gt;True
        &lt;/span&gt;SetDefaultButton.Location = &lt;span style="color: blue"&gt;New &lt;/span&gt;Point(DefaultDeviceLabel.Left, DefaultDeviceLabel.Bottom + 5)
        SetDefaultButton.Text = &lt;span style="color: #a31515"&gt;&amp;quot;Set Default&amp;quot;
        &lt;/span&gt;SetDefaultButton.AutoSize = &lt;span style="color: blue"&gt;True
        &lt;/span&gt;RefreshInformation()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;RefreshInformation()
        PopulateDeviceComboBox()
        DisplayDefaultWaveOutDevice()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;PopulateDeviceComboBox()
        DevicesComboBox.Items.Clear()
        &lt;span style="color: green"&gt;' How many wave out devices are there? WaveOutGetNumDevs API call.
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;waveOutDeviceCount &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= waveOut.GetNumDevs()
        &lt;span style="color: blue"&gt;For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;waveOutDeviceCount - 1
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;caps &lt;span style="color: blue"&gt;As New &lt;/span&gt;WaveOutCaps
            &lt;span style="color: green"&gt;' Get a name - its in a WAVEOUTCAPS structure. 
            ' The name is truncated to 31 chars by the api call. You probably have to 
            ' dig around in the registry to get the full name.
            &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= waveOut.GetDevCaps(i, caps, Marshal.SizeOf(caps))
            &lt;span style="color: blue"&gt;If &lt;/span&gt;result &amp;lt;&amp;gt; MMSYSERR.NoError &lt;span style="color: blue"&gt;Then
                Dim &lt;/span&gt;err &lt;span style="color: blue"&gt;As &lt;/span&gt;MMSYSERR = &lt;span style="color: blue"&gt;DirectCast&lt;/span&gt;(result, MMSYSERR)
                &lt;span style="color: blue"&gt;Throw New &lt;/span&gt;Win32Exception(&lt;span style="color: #a31515"&gt;&amp;quot;GetDevCaps() error, Result: &amp;quot; &lt;/span&gt;&amp;amp; result.ToString(&lt;span style="color: #a31515"&gt;&amp;quot;x8&amp;quot;&lt;/span&gt;) &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;, &amp;quot; &lt;/span&gt;&amp;amp; err.ToString)
            &lt;span style="color: blue"&gt;End If
            &lt;/span&gt;DevicesComboBox.Items.Add(&lt;span style="color: blue"&gt;New &lt;/span&gt;WaveOutDevice(i, caps))
        &lt;span style="color: blue"&gt;Next
        &lt;/span&gt;DevicesComboBox.SelectedIndex = 0
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;DisplayDefaultWaveOutDevice()
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;currentDefault &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= GetIdOfDefaultWaveOutDevice()
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;device &lt;span style="color: blue"&gt;As &lt;/span&gt;WaveOutDevice = &lt;span style="color: blue"&gt;DirectCast&lt;/span&gt;(DevicesComboBox.Items(currentDefault), WaveOutDevice)
        DefaultDeviceLabel.Text = &lt;span style="color: #a31515"&gt;&amp;quot;Defualt: &amp;quot; &lt;/span&gt;&amp;amp; device.WaveOutCaps.szPname
    &lt;span style="color: blue"&gt;End Sub

    Private Function &lt;/span&gt;GetIdOfDefaultWaveOutDevice() &lt;span style="color: blue"&gt;As Integer        
        Dim &lt;/span&gt;id &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;hId &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;flags &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;hFlags &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As Integer
        Try
            &lt;/span&gt;&lt;span style="color: green"&gt;' It would be easier to declare a nice overload with ByRef Integers.
            &lt;/span&gt;hId = Marshal.AllocHGlobal(4)
            hFlags = Marshal.AllocHGlobal(4)
            &lt;span style="color: green"&gt;' http://msdn.microsoft.com/en-us/library/bb981557.aspx
            &lt;/span&gt;result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, hId, hFlags)
            &lt;span style="color: blue"&gt;If &lt;/span&gt;result &amp;lt;&amp;gt; MMSYSERR.NoError &lt;span style="color: blue"&gt;Then
                Dim &lt;/span&gt;err &lt;span style="color: blue"&gt;As &lt;/span&gt;MMSYSERR = &lt;span style="color: blue"&gt;DirectCast&lt;/span&gt;(result, MMSYSERR)
                &lt;span style="color: blue"&gt;Throw New &lt;/span&gt;Win32Exception(&lt;span style="color: #a31515"&gt;&amp;quot;waveOutMessage() error, Result: &amp;quot; &lt;/span&gt;&amp;amp; result.ToString(&lt;span style="color: #a31515"&gt;&amp;quot;x8&amp;quot;&lt;/span&gt;) &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;, &amp;quot; &lt;/span&gt;&amp;amp; err.ToString)
            &lt;span style="color: blue"&gt;End If
            &lt;/span&gt;id = Marshal.ReadInt32(hId)
            flags = Marshal.ReadInt32(hFlags)
        &lt;span style="color: blue"&gt;Finally
            &lt;/span&gt;Marshal.FreeHGlobal(hId)
            Marshal.FreeHGlobal(hFlags)
        &lt;span style="color: blue"&gt;End Try
        &lt;/span&gt;&lt;span style="color: green"&gt;' There is only one flag, DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY, defined as 1
        ' &amp;quot;When the DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY flag bit is set, ... blah ...,  
        ' the waveIn and waveOut APIs use only the current preferred device and do not search 
        ' for other available devices if the preferred device is unavailable. 
        &lt;/span&gt;&lt;span style="color: blue"&gt;Return &lt;/span&gt;id
    &lt;span style="color: blue"&gt;End Function

    Private Sub &lt;/span&gt;SetDefaultButton_Click(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color: blue"&gt;Handles &lt;/span&gt;SetDefaultButton.Click
        &lt;span style="color: blue"&gt;If &lt;/span&gt;DevicesComboBox.Items.Count = 0 &lt;span style="color: blue"&gt;Then Return
        Dim &lt;/span&gt;selectedDevice &lt;span style="color: blue"&gt;As &lt;/span&gt;WaveOutDevice = &lt;span style="color: blue"&gt;DirectCast&lt;/span&gt;(DevicesComboBox.SelectedItem, WaveOutDevice)
        SetDefault(selectedDevice.Id)
        RefreshInformation()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;SetDefault(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;id &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;defaultId &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= GetIdOfDefaultWaveOutDevice()
        &lt;span style="color: blue"&gt;If &lt;/span&gt;defaultId = id &lt;span style="color: blue"&gt;Then Return &lt;/span&gt;&lt;span style="color: green"&gt;' no change.
        &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As Integer
        &lt;/span&gt;&lt;span style="color: green"&gt;' So here we say &amp;quot;change the Id of the device that has id id to 0&amp;quot;, which makes it the default.
        &lt;/span&gt;result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_SET, &lt;span style="color: blue"&gt;New &lt;/span&gt;IntPtr(id), IntPtr.Zero)
        &lt;span style="color: blue"&gt;If &lt;/span&gt;result &amp;lt;&amp;gt; MMSYSERR.NoError &lt;span style="color: blue"&gt;Then
            Dim &lt;/span&gt;err &lt;span style="color: blue"&gt;As &lt;/span&gt;MMSYSERR = &lt;span style="color: blue"&gt;DirectCast&lt;/span&gt;(result, MMSYSERR)
            &lt;span style="color: blue"&gt;Throw New &lt;/span&gt;Win32Exception(&lt;span style="color: #a31515"&gt;&amp;quot;waveOutMessage() error, Result: &amp;quot; &lt;/span&gt;&amp;amp; result.ToString(&lt;span style="color: #a31515"&gt;&amp;quot;x8&amp;quot;&lt;/span&gt;) &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;, &amp;quot; &lt;/span&gt;&amp;amp; err.ToString)
        &lt;span style="color: blue"&gt;End If
    End Sub

End Class
&lt;/span&gt;&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

  &lt;br /&gt;&lt;/span&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;span class="srcSentence"&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="srcSentence"&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="srcSentence"&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-4990448209362234462?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/4990448209362234462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/01/set-default-wave-out-audio-device-vbnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4990448209362234462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4990448209362234462'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/01/set-default-wave-out-audio-device-vbnet.html' title='Set default Wave Out Audio Device - VB.Net / DRVM_MAPPER_PREFERRED_SET'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-2430046166474512547</id><published>2009-01-15T04:45:00.002Z</published><updated>2009-01-15T04:46:23.517Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='setup api'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='enable disable device'/><title type='text'>Enable/Disable a device programmatically with VB.Net using the setup api.</title><content type='html'>&lt;p&gt;Very quickly...&lt;/p&gt;  &lt;p&gt;Check in device manager to see if the device has &amp;quot;Disable&amp;quot; as an option when you R click it. If so then look at the properties, and find the &amp;quot;class guid&amp;quot; and &amp;quot;device instance id&amp;quot;.&lt;/p&gt;  &lt;p&gt;1) Get a handle to a device info set using SetupDiGetClassDevs - this will get all devices in a class.    &lt;br /&gt;2) Get device info data for each device in the class using SetupDiEnumDeviceInfo     &lt;br /&gt;3) Get the device instance id for each device using the device info data from (2) and SetupDiGetDeviceInstanceId.     &lt;br /&gt;4) Fill in a structure to say you want a property change and call SetupDiSetClassInstallParams. This sets the property in the device info set.     &lt;br /&gt;5) Call SetupDiCallClassInstaller to get the installer to make the changes stick.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt; &lt;iframe style="border-right: #dde5e9 1px solid; padding-right: 0px; border-top: #dde5e9 1px solid; padding-left: 0px; padding-bottom: 0px; margin: 3px; border-left: #dde5e9 1px solid; width: 240px; padding-top: 0px; border-bottom: #dde5e9 1px solid; height: 66px; background-color: #ffffff" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/DisableDevice.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-2430046166474512547?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/2430046166474512547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/01/enabledisable-device-programmatically.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2430046166474512547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2430046166474512547'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/01/enabledisable-device-programmatically.html' title='Enable/Disable a device programmatically with VB.Net using the setup api.'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3832244424096147213</id><published>2009-01-09T05:28:00.001Z</published><updated>2009-01-09T05:28:52.086Z</updated><title type='text'>Font choice -&gt; dumb bug</title><content type='html'>&lt;p&gt;Oh wonderful. I thought I was doing something seriously wrong whilst trying to record sound. WaveInOpen takes a flag value, I wanted to specify that it should callback a function and read it as:&lt;/p&gt; &lt;font size="2"&gt;   &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;CALLBACK_FUNCTION   0x000300001&lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/font&gt;

&lt;p&gt;where it is actually&lt;font color="#0000ff" size="2"&gt; &lt;/font&gt;&lt;/p&gt;
&lt;font size="2"&gt;
  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;#define &lt;/span&gt;CALLBACK_FUNCTION   0x00030000l &lt;/pre&gt;
  &lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/font&gt;

&lt;p&gt;Big difference eh. 1 vs L. The L specifies a C Long (32 bit integer). &lt;/p&gt;

&lt;p&gt;I ended up sending two flags then, 0x300000 and 0x1. 0x1 tells it to just query - &amp;quot;can the device be opened&amp;quot; - without actually opening it. 0x300000 isn't defined. In testing it &lt;em&gt;did&lt;/em&gt; call my callback function about 1 time in 3, the other 2 times it just crashed without error. So I though it was because I was doing the wrong thing in the callback. Argh.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3832244424096147213?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3832244424096147213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/01/font-choice-dumb-bug.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3832244424096147213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3832244424096147213'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2009/01/font-choice-dumb-bug.html' title='Font choice -&amp;gt; dumb bug'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-4753608076306015547</id><published>2008-12-28T20:30:00.002Z</published><updated>2008-12-28T20:32:11.888Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WriteFile'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Create bootable flash disk'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Make a bootable USB Flash Drive from a floppy image file (VB.Net)</title><content type='html'>&lt;p&gt;To do this you just need a handle to the drive (the device handle), and then use WriteFile to copy the image to the drive. Here's a rough example.&lt;/p&gt;  &lt;p&gt;At the moment it rounds the byte array containing the image file up to the nearest 512 bytes, as otherwise it returns &amp;quot;invalid parameter&amp;quot;. &lt;/p&gt; &lt;iframe style="border-right: #dde5e9 1px solid; padding-right: 0px; border-top: #dde5e9 1px solid; padding-left: 0px; padding-bottom: 0px; margin: 3px; border-left: #dde5e9 1px solid; width: 240px; padding-top: 0px; border-bottom: #dde5e9 1px solid; height: 66px; background-color: #ffffff" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/WriteDiskImage.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.IO
&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Text

&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color: blue"&gt;Private &lt;/span&gt;sourceFile &lt;span style="color: blue"&gt;As &lt;/span&gt;FileInfo

    &lt;span style="color: blue"&gt;Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;EventArgs) &lt;span style="color: blue"&gt;Handles MyBase&lt;/span&gt;.Load
        RefreshDrives()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;btnBrowse_Click(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;EventArgs) _
        &lt;span style="color: blue"&gt;Handles &lt;/span&gt;btnBrowse.Click
        &lt;span style="color: blue"&gt;Using &lt;/span&gt;ofd &lt;span style="color: blue"&gt;As New &lt;/span&gt;OpenFileDialog
            ofd.Title = &lt;span style="color: #a31515"&gt;&amp;quot;Select disk image file&amp;quot;
            &lt;/span&gt;ofd.Multiselect = &lt;span style="color: blue"&gt;False
            Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As &lt;/span&gt;DialogResult = ofd.ShowDialog
            &lt;span style="color: blue"&gt;If &lt;/span&gt;result = Windows.Forms.DialogResult.OK &lt;span style="color: blue"&gt;Then
                Try
                    &lt;/span&gt;sourceFile = &lt;span style="color: blue"&gt;New &lt;/span&gt;FileInfo(ofd.FileName)
                &lt;span style="color: blue"&gt;Catch &lt;/span&gt;ex &lt;span style="color: blue"&gt;As &lt;/span&gt;Exception
                    MessageBox.Show(ex.Message)
                    sourceFile = &lt;span style="color: blue"&gt;Nothing
                End Try
            End If
        End Using
        If &lt;/span&gt;sourceFile &lt;span style="color: blue"&gt;IsNot Nothing Then
            Me&lt;/span&gt;.TextBox1.Text = sourceFile.ToString
        &lt;span style="color: blue"&gt;End If
        &lt;/span&gt;RefreshBtn_Nuke()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;btnRefresh_Click(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;EventArgs) _
        &lt;span style="color: blue"&gt;Handles &lt;/span&gt;btnRefresh.Click
        RefreshDrives()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;RefreshDrives()
        &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ComboBox1.Items.Clear()
        &lt;span style="color: blue"&gt;For Each &lt;/span&gt;di &lt;span style="color: blue"&gt;As &lt;/span&gt;DriveInfo &lt;span style="color: blue"&gt;In &lt;/span&gt;DriveInfo.GetDrives
            &lt;span style="color: blue"&gt;If &lt;/span&gt;di.DriveType = DriveType.Removable &lt;span style="color: blue"&gt;Then
                Me&lt;/span&gt;.ComboBox1.Items.Add(di)
            &lt;span style="color: blue"&gt;End If
        Next
        Me&lt;/span&gt;.ComboBox1.SelectedIndex = 0
        RefreshBtn_Nuke()
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;RefreshBtn_Nuke()
        btnNuke.Enabled = (sourceFile &lt;span style="color: blue"&gt;IsNot Nothing&lt;/span&gt;) &lt;span style="color: blue"&gt;AndAlso &lt;/span&gt;_
            &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ComboBox1.Items.Count &amp;gt; 0
    &lt;span style="color: blue"&gt;End Sub

    Private Sub &lt;/span&gt;btnNuke_Click(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;sender &lt;span style="color: blue"&gt;As Object&lt;/span&gt;, &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;e &lt;span style="color: blue"&gt;As &lt;/span&gt;EventArgs) &lt;span style="color: blue"&gt;Handles &lt;/span&gt;btnNuke.Click
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As &lt;/span&gt;DialogResult
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;drive &lt;span style="color: blue"&gt;As String &lt;/span&gt;= &lt;span style="color: blue"&gt;Me&lt;/span&gt;.ComboBox1.Text
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sb &lt;span style="color: blue"&gt;As New &lt;/span&gt;StringBuilder
        sb.AppendLine(&lt;span style="color: #a31515"&gt;&amp;quot;Do you really want to erase drive &amp;quot; &lt;/span&gt;&amp;amp; drive &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;)
        sb.AppendLine(&lt;span style="color: #a31515"&gt;&amp;quot;Doing so will DESTROY ALL EXISTING DATA ON DRIVE &amp;quot; &lt;/span&gt;&amp;amp; drive &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot;!&amp;quot;&lt;/span&gt;)
        result = MessageBox.Show(sb.ToString, _
                                 &lt;span style="color: #a31515"&gt;&amp;quot;Destroy Drive &amp;quot; &lt;/span&gt;&amp;amp; drive &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot; ?&amp;quot;&lt;/span&gt;, _
                                 MessageBoxButtons.YesNo, _
                                MessageBoxIcon.Exclamation, _
                                 MessageBoxDefaultButton.Button2)
        &lt;span style="color: blue"&gt;If &lt;/span&gt;result = Windows.Forms.DialogResult.Yes &lt;span style="color: blue"&gt;Then
            Dim &lt;/span&gt;dest &lt;span style="color: blue"&gt;As &lt;/span&gt;DriveInfo = &lt;span style="color: blue"&gt;TryCast&lt;/span&gt;(&lt;span style="color: blue"&gt;Me&lt;/span&gt;.ComboBox1.SelectedItem, DriveInfo)
            &lt;span style="color: blue"&gt;If &lt;/span&gt;sourceFile &lt;span style="color: blue"&gt;IsNot Nothing AndAlso &lt;/span&gt;dest &lt;span style="color: blue"&gt;IsNot Nothing Then
                Dim &lt;/span&gt;written &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= Win32.CopyToDevice(sourceFile, dest)
                MessageBox.Show(&lt;span style="color: #a31515"&gt;&amp;quot;Wrote: &amp;quot; &lt;/span&gt;&amp;amp; written &amp;amp; &lt;span style="color: #a31515"&gt;&amp;quot; bytes to &amp;quot; &lt;/span&gt;&amp;amp; drive, &lt;span style="color: #a31515"&gt;&amp;quot;Done&amp;quot;&lt;/span&gt;, _
                                MessageBoxButtons.OK, MessageBoxIcon.Information)
                Application.Exit()
            &lt;span style="color: blue"&gt;Else
                &lt;/span&gt;RefreshBtn_Nuke()
            &lt;span style="color: blue"&gt;End If
        End If
    End Sub

End Class
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;Option Strict On
Option Explicit On

Imports &lt;/span&gt;Microsoft.Win32.SafeHandles
&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.ComponentModel
&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.IO
&lt;span style="color: blue"&gt;Imports &lt;/span&gt;System.Runtime.InteropServices

&lt;span style="color: blue"&gt;Public Class &lt;/span&gt;Win32

    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;GenericRead &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= &amp;amp;H80000000UI
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;GenericWrite &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= &amp;amp;H40000000
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;FileShareRead &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= 1
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;Filesharewrite &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= 2
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;OpenExisting &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= 3
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;IoctlVolumeGetVolumeDiskExtents &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= &amp;amp;H560000
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;IncorrectFunction &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= 1
    &lt;span style="color: blue"&gt;Private Const &lt;/span&gt;ErrorInsufficientBuffer &lt;span style="color: blue"&gt;As UInteger &lt;/span&gt;= 122

    &lt;span style="color: blue"&gt;Private Class &lt;/span&gt;NativeMethods
        &amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, CharSet:=CharSet.Unicode, SetLastError:=&lt;span style="color: blue"&gt;True&lt;/span&gt;)&amp;gt; _
        &lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;CreateFile( _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;fileName &lt;span style="color: blue"&gt;As String&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;desiredAccess &lt;span style="color: blue"&gt;As UInteger&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;shareMode &lt;span style="color: blue"&gt;As UInteger&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;securityAttributes &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;creationDisposition &lt;span style="color: blue"&gt;As UInteger&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;flagsAndAttributes &lt;span style="color: blue"&gt;As UInteger&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;hTemplateFile &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle
        &lt;span style="color: blue"&gt;End Function

        &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span style="color: blue"&gt;True&lt;/span&gt;)&amp;gt; _
        &lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;DeviceIoControl( _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;hVol &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;controlCode &lt;span style="color: blue"&gt;As UInteger&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;inBuffer &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;inBufferSize &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByRef &lt;/span&gt;outBuffer &lt;span style="color: blue"&gt;As &lt;/span&gt;DiskExtents, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;outBufferSize &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByRef &lt;/span&gt;bytesReturned &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;overlapped &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color: blue"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color: blue"&gt;Boolean
        End Function

        &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span style="color: blue"&gt;True&lt;/span&gt;)&amp;gt; _
        &lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;DeviceIoControl( _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;hVol &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;controlCode &lt;span style="color: blue"&gt;As UInteger&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;inBuffer &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;inBufferSize &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;outBuffer &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;outBufferSize &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByRef &lt;/span&gt;bytesReturned &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;overlapped &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color: blue"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color: blue"&gt;Boolean
        End Function

        &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span style="color: blue"&gt;True&lt;/span&gt;)&amp;gt; _
        &lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;SetFilePointer( _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;hFile &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;lDistanceToMove &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByRef &lt;/span&gt;lpDistanceToMoveHigh &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
            &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;dwMoveMethod &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;) &lt;span style="color: blue"&gt;As UInteger
        End Function

        &lt;/span&gt;&lt;span style="color: green"&gt;' you must write the whole inBuffer.
        &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: #a31515"&gt;&amp;quot;kernel32&amp;quot;&lt;/span&gt;, SetLastError:=&lt;span style="color: blue"&gt;True&lt;/span&gt;, CharSet:=CharSet.Ansi)&amp;gt; _
        &lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;WriteFile( _
          &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;hVol &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle, _
          &amp;lt;MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=3)&amp;gt; _
          &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;inBuffer() &lt;span style="color: blue"&gt;As Byte&lt;/span&gt;, _
          &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;numberOfBytesToWrite &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
          &lt;span style="color: blue"&gt;ByRef &lt;/span&gt;numberOfBytesWritten &lt;span style="color: blue"&gt;As Integer&lt;/span&gt;, _
          &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;overlapped &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color: blue"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color: blue"&gt;Boolean
        End Function

    End Class

    &lt;/span&gt;&lt;span style="color: green"&gt;' DISK_EXTENT in the msdn.
    &lt;/span&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
    &lt;span style="color: blue"&gt;Private Structure &lt;/span&gt;DiskExtent
        &lt;span style="color: blue"&gt;Public &lt;/span&gt;DiskNumber &lt;span style="color: blue"&gt;As Integer
        Public &lt;/span&gt;StartingOffset &lt;span style="color: blue"&gt;As Long
        Public &lt;/span&gt;ExtentLength &lt;span style="color: blue"&gt;As Long
    End Structure

    &lt;/span&gt;&lt;span style="color: green"&gt;' DISK_EXTENTS
    &lt;/span&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
    &lt;span style="color: blue"&gt;Private Structure &lt;/span&gt;DiskExtents
        &lt;span style="color: blue"&gt;Public &lt;/span&gt;numberOfExtents &lt;span style="color: blue"&gt;As Integer
        Public &lt;/span&gt;first &lt;span style="color: blue"&gt;As &lt;/span&gt;DiskExtent &lt;span style="color: green"&gt;' We can't marhsal an array if we don't know its size.
    &lt;/span&gt;&lt;span style="color: blue"&gt;End Structure

    Public Shared Function &lt;/span&gt;CopyToDevice(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;source &lt;span style="color: blue"&gt;As &lt;/span&gt;FileInfo, _
                                        &lt;span style="color: blue"&gt;ByVal &lt;/span&gt;destination &lt;span style="color: blue"&gt;As &lt;/span&gt;DriveInfo) &lt;span style="color: blue"&gt;As Integer
        Dim &lt;/span&gt;physicalDrives &lt;span style="color: blue"&gt;As &lt;/span&gt;List(&lt;span style="color: blue"&gt;Of String&lt;/span&gt;) = GetPhysicalDriveStrings(destination)
        &lt;span style="color: blue"&gt;If &lt;/span&gt;physicalDrives.Count &amp;gt; 1 &lt;span style="color: blue"&gt;Then
            Throw New &lt;/span&gt;Exception(&lt;span style="color: #a31515"&gt;&amp;quot;The volume spans multiple disks!&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;End If
        If &lt;/span&gt;physicalDrives.Count = 0 &lt;span style="color: blue"&gt;Then
            Throw New &lt;/span&gt;Exception(&lt;span style="color: #a31515"&gt;&amp;quot;Could not find the physical drive!&amp;quot;&lt;/span&gt;)
        &lt;span style="color: blue"&gt;End If
        Dim &lt;/span&gt;physicalDrive &lt;span style="color: blue"&gt;As String &lt;/span&gt;= physicalDrives(0)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sourceFile &lt;span style="color: blue"&gt;As String &lt;/span&gt;= source.FullName
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;driveHandle &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle = &lt;span style="color: blue"&gt;Nothing
        Try
            &lt;/span&gt;driveHandle = NativeMethods.CreateFile( _
                physicalDrive, GenericRead &lt;span style="color: blue"&gt;Or &lt;/span&gt;GenericWrite, _
                FileShareRead &lt;span style="color: blue"&gt;Or &lt;/span&gt;Filesharewrite, _
                IntPtr.Zero, OpenExisting, 0, IntPtr.Zero)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;bytes() &lt;span style="color: blue"&gt;As Byte &lt;/span&gt;= &lt;span style="color: blue"&gt;My&lt;/span&gt;.Computer.FileSystem.ReadAllBytes(source.FullName)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;remainder &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 512 - (bytes.Length &lt;span style="color: blue"&gt;Mod &lt;/span&gt;512)
            &lt;span style="color: blue"&gt;If &lt;/span&gt;remainder &amp;lt; 512 &lt;span style="color: blue"&gt;Then
                ReDim Preserve &lt;/span&gt;bytes(bytes.Length + remainder - 1)
            &lt;span style="color: blue"&gt;End If
            Dim &lt;/span&gt;written &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0
            NativeMethods.SetFilePointer(driveHandle, 0, 0, 0)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As Boolean &lt;/span&gt;= NativeMethods.WriteFile(driveHandle, _
                bytes, bytes.Length, written, IntPtr.Zero)
            &lt;span style="color: blue"&gt;If &lt;/span&gt;result = &lt;span style="color: blue"&gt;False Then Throw New &lt;/span&gt;Win32Exception
            &lt;span style="color: blue"&gt;Return &lt;/span&gt;written
        &lt;span style="color: blue"&gt;Finally
            If &lt;/span&gt;driveHandle &lt;span style="color: blue"&gt;IsNot Nothing Then
                If &lt;/span&gt;driveHandle.IsInvalid = &lt;span style="color: blue"&gt;False Then
                    If &lt;/span&gt;driveHandle.IsClosed = &lt;span style="color: blue"&gt;False Then
                        &lt;/span&gt;driveHandle.Close()
                    &lt;span style="color: blue"&gt;End If
                End If
                &lt;/span&gt;driveHandle.Dispose()
            &lt;span style="color: blue"&gt;End If
        End Try

    End Function

    &lt;/span&gt;&lt;span style="color: green"&gt;' A Volume could be on many physical drives.
    ' Returns a list of string containing each physical drive the volume uses.
    ' For CD Drives with no disc in it will return an empty list.
    &lt;/span&gt;&lt;span style="color: blue"&gt;Public Shared Function &lt;/span&gt;GetPhysicalDriveStrings(&lt;span style="color: blue"&gt;ByVal &lt;/span&gt;driveInfo &lt;span style="color: blue"&gt;As &lt;/span&gt;DriveInfo) &lt;span style="color: blue"&gt;As &lt;/span&gt;List(&lt;span style="color: blue"&gt;Of String&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;sfh &lt;span style="color: blue"&gt;As &lt;/span&gt;SafeFileHandle = &lt;span style="color: blue"&gt;Nothing
        Dim &lt;/span&gt;physicalDrives &lt;span style="color: blue"&gt;As New &lt;/span&gt;List(&lt;span style="color: blue"&gt;Of String&lt;/span&gt;)(1)
        &lt;span style="color: blue"&gt;Dim &lt;/span&gt;path &lt;span style="color: blue"&gt;As String &lt;/span&gt;= &lt;span style="color: #a31515"&gt;&amp;quot;\\.\&amp;quot; &lt;/span&gt;&amp;amp; driveInfo.RootDirectory.ToString.TrimEnd(&lt;span style="color: #a31515"&gt;&amp;quot;\&amp;quot;c&lt;/span&gt;)
        &lt;span style="color: blue"&gt;Try
            &lt;/span&gt;sfh = NativeMethods.CreateFile(path, GenericRead, FileShareRead &lt;span style="color: blue"&gt;Or &lt;/span&gt;Filesharewrite, _
                                           IntPtr.Zero, OpenExisting, 0, IntPtr.Zero)
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;bytesReturned &lt;span style="color: blue"&gt;As Integer
            Dim &lt;/span&gt;de1 &lt;span style="color: blue"&gt;As &lt;/span&gt;DiskExtents = &lt;span style="color: blue"&gt;Nothing
            Dim &lt;/span&gt;numDiskExtents &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;result &lt;span style="color: blue"&gt;As Boolean &lt;/span&gt;= NativeMethods.DeviceIoControl(sfh, _
                IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, 0, de1, Marshal.SizeOf(de1), _
                bytesReturned, IntPtr.Zero)
            &lt;span style="color: blue"&gt;If &lt;/span&gt;result = &lt;span style="color: blue"&gt;True Then
                &lt;/span&gt;&lt;span style="color: green"&gt;' there was only one disk extent. So the volume lies on 1 physical drive.
                &lt;/span&gt;physicalDrives.Add(&lt;span style="color: #a31515"&gt;&amp;quot;\\.\PhysicalDrive&amp;quot; &lt;/span&gt;&amp;amp; de1.first.DiskNumber.ToString)
                &lt;span style="color: blue"&gt;Return &lt;/span&gt;physicalDrives
            &lt;span style="color: blue"&gt;End If
            If &lt;/span&gt;Marshal.GetLastWin32Error = IncorrectFunction &lt;span style="color: blue"&gt;Then
                &lt;/span&gt;&lt;span style="color: green"&gt;' The drive is removable and removed, like a CDRom with nothing in it.
                &lt;/span&gt;&lt;span style="color: blue"&gt;Return &lt;/span&gt;physicalDrives
            &lt;span style="color: blue"&gt;End If
            If &lt;/span&gt;Marshal.GetLastWin32Error &amp;lt;&amp;gt; ErrorInsufficientBuffer &lt;span style="color: blue"&gt;Then
                Throw New &lt;/span&gt;Win32Exception
            &lt;span style="color: blue"&gt;End If
            &lt;/span&gt;&lt;span style="color: green"&gt;' The volume is on multiple disks.
            ' Untested...
            ' We need a blob of memory for the DISK_EXTENTS structure, and all the DISK_EXTENTS
            &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;blobSize &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= Marshal.SizeOf(&lt;span style="color: blue"&gt;GetType&lt;/span&gt;(DiskExtents)) + _
                                      (de1.numberOfExtents - 1) * _
                                      Marshal.SizeOf(&lt;span style="color: blue"&gt;GetType&lt;/span&gt;(DiskExtent))
            &lt;span style="color: blue"&gt;Dim &lt;/span&gt;pBlob &lt;span style="color: blue"&gt;As &lt;/span&gt;IntPtr = Marshal.AllocHGlobal(blobSize)
            result = NativeMethods.DeviceIoControl(sfh, IoctlVolumeGetVolumeDiskExtents, _
                IntPtr.Zero, 0, pBlob, blobSize, bytesReturned, IntPtr.Zero)
            &lt;span style="color: blue"&gt;If &lt;/span&gt;result = &lt;span style="color: blue"&gt;False Then Throw New &lt;/span&gt;Win32Exception
            &lt;span style="color: green"&gt;' Read them out one at a time.
            &lt;/span&gt;&lt;span style="color: blue"&gt;Dim &lt;/span&gt;pNext &lt;span style="color: blue"&gt;As New &lt;/span&gt;IntPtr(pBlob.ToInt32 + 4) &lt;span style="color: green"&gt;' is this always ok on 64 bit OSes? ToInt64?
            &lt;/span&gt;&lt;span style="color: blue"&gt;For &lt;/span&gt;i &lt;span style="color: blue"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color: blue"&gt;To &lt;/span&gt;de1.numberOfExtents - 1
                &lt;span style="color: blue"&gt;Dim &lt;/span&gt;diskExtentN &lt;span style="color: blue"&gt;As &lt;/span&gt;DiskExtent = &lt;span style="color: blue"&gt;DirectCast&lt;/span&gt;(Marshal.PtrToStructure(pNext, _
                    &lt;span style="color: blue"&gt;GetType&lt;/span&gt;(DiskExtent)), DiskExtent)
                physicalDrives.Add(&lt;span style="color: #a31515"&gt;&amp;quot;\\.\PhysicalDrive&amp;quot; &lt;/span&gt;&amp;amp; diskExtentN.DiskNumber.ToString)
                pNext = &lt;span style="color: blue"&gt;New &lt;/span&gt;IntPtr(pNext.ToInt32 + Marshal.SizeOf(&lt;span style="color: blue"&gt;GetType&lt;/span&gt;(DiskExtent)))
            &lt;span style="color: blue"&gt;Next
            Return &lt;/span&gt;physicalDrives
        &lt;span style="color: blue"&gt;Finally
            If &lt;/span&gt;sfh &lt;span style="color: blue"&gt;IsNot Nothing Then
                If &lt;/span&gt;sfh.IsInvalid = &lt;span style="color: blue"&gt;False Then
                    &lt;/span&gt;sfh.Close()
                &lt;span style="color: blue"&gt;End If
                &lt;/span&gt;sfh.Dispose()
            &lt;span style="color: blue"&gt;End If
        End Try
    End Function


End Class
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-4753608076306015547?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/4753608076306015547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/make-bootable-usb-flash-drive-from.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4753608076306015547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4753608076306015547'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/make-bootable-usb-flash-drive-from.html' title='Make a bootable USB Flash Drive from a floppy image file (VB.Net)'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-2761880417549272085</id><published>2008-12-24T01:59:00.002Z</published><updated>2008-12-24T02:03:55.708Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='enumerate system tray icons'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='VirtualAllocEx'/><category scheme='http://www.blogger.com/atom/ns#' term='ReadProcessMemory'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>VB.Net enumerate the system tray icons/buttons</title><content type='html'>&lt;p&gt;Another msdn post. This one asked how to get the paths to the icons in the system tray. This sounds pretty simple, but isn't. You can start off by finding the window with Spy++, and then getting a handle to it. Then SendMessage with TB_BUTTONCOUNT to get the number of buttons. (TBBUTTON = &lt;strong&gt;&lt;u&gt;T&lt;/u&gt;&lt;/strong&gt;ask&lt;strong&gt;&lt;u&gt;B&lt;/u&gt;&lt;/strong&gt;ar&lt;strong&gt;&lt;u&gt;B&lt;/u&gt;&lt;/strong&gt;utton). Then you send TB_GETBUTTON repeatedly and get back TBBUTTON structures with information about the buttons. (See the last blog post for info on the x86/x64 mess)&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;typedef struct &lt;/span&gt;_TBBUTTON {    &lt;span style="color:blue;"&gt;int        &lt;/span&gt;iBitmap;
    &lt;span style="color:blue;"&gt;int        &lt;/span&gt;idCommand;
    BYTE     fsState;
    BYTE     fsStyle;
&lt;span style="color:blue;"&gt;#ifdef &lt;/span&gt;_WIN64
    BYTE     bReserved[6]     &lt;span style="color:green;"&gt;// padding for alignment
&lt;/span&gt;&lt;span style="color:blue;"&gt;#elif defined&lt;/span&gt;(_WIN32)
    BYTE     bReserved[2]     &lt;span style="color:green;"&gt;// padding for alignment
&lt;/span&gt;&lt;span style="color:blue;"&gt;#endif
   &lt;/span&gt;DWORD_PTR   dwData;
    INT_PTR          iString;
} TBBUTTON, NEAR *PTBBUTTON *LPTBBUTTON;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The dwData field points to a NOTIFYICONDATA structure with some more gobbledegook:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;typedef struct &lt;/span&gt;_NOTIFYICONDATA {
    DWORD cbSize;
    HWND hWnd;
    UINT uID;
    UINT uFlags;
    UINT uCallbackMessage;
    HICON hIcon;
    TCHAR szTip[64];
    DWORD dwState;
    DWORD dwStateMask;
    TCHAR szInfo[256];
    &lt;span style="color:blue;"&gt;union &lt;/span&gt;{
        UINT uTimeout;
        UINT uVersion;
    };
    TCHAR szInfoTitle[64];
    DWORD dwInfoFlags;
    GUID guidItem;
    HICON hBalloonIcon;
} NOTIFYICONDATA, *PNOTIFYICONDATA;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We don't need all that, so we could trim it down. Earlier versions of windows used a smaller version anyway.&lt;/p&gt;

&lt;p&gt;The difficulty lies in the fact that some of the pointers don't point anywhere useful. Say my process has a button at address 100. That address is local to my process, it has its own virtual memory space. If another process reads that pointer, then the value - 100 - will not mean anything as the other process has its own virtual memory space that maps to a different block of real memory. In our program, we SendMessage to the process hosting the tray buttons asking it to stick a TBBUTTON structure into some memory that is allocated in our home process. Unfortunately the pointer to the memory has no meaning to the other process, so the button goes astray.&lt;/p&gt;

&lt;p&gt;To get around this, we ask the other process to create a blob of memory big enough for a tray button using VirtualAllocEx. Then we SendMessage, asking the other process to put the button into this blob of memory. Finally we read the contents of that memory with ReadProcessMemory:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;tbb &lt;span style="color:blue;"&gt;As New &lt;/span&gt;TBBUTTON32
&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;friendlyTB &lt;span style="color:blue;"&gt;As New &lt;/span&gt;TrayButton
friendlyTB.SetTrayIndex(index)
&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;pButton &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr = IntPtr.Zero
&lt;span style="color:blue;"&gt;Try
    &lt;/span&gt;&lt;span style="color:green;"&gt;' Create memory in the explorer process to store a TBBUTTON strucutre:
    &lt;/span&gt;pButton = VirtualAllocEx(hProcess, &lt;span style="color:blue;"&gt;Nothing&lt;/span&gt;, tbb.Size, MEM_COMMIT, PAGE_READWRITE)
    &lt;span style="color:green;"&gt;' Use SendMessage to request that the memory is filled with the TBBUTTON @ index.
    &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;bResult &lt;span style="color:blue;"&gt;As Boolean &lt;/span&gt;= SendMessage(hwndTrayToolbar, TB_GETBUTTON, index, pButton)
    &lt;span style="color:blue;"&gt;If &lt;/span&gt;bResult = &lt;span style="color:blue;"&gt;False Then Throw New &lt;/span&gt;Win32Exception
    &lt;span style="color:green;"&gt;' And read the memory from the other process:
    &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;bytesReturned &lt;span style="color:blue;"&gt;As Integer
    &lt;/span&gt;bResult = ReadProcessMemory(hProcess, pButton, tbb, tbb.Size, bytesReturned)
    &lt;span style="color:blue;"&gt;If &lt;/span&gt;bResult = &lt;span style="color:blue;"&gt;False Then Throw New &lt;/span&gt;Win32Exception&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here's an app that doesn't work too well as there are many complications to do with animated icons, OSes, x86/x64 that I haven't touched...&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;iframe style="BORDER-RIGHT: #dde5e9 1px solid; PADDING-RIGHT: 0px; BORDER-TOP: #dde5e9 1px solid; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 3px; BORDER-LEFT: #dde5e9 1px solid; WIDTH: 240px; PADDING-TOP: 0px; BORDER-BOTTOM: #dde5e9 1px solid; HEIGHT: 66px; BACKGROUND-COLOR: #ffffff" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/GetTheTray2.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-2761880417549272085?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/2761880417549272085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/vbnet-enumerate-system-tray.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2761880417549272085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2761880417549272085'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/vbnet-enumerate-system-tray.html' title='VB.Net enumerate the system tray icons/buttons'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-6944567861322287196</id><published>2008-12-24T00:56:00.002Z</published><updated>2008-12-24T01:24:10.338Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='x64'/><category scheme='http://www.blogger.com/atom/ns#' term='FieldOffset'/><category scheme='http://www.blogger.com/atom/ns#' term='x86'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='StructLayout'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='Pack'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='structures'/><title type='text'>Structures that vary in size on x86/x64 - what to do?</title><content type='html'>&lt;p&gt;Some structures can be difficult to marshal, as their size varies on x86 compared to x64:&lt;/p&gt;&lt;pre class="code"&gt;typedef struct _TBBUTTON {
   int         iBitmap;
   int         idCommand;
   &lt;span style="color:blue;"&gt;BYTE     &lt;/span&gt;fsState;
   &lt;span style="color:blue;"&gt;BYTE     &lt;/span&gt;fsStyle;
&lt;span style="color:blue;"&gt;#&lt;/span&gt;ifdef _WIN64
   &lt;span style="color:blue;"&gt;BYTE     &lt;/span&gt;bReserved[6]     // padding &lt;span style="color:blue;"&gt;for &lt;/span&gt;alignment
&lt;span style="color:blue;"&gt;#&lt;/span&gt;elif defined(_WIN32)
   &lt;span style="color:blue;"&gt;BYTE     &lt;/span&gt;bReserved[2]     // padding &lt;span style="color:blue;"&gt;for &lt;/span&gt;alignment
&lt;span style="color:blue;"&gt;#endif
   &lt;/span&gt;DWORD_PTR   dwData;
   INT_PTR          iString;
} TBBUTTON, NEAR *PTBBUTTON *LPTBBUTTON;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;&lt;/span&gt; &lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;The layouts in x86 and x64 would look like this:&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;&lt;/span&gt; &lt;/pre&gt;&lt;pre class="code"&gt;&lt;a href="http://lh4.ggpht.com/_qnUNSzxixDU/SVGIodlld7I/AAAAAAAAACY/6qssvh4QFYM/s1600-h/image%5B3%5D.png"&gt;&lt;img style="border: 0px none ;" alt="image" src="http://lh5.ggpht.com/_qnUNSzxixDU/SVGIoyu0HLI/AAAAAAAAACc/Lrm8CUMmCJg/image_thumb%5B1%5D.png?imgmax=800" border="0" width="387" height="340" /&gt;&lt;/a&gt; &lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;&lt;/span&gt; &lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;In C the standard is for, say, an int to stay within a 4 byte boundary of the start of the structure. A short would
not cross a 2 byte boundary. Bytes can go where they like (well, they shouldn't cross the byte boundary, which I
guess they could by having bits spread over 2 bytes!)&lt;/span&gt;&lt;span style="font-family:Trebuchet MS;"&gt; &lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;A pointer on x86 is a 4 byte value, and shouldn't cross a 4 &lt;/span&gt;&lt;span style="font-family:Trebuchet MS;"&gt;byte boundary. A pointer on x64 is an 8 byte value, and
&lt;/span&gt;&lt;span style="font-family:Trebuchet MS;"&gt;shouldn't cross an 8 byte boundary. Phew. Enough about byte boundaries...&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;TBBUTTON causes problems as it has the two BYTE fields in the middle. We need to pad, to get the dwData field
to start at a suitable location. Once it is in the correct place, iString will be fine.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;With .Net we have a few ways to arrange structures. We can use StructLayout(LayoutKind.Sequential, Pack:=x).
Sequential means that .Net is not allowed to move the fields around at runtime, we want them to be arranged
in memory in the order that they appear in our declaration, this will match the C behaviour. Pack allows you to
specify the boundary to align the fields against. Often you would use sequential and pack = 1, then add fields of
padding to get it aligned.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;Alternatively, you can use StructLayout(LayoutKind.Explicit) and hard-code where the fields should go. But,
this will only work if the structures have the same layout in x86 and x64. (Unfortunately you must use a
constant for the field offset, so you can't calculate it at runtime).&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;For TBBUTTON we are stuffed. There is no arrangement of &lt;em&gt;pack&lt;/em&gt; and padding so that "one structure fits all", we will
need 2 declarations. And then we'll choose between them at runtime. (I think it might also be possible to just
compile it for x86 and run it under WOW64 on x64...)&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&amp;lt;StructLayout(LayoutKind.Sequential, Pack:=1)&amp;gt; _
&lt;span style="color:blue;"&gt;Public Structure &lt;/span&gt;TBBUTTON32
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;bitmapIndex &lt;span style="color:blue;"&gt;As Integer
   Public &lt;/span&gt;command &lt;span style="color:blue;"&gt;As Integer
   Public &lt;/span&gt;state &lt;span style="color:blue;"&gt;As &lt;/span&gt;TBStates
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;style &lt;span style="color:blue;"&gt;As &lt;/span&gt;TBStyles
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;padding &lt;span style="color:blue;"&gt;As UShort
   Public &lt;/span&gt;data &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;iString &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;Public Function &lt;/span&gt;Size() &lt;span style="color:blue;"&gt;As Integer
       Return &lt;/span&gt;Marshal.SizeOf(&lt;span style="color:blue;"&gt;Me&lt;/span&gt;)
   &lt;span style="color:blue;"&gt;End Function
End Structure

&lt;/span&gt;&amp;lt;StructLayout(LayoutKind.Sequential, Pack:=1)&amp;gt; _
&lt;span style="color:blue;"&gt;Public Structure &lt;/span&gt;TBBUTTON64
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;bitmapIndex &lt;span style="color:blue;"&gt;As Integer
   Public &lt;/span&gt;command &lt;span style="color:blue;"&gt;As Integer
   Public &lt;/span&gt;state &lt;span style="color:blue;"&gt;As &lt;/span&gt;TBStates
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;style &lt;span style="color:blue;"&gt;As &lt;/span&gt;TBStyles
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;padding1 &lt;span style="color:blue;"&gt;As Integer
   Public &lt;/span&gt;padding2 &lt;span style="color:blue;"&gt;As UShort
   Public &lt;/span&gt;data &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;Public &lt;/span&gt;iString &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;Public Function &lt;/span&gt;Size() &lt;span style="color:blue;"&gt;As Integer
       Return &lt;/span&gt;Marshal.SizeOf(&lt;span style="color:blue;"&gt;Me&lt;/span&gt;)
   &lt;span style="color:blue;"&gt;End Function
End Structure&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;The function is there for convenience. The 6 bytes of padding in the 64 bit version are spread across two variables.
We could equally use field offsets, but it takes a bit longer as you have to calculate them all. Unless you brain finds
that easy. My brain prefers arranging them in blocks and having padding bytes, and doesn't consider the numbers.

&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;One thing that you think might work is the conditional compile thingy in VB.Net:&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;#if Platform="x86"&lt;/span&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="font-family:Trebuchet MS;"&gt;but this depends on the build target, it's not determined at runtime. So again, you would end up with two builds.&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-family:Trebuchet MS;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-6944567861322287196?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/6944567861322287196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/structures-that-vary-in-size-on-x86x64.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/6944567861322287196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/6944567861322287196'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/structures-that-vary-in-size-on-x86x64.html' title='Structures that vary in size on x86/x64 - what to do?'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_qnUNSzxixDU/SVGIoyu0HLI/AAAAAAAAACc/Lrm8CUMmCJg/s72-c/image_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-7843570706956002337</id><published>2008-12-23T16:00:00.001Z</published><updated>2008-12-23T16:00:20.443Z</updated><title type='text'>So, ...</title><content type='html'>&lt;p&gt;I must stop this. Looking back at my posts, and at forum posts it seems I start far too many new paragraphs with &amp;quot;So, ...&amp;quot;. I wonder if it crept in to my TMAs? &lt;/p&gt;  &lt;p&gt;Therefore, I will keep an eye out for it. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-7843570706956002337?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/7843570706956002337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/so.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/7843570706956002337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/7843570706956002337'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/so.html' title='So, ...'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3421247004530052131</id><published>2008-12-23T01:32:00.003Z</published><updated>2008-12-23T01:40:17.471Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER'/><category scheme='http://www.blogger.com/atom/ns#' term='Get usb flash drive serial'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='ufd serial'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER - VB.Net - might be incorrect</title><content type='html'>For anyone trying to get IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER to work.

The following would return an error about the buffer being too small, if the device supports the call, and if I haven't made a mistake. I get "The request is not supported", which seems to be what other folks are saying. It seems no USB Flash drives actually support this call, I've tried with a secure sandisk one.

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;Option Strict On
Option Explicit On
Option Infer Off

Imports &lt;/span&gt;Microsoft.Win32.SafeHandles
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.Runtime.InteropServices
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.ComponentModel

&lt;span style="color:blue;"&gt;Public Class &lt;/span&gt;Form1

  &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER &lt;span style="color:blue;"&gt;As UInteger &lt;/span&gt;= &amp;amp;HED0000

  &amp;lt;Flags()&amp;gt; _
  &lt;span style="color:blue;"&gt;Private Enum &lt;/span&gt;AccessRights &lt;span style="color:blue;"&gt;As UInteger
      &lt;/span&gt;GenericRead = &amp;amp;H80000000UI
      GenericWrite = &amp;amp;H40000000
      GenericExecute = &amp;amp;H20000000
      GenericAll = &amp;amp;H10000000
  &lt;span style="color:blue;"&gt;End Enum

  &lt;/span&gt;&amp;lt;Flags()&amp;gt; _
  &lt;span style="color:blue;"&gt;Private Enum &lt;/span&gt;ShareModes &lt;span style="color:blue;"&gt;As UInteger
      &lt;/span&gt;FileShareRead = 1
      FileShareWrite = 2
      FileShareDelete = 4
  &lt;span style="color:blue;"&gt;End Enum

  Private Enum &lt;/span&gt;CreationDisposition &lt;span style="color:blue;"&gt;As UInteger
      &lt;/span&gt;CreateNew = 1
      CreateAlways = 2
      OpenExisting = 3
      OpenAlways = 4
      TruncateExisting = 5
  &lt;span style="color:blue;"&gt;End Enum

  &lt;/span&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
  &lt;span style="color:blue;"&gt;Private Structure &lt;/span&gt;MediaSerialNumberData
      &lt;span style="color:blue;"&gt;Public &lt;/span&gt;SerialNumberLength &lt;span style="color:blue;"&gt;As UInteger
      Public &lt;/span&gt;Result &lt;span style="color:blue;"&gt;As UInteger
      Public &lt;/span&gt;Reserved &lt;span style="color:blue;"&gt;As &lt;/span&gt;UInt64
      &lt;span style="color:blue;"&gt;Public &lt;/span&gt;SerialNumberData &lt;span style="color:blue;"&gt;As Byte &lt;/span&gt;&lt;span style="color:green;"&gt;' We would get the 1st byte, if any UFDs actually worked.
      &lt;/span&gt;&lt;span style="color:blue;"&gt;Public Function &lt;/span&gt;Size() &lt;span style="color:blue;"&gt;As Integer
          Return &lt;/span&gt;Marshal.SizeOf(&lt;span style="color:blue;"&gt;Me&lt;/span&gt;)
      &lt;span style="color:blue;"&gt;End Function
  End Structure

  &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"kernel32"&lt;/span&gt;, CharSet:=CharSet.Unicode, SetLastError:=&lt;span style="color:blue;"&gt;True&lt;/span&gt;)&amp;gt; _
  &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;CreateFile( _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;fileName &lt;span style="color:blue;"&gt;As String&lt;/span&gt;, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;desiredAccess &lt;span style="color:blue;"&gt;As &lt;/span&gt;AccessRights, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;shareMode &lt;span style="color:blue;"&gt;As &lt;/span&gt;ShareModes, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;securityAttributes &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;creationDisposition &lt;span style="color:blue;"&gt;As &lt;/span&gt;CreationDisposition, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;flagsAndAttributes &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hTemplateFile &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle
  &lt;span style="color:blue;"&gt;End Function

  &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"kernel32"&lt;/span&gt;, SetLastError:=&lt;span style="color:blue;"&gt;True&lt;/span&gt;)&amp;gt; _
  &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;DeviceIoControl( _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hVol &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;controlCode &lt;span style="color:blue;"&gt;As UInteger&lt;/span&gt;, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;inBuffer &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;inBufferSize &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
  &lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;outBuffer &lt;span style="color:blue;"&gt;As &lt;/span&gt;MediaSerialNumberData, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;outBufferSize &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
  &lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;bytesReturned &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
  &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;overlapped &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color:blue;"&gt;Boolean
  End Function

  Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;sender &lt;span style="color:blue;"&gt;As Object&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;e &lt;span style="color:blue;"&gt;As &lt;/span&gt;EventArgs) &lt;span style="color:blue;"&gt;Handles MyBase&lt;/span&gt;.Load
      &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;sfh &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle = &lt;span style="color:blue;"&gt;Nothing
      Try
          &lt;/span&gt;sfh = CreateFile(&lt;span style="color: rgb(163, 21, 21);"&gt;"//./H:"&lt;/span&gt;, AccessRights.GenericRead, _
                           ShareModes.FileShareRead &lt;span style="color:blue;"&gt;Or &lt;/span&gt;_
                           ShareModes.FileShareWrite, _
                           IntPtr.Zero, _
                           CreationDisposition.OpenExisting, _
                           0, IntPtr.Zero)
          &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;msnd &lt;span style="color:blue;"&gt;As New &lt;/span&gt;MediaSerialNumberData
          &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;returned &lt;span style="color:blue;"&gt;As Integer
          Dim &lt;/span&gt;result &lt;span style="color:blue;"&gt;As Boolean &lt;/span&gt;= DeviceIoControl(sfh, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, _
                                                  IntPtr.Zero, 0, msnd, msnd.Size, returned, IntPtr.Zero)
          &lt;span style="color:blue;"&gt;If &lt;/span&gt;result = &lt;span style="color:blue;"&gt;False Then
              &lt;/span&gt;Console.WriteLine((&lt;span style="color:blue;"&gt;New &lt;/span&gt;Win32Exception).Message)
          &lt;span style="color:blue;"&gt;End If
      Catch &lt;/span&gt;ex &lt;span style="color:blue;"&gt;As &lt;/span&gt;Exception
          Console.WriteLine(ex.Message)
      &lt;span style="color:blue;"&gt;Finally
          If &lt;/span&gt;sfh &lt;span style="color:blue;"&gt;IsNot Nothing Then
              If &lt;/span&gt;sfh.IsInvalid = &lt;span style="color:blue;"&gt;False Then
                  If &lt;/span&gt;sfh.IsClosed = &lt;span style="color:blue;"&gt;False Then
                      &lt;/span&gt;sfh.Close()
                  &lt;span style="color:blue;"&gt;End If
              End If
              &lt;/span&gt;sfh.Dispose()
          &lt;span style="color:blue;"&gt;End If
      End Try

  End Sub

End Class
&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3421247004530052131?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3421247004530052131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/ioctlstoragegetmediaserialnumber-vbnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3421247004530052131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3421247004530052131'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/ioctlstoragegetmediaserialnumber-vbnet.html' title='IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER - VB.Net - might be incorrect'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-8660897026438024590</id><published>2008-12-22T13:30:00.002Z</published><updated>2008-12-22T15:45:32.059Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open University'/><category scheme='http://www.blogger.com/atom/ns#' term='M450'/><category scheme='http://www.blogger.com/atom/ns#' term='M450 Project choice'/><title type='text'>M450 Project</title><content type='html'>&lt;p&gt;Well, I've signed up for my final 3 open university courses for the B29 degree. M450 (project), M359 (database), M363 (mishmash - seems to be mainly about requirements gathering, planning and design). And I'm straight in at the deep end, as there are only a few days left to come up with an M450 project idea. &lt;/p&gt;  &lt;p&gt;The M450 bumph says we should spend about 300 hours on the course. The project must have some challenges - challenges that require looking at some papers! The 300 hours includes the time to answer the TMAs and do the research. So - nothing too complicated, and nothing too simple. It's hard to get something "just right". It also seems to be hinting that it is useful to have a client, or imaginary-client, so that we can assess the stages of development. &lt;/p&gt;  &lt;p&gt;I had kept notes of interesting ideas whilst doing the AI course. I was interested in the idea of using a neural network to do colour quantisation - reduce the amount of colour information in a picture. But, I've discovered that is old-hat and it is even part of the java library. Groan. &lt;/p&gt;  &lt;p&gt;Then I thought about doing a genetic algorithm to control some arcade game - snake and lunar lander were ideas as they are self-contained and simple games. But they have both been done. I kinda hoped to do a solver for the Times Killer Sudoku (soduku itself has been done to death), but there are now several solvers for that out there too. That would have been interesting - to compare all the different search and rules techniques. Then I thought about maybe rotating photos round the correct way using a neural network to detect the correct orientation. I figured that it wouldn't work for any old photo, so I would narrow it down to portraits or pictures of houses. For portraits, hopefully it would get the general idea that the blob of face colour should be somewhere in the top middle. For houses I thought of the scenario of an estate agent wanting to automatically rotate the images as they come in from the camera. (Why don't cameras have a built in spirit level and tag the images with the orientation? Patent the idea quick!!). The nn would be able to detect the block of sky. But - nope, that's been done to death too. I'm thinking that maybe finding any application for AI is a bit tricky. &lt;/p&gt;  &lt;p&gt;So, that leaves the other choice - M362. There we could have some threading thing or go for a distributed application. I wrote a program to track patients psa blood test results. The idea is that the clinic is clogged up with gentlemen who come in, see the doctor, who glances at the blood results (which are taken to ensure that cancer has not recurred, if it has then the levels will be high), (s)he sees they are normal, has a bit of a chat about the weather and waves goodbye to the patient. This is a waste of time, "clinics cost money", and there are - of course - waiting lists to consider. The consultant needs to see the blood test, but not the patient. So, enter the program, it tracks the blood results and creates documents for the GP - to tell them the patient has entered remote follow up, to request that blood be taken, and to recall patients to clinic to be seen by the consultant. I wrote the standalone program a few years ago, and it was nominated for the HSJ awards this year (black tie dinner on Park Lane, don't'cha'know). We didn't win, I think we were short-listed to encourage other small projects that have a big effect (the program has saved the NHS at least £100,000), most of the other projects were on a bigger scale. &lt;/p&gt;  &lt;p&gt;So, my proposal would be to investigate the use of JavaEE for the program. The hospital is interested in getting the program on the network, so I think that it would be a good opportunity to evaluate JavaEE. As the program itself is quite large, I would write a simplified version for the OU project - I would be creating a prototype n-tier version of the program. I would create a database, simplified logic, and concentrate on the web and client tier. None of the original program would be used, as it is in the wrong language, and old. But is this enough? What's the challenge? Which papers etc would I reference and work through? &amp;lt;sigh&amp;gt; Is creating a database application enough of a "challenge". Getting a program right is hard work, and I'll have to learn lots of new stuff - but I'll be investigating well-trodden paths and following well written instructions -- so is that good enough? &lt;/p&gt;  &lt;p&gt;I've found an old board game that has little written about it on the web. I could only find 1 AI implementation for it, and that's a mac program - alien to me. Maybe I'll just do that. It might be more interesting. Research would be needed - all the papers on making AIs for chess, checkers, etc would be helpful. Writing the game itself would be half the challenge. There would be plenty of stuff to do and to talk about.&lt;/p&gt;  &lt;p&gt;Time is running out, and Xmas is eating in to all my spare time.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-8660897026438024590?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/8660897026438024590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/m450-project.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/8660897026438024590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/8660897026438024590'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/m450-project.html' title='M450 Project'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-2145388038217639509</id><published>2008-12-22T12:55:00.001Z</published><updated>2009-01-25T15:07:15.252Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SD Card'/><category scheme='http://www.blogger.com/atom/ns#' term='WDK'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CID'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CSD'/><title type='text'>Read SD Card CID (serial number)</title><content type='html'>I just moved blogs, so here's an overview of the SD card CID stuff.

I've had some success reading the CID from an SD Card: &lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_qnUNSzxixDU/SU-QUr1bE4I/AAAAAAAAAAM/UePWb0SDt7g/s1600-h/cids.png"&gt;&lt;img id="BLOGGER_PHOTO_ID_5282599572967461762" style="margin: 0pt 10px 10px 0pt; float: left; width: 400px; cursor: pointer; height: 397px;" alt="" src="http://3.bp.blogspot.com/_qnUNSzxixDU/SU-QUr1bE4I/AAAAAAAAAAM/UePWb0SDt7g/s400/cids.png" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Where:
&lt;/p&gt;&lt;p&gt;1) The OS is XP or Vista
2) The device is not attached via any USB gizmo. It works only in a card reader attached directly to the PCI bus. (Can scsi pass through get around this? It's not an ATA or SCSI command...)
3) Admin privileges...&lt;/p&gt;
&lt;p&gt;What &lt;strong&gt;&lt;u&gt;not&lt;/u&gt;&lt;/strong&gt; to do:&lt;/p&gt;&lt;p&gt;&lt;span style=";font-family:Courier New;font-size:100%;"  &gt;1) IOCTL_DISK_GET_STORAGEID
2) GetFileInformationByHandle&lt;/span&gt;&lt;/p&gt;&lt;p&gt;As both these return a number assigned when the volume is created. It will change next time the drive is formatted.

What I did:&lt;/p&gt;&lt;p&gt;Use IOCTL_SFFDISK_DEVICE_COMMAND to send command 10 (see the SD spec).
&lt;/p&gt;&lt;p&gt;&lt;a href="http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-secure-digital-sd-card-serial.html" target="_blank"&gt;Read Secure Digital (SD) Card Serial Number from CID&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://jo0ls-dotnet-stuff.blogspot.com/2008/12/sd-card-read-cidserial-number-musings.html" target="_blank"&gt;SD Card Musings&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-cid-and-csd-c-implementation.html" target="_blank"&gt;Read CID and CSD C# implementation&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;iframe style="border: 1px solid rgb(221, 229, 233); margin: 3px; padding: 0px; width: 240px; height: 66px; background-color: rgb(255, 255, 255);" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/JDMcF.SDCard.zip" scrolling="no" frameborder="0"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Pocket PC?&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.tech-archive.net/Archive/PocketPC/microsoft.public.pocketpc.developer/2004-09/1563.html" target="_blank"&gt;I don't think it works&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The Future?&lt;/p&gt;&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/IEEE_1667" target="_blank"&gt;IEEE 1667&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-2145388038217639509?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/2145388038217639509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-sd-card-cid-serial-number.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2145388038217639509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2145388038217639509'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-sd-card-cid-serial-number.html' title='Read SD Card CID (serial number)'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_qnUNSzxixDU/SU-QUr1bE4I/AAAAAAAAAAM/UePWb0SDt7g/s72-c/cids.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-215921107356845983</id><published>2008-12-22T12:18:00.002Z</published><updated>2008-12-22T15:32:40.207Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='paste as html'/><category scheme='http://www.blogger.com/atom/ns#' term='live writer'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Paste from Visual studio</title><content type='html'>&lt;pre class="code"&gt;0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;That's using the paste from visual studio plug-in for microsoft's live writer. Tells me the width of this blog. I can then make a guide line appear in the IDE using a registry hack, see&lt;/p&gt;

&lt;p&gt;Sarah Ford's weblog - &lt;a href="http://blogs.msdn.com/saraford/archive/2004/11/15/257953.aspx" target="_blank"&gt;"Guidelines – a hidden feature for the Visual Studio Editor"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(I remember why I didn't use blogger originally -- there's not much room, and I can't be bothered to mess with the templates).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-215921107356845983?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/215921107356845983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/paste-from-visual-studio.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/215921107356845983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/215921107356845983'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/paste-from-visual-studio.html' title='Paste from Visual studio'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-8796426469291946628</id><published>2008-12-22T12:03:00.002Z</published><updated>2008-12-22T16:19:47.906Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='blogger'/><category scheme='http://www.blogger.com/atom/ns#' term='jo0ls&apos; stuff'/><category scheme='http://www.blogger.com/atom/ns#' term='live spaces'/><title type='text'>Moving to blogger</title><content type='html'>&lt;p&gt;I'm sick of Live spaces, as nothing turns up on google searches. Lets see how blogger compares. I'll probably use some of the live spaces facilities such as the file storage...&lt;/p&gt;&lt;p&gt;There will be a brief period of frenzied activity as I move some old posts here.&lt;/p&gt;&lt;p&gt;(Edit: Ok, moved and back dated, which is why this post makes little sense.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-8796426469291946628?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/8796426469291946628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/moving-to-blogger.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/8796426469291946628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/8796426469291946628'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/moving-to-blogger.html' title='Moving to blogger'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-5342135717714885457</id><published>2008-12-16T15:36:00.000Z</published><updated>2008-12-22T15:39:07.652Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='structure'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='field offset'/><title type='text'>Determine the layout of a structure for .Net Platform Invoke</title><content type='html'>&lt;p&gt;I was trying to create a signature for NOTIFYICONDATA, and decided to see what I could find out about it with C++. &lt;/p&gt;&lt;p&gt;1) start a new c++ CLR Console project in visual studio. Name it whatever you like.
2) Alter stdafx.h:&lt;/p&gt;&lt;pre&gt;&lt;span style="color:blue;"&gt;#pragma once
#define &lt;/span&gt;STRICT
&lt;span style="color:blue;"&gt;#include &lt;/span&gt;&lt;span style="COLOR: rgb(163,21,21)"&gt;&amp;lt;windows.h&amp;gt;   &lt;/span&gt;&lt;span style="color:green;"&gt;// common Win32 stuff
&lt;/span&gt;&lt;span style="color:blue;"&gt;#include &lt;/span&gt;&lt;span style="COLOR: rgb(163,21,21)"&gt;&amp;lt;commctrl.h&amp;gt;  &lt;/span&gt;&lt;span style="color:green;"&gt;// defines the structure we are interseted in
&lt;/span&gt;&lt;span style="color:blue;"&gt;#include &lt;/span&gt;&lt;span style="COLOR: rgb(163,21,21)"&gt;&amp;lt;stddef.h&amp;gt;    &lt;/span&gt;&lt;span style="color:green;"&gt;// we use offsetof
&lt;/span&gt;&lt;span style="color:blue;"&gt;using namespace &lt;/span&gt;System;  &lt;span style="color:green;"&gt;// .Net types&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;3) in main, you can create a structure and determine its size. You can also find the offset for each field in the structure. Then you can swap the build to x64 and see what size they should be on x64 systems. This is definitely useful for when you want to create a managed C# or VB.Net version of the structure. &lt;/p&gt;&lt;pre&gt;&lt;span style="color:blue;"&gt;#include &lt;/span&gt;&lt;span style="COLOR: rgb(163,21,21)"&gt;"stdafx.h"

&lt;/span&gt;&lt;span style="color:blue;"&gt;using namespace &lt;/span&gt;System;

&lt;span style="color:blue;"&gt;int &lt;/span&gt;main(&lt;span style="color:blue;"&gt;array&lt;/span&gt;&amp;lt;System::String ^&amp;gt; ^args)
{
    NOTIFYICONDATA tbb;
    &lt;span style="color:blue;"&gt;int &lt;/span&gt;i = &lt;span style="color:blue;"&gt;sizeof&lt;/span&gt;(tbb);
    Console::WriteLine(i);   
    Console::WriteLine(offsetof(NOTIFYICONDATA,cbSize));
    Console::WriteLine(offsetof(NOTIFYICONDATA,hWnd));
    Console::WriteLine(offsetof(NOTIFYICONDATA,uID));
    Console::WriteLine(offsetof(NOTIFYICONDATA,uFlags));
    Console::WriteLine(offsetof(NOTIFYICONDATA,uCallbackMessage));
    Console::WriteLine(offsetof(NOTIFYICONDATA,hIcon));
    Console::WriteLine(offsetof(NOTIFYICONDATA,szTip));
    Console::WriteLine(offsetof(NOTIFYICONDATA,dwState));
    Console::WriteLine(offsetof(NOTIFYICONDATA,dwStateMask));
    Console::WriteLine(offsetof(NOTIFYICONDATA,szInfo));
    Console::WriteLine(offsetof(NOTIFYICONDATA,uTimeout));
    Console::WriteLine(offsetof(NOTIFYICONDATA,szInfoTitle));
    Console::WriteLine(offsetof(NOTIFYICONDATA,dwInfoFlags));
    Console::WriteLine(offsetof(NOTIFYICONDATA,guidItem));
    Console::WriteLine(offsetof(NOTIFYICONDATA,hBalloonIcon));
    Console::ReadKey();
    &lt;span style="color:blue;"&gt;return &lt;/span&gt;0;
}&lt;/pre&gt;Ugly, but it works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-5342135717714885457?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/5342135717714885457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/determine-layout-of-structure-for-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/5342135717714885457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/5342135717714885457'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/determine-layout-of-structure-for-net.html' title='Determine the layout of a structure for .Net Platform Invoke'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3851522659806751112</id><published>2008-12-13T13:23:00.000Z</published><updated>2008-12-22T15:46:44.927Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open University'/><category scheme='http://www.blogger.com/atom/ns#' term='B29'/><category scheme='http://www.blogger.com/atom/ns#' term='B29 Calculator'/><category scheme='http://www.blogger.com/atom/ns#' term='Results'/><category scheme='http://www.blogger.com/atom/ns#' term='Open university first class server address'/><title type='text'>Open University - story so far</title><content type='html'>&lt;span id="ctl00_MainContentPlaceholder_ctl01_ctl00_lblEntry"&gt;   &lt;div&gt;I can never find this:&lt;/div&gt;    &lt;div&gt;Open university first class server address: oufcnt2.open.ac.uk   
  
This is handy:&lt;/div&gt;    &lt;div&gt;B29 course calculator &lt;a href="http://www.subrosauk.com/ou/b29grade.html"&gt;&lt;span style="color: rgb(0, 102, 204);"&gt;http://www.subrosauk.com/ou/b29grade.html&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;    &lt;div&gt; &lt;/div&gt;    &lt;div&gt;My results so far... &lt;/div&gt;    &lt;div&gt;
(OES/OCAS)    
  
&lt;/div&gt;    &lt;div&gt;T175 "Networked living: exploring information and communication technologies" - (89/94)&lt;/div&gt;    &lt;div&gt;MST121 "Using Mathematics" - (94/92)   
&lt;/div&gt;    &lt;div&gt;M150 "Data, computing and information" - (OCAS 95)&lt;/div&gt;    &lt;div&gt;M253 "Team working in distributed environments" - (78/86)&lt;/div&gt;    &lt;div&gt;M255 "Object-oriented programming with Java" - (91/96) Distinction   
M256 "Software development with Java" - (86/95) Distinction    
M257 "Putting Java to work" - (87/96) Distinction    
&lt;/div&gt;    &lt;div&gt;M263 "Building blocks of software" - (82/97) Distinction    
M362 "Developing concurrent distributed systems" - (88/95) Distinction    
&lt;/div&gt;    &lt;div&gt;M366 "Natural and Artificial Intelligence" - (93/96) Distinction   
&lt;/div&gt;    &lt;div&gt;   
&lt;/div&gt;    &lt;p&gt;Starting early 2009:   
  
M359 "Relational databases: theory and practice"    
M363 "Software engineering with objects"    
M450 "The computing project"&lt;/p&gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3851522659806751112?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3851522659806751112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/open-university-story-so-far.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3851522659806751112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3851522659806751112'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/open-university-story-so-far.html' title='Open University - story so far'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3690973355800739664</id><published>2008-12-10T15:41:00.000Z</published><updated>2008-12-22T15:42:01.573Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='global keyboard hook'/><title type='text'>VB.Net Global keyboard hook to detect "print screen" keypress</title><content type='html'>&lt;p&gt;As described...&lt;/p&gt;&lt;pre&gt;&lt;span style="color:blue;"&gt;Option Strict On
Option Explicit On

Imports &lt;/span&gt;System.Runtime.InteropServices

&lt;span style="color:blue;"&gt;Public Class &lt;/span&gt;Form1

    &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;WH_KEYBOARD_LL &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 13
    &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;WM_KEYUP &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= &amp;amp;H101
    &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;WM_SYSKEYUP &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= &amp;amp;H105
    &lt;span style="color:blue;"&gt;Private &lt;/span&gt;proc &lt;span style="color:blue;"&gt;As &lt;/span&gt;LowLevelKeyboardProcDelegate = &lt;span style="color:blue;"&gt;AddressOf &lt;/span&gt;HookCallback
    &lt;span style="color:blue;"&gt;Private &lt;/span&gt;hookID &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr

    &lt;span style="color:blue;"&gt;Private Delegate Function &lt;/span&gt;LowLevelKeyboardProcDelegate(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;nCode &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;wParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
        &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;lParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr

    &amp;lt;DllImport(&lt;span style="COLOR: rgb(163,21,21)"&gt;"user32"&lt;/span&gt;)&amp;gt; _
    &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;SetWindowsHookEx(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;idHook &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;lpfn &lt;span style="color:blue;"&gt;As &lt;/span&gt;LowLevelKeyboardProcDelegate, _
        &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hMod &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;dwThreadId &lt;span style="color:blue;"&gt;As UInteger&lt;/span&gt;) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
    &lt;span style="color:blue;"&gt;End Function

    &lt;/span&gt;&amp;lt;DllImport(&lt;span style="COLOR: rgb(163,21,21)"&gt;"user32.dll"&lt;/span&gt;)&amp;gt; _
    &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;UnhookWindowsHookEx(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hhk &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color:blue;"&gt;Boolean
    End Function

    &lt;/span&gt;&amp;lt;DllImport(&lt;span style="COLOR: rgb(163,21,21)"&gt;"user32.dll"&lt;/span&gt;)&amp;gt; _
    &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;CallNextHookEx(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hhk &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;nCode &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;wParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;_
        ByVal &lt;/span&gt;lParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
    &lt;span style="color:blue;"&gt;End Function

    &lt;/span&gt;&amp;lt;DllImport(&lt;span style="COLOR: rgb(163,21,21)"&gt;"kernel32.dll"&lt;/span&gt;, CharSet:=CharSet.Unicode)&amp;gt; _
    &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;GetModuleHandle(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;lpModuleName &lt;span style="color:blue;"&gt;As String&lt;/span&gt;) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
    &lt;span style="color:blue;"&gt;End Function

    Sub New&lt;/span&gt;()
        &lt;span style="color:green;"&gt;' This call is required by the Windows Form Designer.
        &lt;/span&gt;InitializeComponent()
        &lt;span style="color:green;"&gt;' Add any initialization after the InitializeComponent() call.
        &lt;/span&gt;hookID = SetHook(proc)
    &lt;span style="color:blue;"&gt;End Sub

    Private Sub &lt;/span&gt;Form1_FormClosing(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;sender &lt;span style="color:blue;"&gt;As Object&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;e &lt;span style="color:blue;"&gt;As &lt;/span&gt;FormClosingEventArgs) &lt;span style="color:blue;"&gt;Handles Me&lt;/span&gt;.FormClosing
        UnhookWindowsHookEx(hookID)
    &lt;span style="color:blue;"&gt;End Sub

    Private Function &lt;/span&gt;SetHook(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;proc &lt;span style="color:blue;"&gt;As &lt;/span&gt;LowLevelKeyboardProcDelegate) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
        &lt;span style="color:blue;"&gt;Using &lt;/span&gt;curProcess &lt;span style="color:blue;"&gt;As &lt;/span&gt;Process = Process.GetCurrentProcess()
            &lt;span style="color:blue;"&gt;Using &lt;/span&gt;curModule &lt;span style="color:blue;"&gt;As &lt;/span&gt;ProcessModule = curProcess.MainModule
                &lt;span style="color:blue;"&gt;Return &lt;/span&gt;SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0)
            &lt;span style="color:blue;"&gt;End Using
        End Using
    End Function

    Private Function &lt;/span&gt;HookCallback(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;nCode &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;wParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;lParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
        &lt;span style="color:green;"&gt;' we check keyup for standard printscreen, and syskeyup incase it is alt+printscreen
        ' we aren't checking keydown, as that fires before the screenshot is taken.
        &lt;/span&gt;&lt;span style="color:blue;"&gt;If &lt;/span&gt;nCode &amp;gt;= 0 &lt;span style="color:blue;"&gt;AndAlso &lt;/span&gt;(wParam.ToInt32 = WM_KEYUP &lt;span style="color:blue;"&gt;OrElse &lt;/span&gt;wParam.ToInt32 = WM_SYSKEYUP) &lt;span style="color:blue;"&gt;Then
            Dim &lt;/span&gt;vkCode &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= Marshal.ReadInt32(lParam)
            &lt;span style="color:blue;"&gt;If &lt;/span&gt;vkCode = Keys.PrintScreen &lt;span style="color:blue;"&gt;Then
                Dim &lt;/span&gt;data &lt;span style="color:blue;"&gt;As &lt;/span&gt;IDataObject = Clipboard.GetDataObject()
                &lt;span style="color:blue;"&gt;If &lt;/span&gt;data.GetDataPresent(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(Bitmap)) &lt;span style="color:blue;"&gt;Then
                    Me&lt;/span&gt;.BackgroundImage = &lt;span style="color:blue;"&gt;DirectCast&lt;/span&gt;(data.GetData(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(Bitmap)), Bitmap)
                &lt;span style="color:blue;"&gt;End If
            End If
        End If
        Return &lt;/span&gt;CallNextHookEx(hookID, nCode, wParam, lParam)
    &lt;span style="color:blue;"&gt;End Function

End Class

&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3690973355800739664?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3690973355800739664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/vbnet-global-keyboard-hook-to-detect.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3690973355800739664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3690973355800739664'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/vbnet-global-keyboard-hook-to-detect.html' title='VB.Net Global keyboard hook to detect &amp;quot;print screen&amp;quot; keypress'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-253465533288668909</id><published>2008-12-10T12:00:00.000Z</published><updated>2008-12-22T15:44:24.082Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='SetClipBoardViewer'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>SetClipboardViewer API VB.NET</title><content type='html'>This registers a form as a clipboard viewer. It then recieves notification when something happens to the clipboard. Some post on the msdn forum. It mentioned: http://www.radsoftware.com.au/articles/ClipboardMonitor_VB.txt, which I've tidied up to my liking (a stray long, a strange cast removed, you can't override Dispose (could you before?))   &lt;pre&gt;&lt;span style="color:blue;"&gt;Option Strict On
Option Explicit On

Imports &lt;/span&gt;System.Runtime.InteropServices

&lt;span style="color:blue;"&gt;Public Class &lt;/span&gt;Form1

   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;WM_DRAWCLIPBOARD &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= &amp;amp;H308
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;WM_CHANGECBCHAIN &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= &amp;amp;H30D

   &lt;span style="color:blue;"&gt;Private &lt;/span&gt;mNextClipBoardViewerHWnd &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;Private Event &lt;/span&gt;OnClipboardChanged()

   &amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"user32"&lt;/span&gt;)&amp;gt; _
   &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;SetClipboardViewer(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hWnd &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;End Function

   &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"user32"&lt;/span&gt;)&amp;gt; _
   &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;ChangeClipboardChain(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hWnd &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hWndNext &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;_
       &amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color:blue;"&gt;Boolean
   End Function

   &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"user32"&lt;/span&gt;)&amp;gt; _
   &lt;span style="color:blue;"&gt;Private Shared Function &lt;/span&gt;SendMessage(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hWnd &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;msg &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;wParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, &lt;span style="color:blue;"&gt;_
       ByVal &lt;/span&gt;lParam &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr
   &lt;span style="color:blue;"&gt;End Function

   Sub New&lt;/span&gt;()
       InitializeComponent()
       mNextClipBoardViewerHWnd = SetClipboardViewer(&lt;span style="color:blue;"&gt;Me&lt;/span&gt;.Handle)
       &lt;span style="color:blue;"&gt;AddHandler Me&lt;/span&gt;.OnClipboardChanged, &lt;span style="color:blue;"&gt;AddressOf &lt;/span&gt;ClipBoardChanged
   &lt;span style="color:blue;"&gt;End Sub

   Protected Overrides Sub &lt;/span&gt;WndProc(&lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;m &lt;span style="color:blue;"&gt;As &lt;/span&gt;Message)
       &lt;span style="color:blue;"&gt;Select Case &lt;/span&gt;m.Msg
           &lt;span style="color:blue;"&gt;Case &lt;/span&gt;WM_DRAWCLIPBOARD
               &lt;span style="color:blue;"&gt;RaiseEvent &lt;/span&gt;OnClipboardChanged()
               SendMessage(mNextClipBoardViewerHWnd, m.Msg, m.WParam, m.LParam)

           &lt;span style="color:blue;"&gt;Case &lt;/span&gt;WM_CHANGECBCHAIN
               &lt;span style="color:blue;"&gt;If &lt;/span&gt;m.WParam.Equals(mNextClipBoardViewerHWnd) &lt;span style="color:blue;"&gt;Then
                   &lt;/span&gt;mNextClipBoardViewerHWnd = m.LParam
               &lt;span style="color:blue;"&gt;Else
                   &lt;/span&gt;SendMessage(mNextClipBoardViewerHWnd, m.Msg, m.WParam, m.LParam)
               &lt;span style="color:blue;"&gt;End If
       End Select
       MyBase&lt;/span&gt;.WndProc(m)
   &lt;span style="color:blue;"&gt;End Sub

   Private Sub &lt;/span&gt;ClipBoardChanged()
       &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;data &lt;span style="color:blue;"&gt;As &lt;/span&gt;IDataObject = Clipboard.GetDataObject()
       &lt;span style="color:blue;"&gt;If &lt;/span&gt;data.GetDataPresent(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(Bitmap)) &lt;span style="color:blue;"&gt;Then
           Me&lt;/span&gt;.BackgroundImage = &lt;span style="color:blue;"&gt;DirectCast&lt;/span&gt;(data.GetData(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(Bitmap)), Bitmap)
       &lt;span style="color:blue;"&gt;End If
   End Sub

   Private Sub &lt;/span&gt;Form1_FormClosing(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;sender &lt;span style="color:blue;"&gt;As Object&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;e &lt;span style="color:blue;"&gt;As &lt;/span&gt;FormClosingEventArgs) &lt;span style="color:blue;"&gt;Handles Me&lt;/span&gt;.FormClosing
       ChangeClipboardChain(&lt;span style="color:blue;"&gt;Me&lt;/span&gt;.Handle, mNextClipBoardViewerHWnd)
   &lt;span style="color:blue;"&gt;End Sub

End Class
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;To use: start a few instances of the program. Copy an image into the clipboard - the backgrounds of the forms should change. Then close one of the forms and change the image in the clipboard - all the backgrounds should change.
 &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-253465533288668909?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/253465533288668909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/setclipboardviewer-api-vbnet.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/253465533288668909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/253465533288668909'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/setclipboardviewer-api-vbnet.html' title='SetClipboardViewer API VB.NET'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3825000455104564462</id><published>2008-11-30T15:54:00.000Z</published><updated>2008-12-22T15:56:21.590Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CID'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CSD'/><title type='text'>Read CID and CSD C# implementation.</title><content type='html'>&lt;p&gt;
Ok, here goes. It's pretty huge, so I'll just post the important bits and post a download link to the source at the bottom. I've not yet started on getting overlap to work. YOU HAVE TO SET THE BUILD TARGET TO x86. (if you have an express edition then you'll need to expose the configuration manager first - its in the settings somewhere - "show advanced build options" or something).
&lt;/p&gt;&lt;p&gt;(Remember this is Windows XP/Vista, Admin privileges required, build target must be x86, SD card must be attached via an SD reader connected directly to the PCI host - no USB reader...)
&lt;/p&gt;&lt;p&gt;First up... &lt;/p&gt;&lt;p&gt;&lt;u&gt;ENUMS&lt;/u&gt; - Boring they are in the header files in the WDK&lt;/p&gt;&lt;pre&gt;&lt;span style="color:green;"&gt;// SD_COMMAND_CLASS
&lt;/span&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdCommandClass &lt;/span&gt;: &lt;span style="color:blue;"&gt;uint
&lt;/span&gt;{
    Standard,                       &lt;span style="color:green;"&gt;// SDCC_STANDARD
    &lt;/span&gt;AppCmd                          &lt;span style="color:green;"&gt;// SDCC_APP_CMD
&lt;/span&gt;};

&lt;span style="color:green;"&gt;// SD_TRANSFER_DIRECTION
&lt;/span&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdTransferDirection &lt;/span&gt;: &lt;span style="color:blue;"&gt;uint
&lt;/span&gt;{
    Unspecified,                    &lt;span style="color:green;"&gt;// SDTD_UNSPECIFIED
    &lt;/span&gt;Read,                           &lt;span style="color:green;"&gt;// SDTD_READ
    &lt;/span&gt;Write                           &lt;span style="color:green;"&gt;// SDTD_WRITE
&lt;/span&gt;};

&lt;span style="color:green;"&gt;// SD_TRANSFER_TYPE
&lt;/span&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdTransferType &lt;/span&gt;: &lt;span style="color:blue;"&gt;uint
&lt;/span&gt;{
    Unspecified,                    &lt;span style="color:green;"&gt;// SDTT_UNSPECIFIED
    &lt;/span&gt;CmdOnly,                        &lt;span style="color:green;"&gt;// SDTT_CMD_ONLY
    &lt;/span&gt;SingleBlock,                    &lt;span style="color:green;"&gt;// SDTT_SINGLE_BLOCK
    &lt;/span&gt;MultiBlock,                     &lt;span style="color:green;"&gt;// SDTT_MULTI_BLOCK
    &lt;/span&gt;MultiBlockNoCmd12               &lt;span style="color:green;"&gt;// SDTT_MULTI_BLOCK_NO_CMD12
&lt;/span&gt;};

&lt;span style="color:green;"&gt;// SD_RESPONSE_TYPE
&lt;/span&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdResponseType &lt;/span&gt;: &lt;span style="color:blue;"&gt;uint
&lt;/span&gt;{
    Unspecified,                    &lt;span style="color:green;"&gt;// SDRT_UNSPECIFIED
    &lt;/span&gt;None,                           &lt;span style="color:green;"&gt;// SDRT_NONE
    &lt;/span&gt;R1,                             &lt;span style="color:green;"&gt;// SDRT_1
    &lt;/span&gt;R1b,                            &lt;span style="color:green;"&gt;// SDRT_1B
    &lt;/span&gt;R2,                             &lt;span style="color:green;"&gt;// SDRT_2
    &lt;/span&gt;R3,                             &lt;span style="color:green;"&gt;// SDRT_3
    &lt;/span&gt;R4,                             &lt;span style="color:green;"&gt;// SDRT_4
    &lt;/span&gt;R5,                             &lt;span style="color:green;"&gt;// SDRT_5
    &lt;/span&gt;R5b,                            &lt;span style="color:green;"&gt;// SDRT_5B
    &lt;/span&gt;R6                              &lt;span style="color:green;"&gt;// SDRT_6
&lt;/span&gt;};

&lt;span style="color:green;"&gt;// SFFDISK_DCMD
&lt;/span&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskDcmd &lt;/span&gt;: &lt;span style="color:blue;"&gt;uint
&lt;/span&gt;{
    GetVersion,                     &lt;span style="color:green;"&gt;// SFFDISK_DC_GET_VERSION
    &lt;/span&gt;LockChannel,                    &lt;span style="color:green;"&gt;// SFFDISK_DC_LOCK_CHANNEL
    &lt;/span&gt;UnlockChannel,                  &lt;span style="color:green;"&gt;// SFFDISK_DC_UNLOCK_CHANNEL
    &lt;/span&gt;DeviceCommand                   &lt;span style="color:green;"&gt;// SFFDISK_DC_DEVICE_COMMAND
&lt;/span&gt;};&lt;/pre&gt;

&lt;pre&gt;&lt;span style="color:blue;"&gt;public enum &lt;/span&gt;IoCtlCode : &lt;span style="color:blue;"&gt;uint
&lt;/span&gt;{
    SffdiskQueryDeviceProtocol = 0x71E80,       &lt;span style="color:green;"&gt;// IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL   
    &lt;/span&gt;SffdiskDeviceCommand = 0x79E84,             &lt;span style="color:green;"&gt;// IOCTL_SFFDISK_DEVICE_COMMAND   
    &lt;/span&gt;VolumeGetVolumeDiskExtents = 0x560000       &lt;span style="color:green;"&gt;// IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
&lt;/span&gt;};&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Native Methods&lt;/u&gt; - There are plenty of overrides of DeviceIOControl. The last one that takes byte[] sends the sd command.


Note the use of SafeHandles instead of IntPtr.&lt;/p&gt;

&lt;pre&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;DllImport&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"kernel32"&lt;/span&gt;, CharSet = &lt;span style="COLOR: rgb(43,145,175)"&gt;CharSet&lt;/span&gt;.Unicode, SetLastError = &lt;span style="color:blue;"&gt;true&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public extern static &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;CreateFile(&lt;span style="COLOR: rgb(43,145,175)"&gt;String &lt;/span&gt;fileName, &lt;span style="COLOR: rgb(43,145,175)"&gt;AccessRights &lt;/span&gt;desiredAccess, &lt;span style="COLOR: rgb(43,145,175)"&gt;ShareModes &lt;/span&gt;shareMode, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;securityAttributes, &lt;span style="COLOR: rgb(43,145,175)"&gt;CreationDisposition &lt;/span&gt;creationDisposition, &lt;span style="color:blue;"&gt;int &lt;/span&gt;flagsAndAttributes, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;hTemplateFile);

&lt;span style="color:green;"&gt;// overload used for querydeviceprotocol
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;DllImport&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"kernel32"&lt;/span&gt;, SetLastError = &lt;span style="color:blue;"&gt;true&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public extern static bool &lt;/span&gt;DeviceIoControl(&lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;hVol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IoCtlCode &lt;/span&gt;controlCode, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;inBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;inBufferSize, &lt;span style="color:blue;"&gt;ref &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskQueryDeviceProtocolData &lt;/span&gt;outBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;outBufferSize, &lt;span style="color:blue;"&gt;out int &lt;/span&gt;bytesReturned, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;overlapped);

&lt;span style="color:green;"&gt;// overload used for getting the disk extents
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;DllImport&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"kernel32"&lt;/span&gt;, SetLastError = &lt;span style="color:blue;"&gt;true&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public extern static bool &lt;/span&gt;DeviceIoControl(&lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;hVol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IoCtlCode &lt;/span&gt;controlCode, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;inBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;inBufferSize, &lt;span style="color:blue;"&gt;out &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;DiskExtents &lt;/span&gt;outBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;outBufferSize, &lt;span style="color:blue;"&gt;out int &lt;/span&gt;bytesReturned, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;overlapped);

&lt;span style="color:green;"&gt;// overload used for getting more than 1 diskextent
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;DllImport&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"kernel32"&lt;/span&gt;, SetLastError = &lt;span style="color:blue;"&gt;true&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public extern static bool &lt;/span&gt;DeviceIoControl(&lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;hVol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IoCtlCode &lt;/span&gt;controlCode, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;inBuffer,&lt;span style="color:blue;"&gt;int &lt;/span&gt;inBufferSize, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;outBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;outBufferSize, &lt;span style="color:blue;"&gt;out int &lt;/span&gt;bytesReturned, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;overlapped);

&lt;span style="color:green;"&gt;// Overload for the CID
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;DllImport&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"kernel32"&lt;/span&gt;, SetLastError = &lt;span style="color:blue;"&gt;true&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public extern static bool &lt;/span&gt;DeviceIoControl(&lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;hVol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IoCtlCode &lt;/span&gt;controlCode, &lt;span style="COLOR: rgb(43,145,175)"&gt;Byte&lt;/span&gt;[] inBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;inBufferSize, &lt;span style="COLOR: rgb(43,145,175)"&gt;Byte&lt;/span&gt;[] outBuffer, &lt;span style="color:blue;"&gt;int &lt;/span&gt;outBufferSize, &lt;span style="color:blue;"&gt;out int &lt;/span&gt;bytesReturned, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;ovelapped);&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;u&gt;The Structures&lt;/u&gt; - No fancy marshaling required. Again, see the WDK header files.&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:green;"&gt;// SDCMD_DESCRIPTOR
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;StructLayout&lt;/span&gt;(&lt;span style="COLOR: rgb(43,145,175)"&gt;LayoutKind&lt;/span&gt;.Sequential)]
&lt;span style="color:blue;"&gt;struct &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdCmdDescriptor
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Byte &lt;/span&gt;CommandCode;
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdCommandClass &lt;/span&gt;CmdClass;
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdTransferDirection &lt;/span&gt;TransferDirection;
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdTransferType &lt;/span&gt;TransferType;
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdResponseType &lt;/span&gt;ResponseType;
    &lt;span style="color:blue;"&gt;public int &lt;/span&gt;GetSize()
    {
        &lt;span style="color:blue;"&gt;return &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.SizeOf(&lt;span style="color:blue;"&gt;this&lt;/span&gt;);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;pre&gt;&lt;span style="color:green;"&gt;// SFFDISK_DEVICE_COMMAND_DATA
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;StructLayout&lt;/span&gt;(&lt;span style="COLOR: rgb(43,145,175)"&gt;LayoutKind&lt;/span&gt;.Sequential)]
&lt;span style="color:blue;"&gt;struct &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskDeviceCommandData
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public ushort &lt;/span&gt;Size;                     &lt;span style="color:green;"&gt;// 0
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public ushort &lt;/span&gt;Reserved;                 &lt;span style="color:green;"&gt;// 2
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskDcmd &lt;/span&gt;Command;             &lt;span style="color:green;"&gt;// 4
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public ushort &lt;/span&gt;ProtocolArgumentSize;     &lt;span style="color:green;"&gt;// 8
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public uint &lt;/span&gt;DeviceDataBufferSize;       &lt;span style="color:green;"&gt;// 12
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public uint &lt;/span&gt;Information;                &lt;span style="color:green;"&gt;// 16   *ULONG_PTR*, Data[] Follows.
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public void &lt;/span&gt;Init()
    {
        &lt;span style="color:blue;"&gt;this&lt;/span&gt;.Size = (&lt;span style="color:blue;"&gt;ushort&lt;/span&gt;)&lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.SizeOf(&lt;span style="color:blue;"&gt;this&lt;/span&gt;);
    }
} &lt;/pre&gt;

&lt;pre&gt;&lt;span style="color:green;"&gt;// SFFDISK_QUERY_DEVICE_PROTOCOL_DATA
&lt;/span&gt;[&lt;span style="COLOR: rgb(43,145,175)"&gt;StructLayout&lt;/span&gt;(&lt;span style="COLOR: rgb(43,145,175)"&gt;LayoutKind&lt;/span&gt;.Sequential)]
&lt;span style="color:blue;"&gt;struct &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskQueryDeviceProtocolData
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public ushort &lt;/span&gt;Size;
    &lt;span style="color:blue;"&gt;public ushort &lt;/span&gt;Reserved;
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Guid &lt;/span&gt;ProtocolGuid;
    &lt;span style="color:blue;"&gt;public void &lt;/span&gt;Init()
    {
        &lt;span style="color:blue;"&gt;this&lt;/span&gt;.Size = (&lt;span style="color:blue;"&gt;ushort&lt;/span&gt;)&lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.SizeOf(&lt;span style="color:blue;"&gt;this&lt;/span&gt;);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;u&gt;The class that makes the call&lt;/u&gt; - could do with more tidying up. CID and CSD are classes with lots of properties, the constructor takes the byte array returned by the deviceIOControl call and fills in the properties. They probably have mistakes too. See the linked code.&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:blue;"&gt;using &lt;/span&gt;Microsoft.Win32.SafeHandles;
&lt;span style="color:blue;"&gt;using &lt;/span&gt;System;
&lt;span style="color:blue;"&gt;using &lt;/span&gt;System.Collections.Generic;
&lt;span style="color:blue;"&gt;using &lt;/span&gt;System.ComponentModel;
&lt;span style="color:blue;"&gt;using &lt;/span&gt;System.IO;
&lt;span style="color:blue;"&gt;using &lt;/span&gt;System.Runtime.InteropServices;
&lt;span style="color:blue;"&gt;using &lt;/span&gt;System.Text;

&lt;span style="color:blue;"&gt;namespace &lt;/span&gt;JDMcF.SDCard
{
    &lt;span style="color:green;"&gt;// This class might get some information about an SDCard.
    // Does not work with USB SD Card Readers.
    // Does not work with some SD Bus Host Drivers.
    // Administrator privileges required.
    // I don't know if the IOCTLs work with mobile devices.
    // I don't know if I'm translating the bytes from the CID correctly.
    &lt;/span&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SDCard
    &lt;/span&gt;{
        &lt;span style="color:green;"&gt;// GUID_SFF_PROTOCOL_SD
        &lt;/span&gt;&lt;span style="color:blue;"&gt;private static readonly &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Guid &lt;/span&gt;GuidSffProtocolSd = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Guid&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"AD7536A8-D055-4C40-AA4D-96312DDB6B38"&lt;/span&gt;);

        &lt;span style="color:blue;"&gt;private &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;CID &lt;/span&gt;cid;
        &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;CID &lt;/span&gt;CID { &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;cid; } }

        &lt;span style="color:blue;"&gt;private &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;CSD &lt;/span&gt;csd;
        &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;CSD &lt;/span&gt;CSD { &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;csd; } }

        &lt;span style="color:blue;"&gt;private &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;DriveInfo &lt;/span&gt;driveInfo;
        &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;DriveInfo &lt;/span&gt;DriveInfo { &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;driveInfo; } }

        &lt;span style="color:blue;"&gt;private string &lt;/span&gt;physicalDrivePath;
        &lt;span style="color:blue;"&gt;public string &lt;/span&gt;PhysicalDrivePath { &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;physicalDrivePath; } }

        &lt;span style="color:blue;"&gt;private &lt;/span&gt;SDCard(&lt;span style="color:blue;"&gt;string &lt;/span&gt;physicalDrivePath, &lt;span style="COLOR: rgb(43,145,175)"&gt;DriveInfo &lt;/span&gt;driveInfo)
        {
            &lt;span style="color:green;"&gt;// At first only these are initialised. It takes a second or so to
            &lt;/span&gt;&lt;span style="color:green;"&gt;// read the CID so we so
            // it on another thread and raise an event once done.
            &lt;/span&gt;&lt;span style="color:blue;"&gt;this&lt;/span&gt;.physicalDrivePath = physicalDrivePath;
            &lt;span style="color:blue;"&gt;this&lt;/span&gt;.driveInfo = driveInfo;
        }

        &lt;span style="color:blue;"&gt;public static &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SDCard&lt;/span&gt;&amp;gt; GetSDCards()
        {
            &lt;span style="COLOR: rgb(43,145,175)"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SDCard&lt;/span&gt;&amp;gt; cards = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SDCard&lt;/span&gt;&amp;gt;();
            &lt;span style="color:green;"&gt;// There are probably ways to mount the card elsewhere,
            // &lt;/span&gt;&lt;span style="color:green;"&gt;so it might miss those...
            &lt;/span&gt;&lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="COLOR: rgb(43,145,175)"&gt;DriveInfo &lt;/span&gt;di &lt;span style="color:blue;"&gt;in &lt;/span&gt;System.IO.&lt;span style="COLOR: rgb(43,145,175)"&gt;DriveInfo&lt;/span&gt;.GetDrives())
            {
                &lt;span style="color:green;"&gt;// Are all SD Cards Removable? I don't know!
                &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;(di.DriveType == &lt;span style="COLOR: rgb(43,145,175)"&gt;DriveType&lt;/span&gt;.Removable)
                {
                    &lt;span style="color:green;"&gt;// We are enumerating volumes. Volumes can span physical
                    // &lt;/span&gt;&lt;span style="color:green;"&gt;disks. Work out how many physical disks are involved
                    // &lt;/span&gt;&lt;span style="color:green;"&gt;with each volume. (seems unlikely, but I just figured
                    // &lt;/span&gt;&lt;span style="color:green;"&gt;out how to do this so what the heck)...
                    &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;&amp;gt; physicalPaths =
&lt;span style="COLOR: rgb(43,145,175)"&gt;                        VolumeInfo&lt;/span&gt;.GetPhysicalDriveStrings(di);
                    &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color:blue;"&gt;string &lt;/span&gt;physicalPath &lt;span style="color:blue;"&gt;in &lt;/span&gt;physicalPaths)
                    {
                        &lt;span style="color:blue;"&gt;if &lt;/span&gt;(IsSD(physicalPath))
                        {
                            cards.Add(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SDCard&lt;/span&gt;(physicalPath, di));
                        }
                    }
                }
            }
            &lt;span style="color:blue;"&gt;return &lt;/span&gt;cards;
        }

        &lt;span style="color:green;"&gt;// Send IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL to see if the handle
        // belongs to an SD Card.
        &lt;/span&gt;&lt;span style="color:blue;"&gt;private static bool &lt;/span&gt;IsSD(&lt;span style="color:blue;"&gt;string &lt;/span&gt;physicalPath)
        {
            &lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;hVol = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
            &lt;span style="color:blue;"&gt;try
            &lt;/span&gt;{
                hVol = &lt;span style="COLOR: rgb(43,145,175)"&gt;NativeMethods&lt;/span&gt;.CreateFile(physicalPath, &lt;span style="COLOR: rgb(43,145,175)"&gt;AccessRights&lt;/span&gt;.GenericRead, &lt;span style="COLOR: rgb(43,145,175)"&gt;ShareModes&lt;/span&gt;.FileShareRead  &lt;span style="COLOR: rgb(43,145,175)"&gt;ShareModes&lt;/span&gt;.FileShareWrite,
&lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero, &lt;span style="COLOR: rgb(43,145,175)"&gt;CreationDisposition&lt;/span&gt;.OpenExisting, 0, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero);
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(hVol.IsInvalid)
                {
                    &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Win32Exception&lt;/span&gt;(&lt;span style="COLOR: rgb(163,21,21)"&gt;"Couldn't CreateFile for " &lt;/span&gt;+
                                             physicalPath);
                &lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskQueryDeviceProtocolData &lt;/span&gt;queryData1 =
                    &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskQueryDeviceProtocolData&lt;/span&gt;();
                queryData1.Init();
                &lt;span style="color:blue;"&gt;int &lt;/span&gt;bytesReturned;
                &lt;span style="color:blue;"&gt;bool &lt;/span&gt;result = &lt;span style="COLOR: rgb(43,145,175)"&gt;NativeMethods&lt;/span&gt;.DeviceIoControl(hVol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IoCtlCode&lt;/span&gt;.SffdiskQueryDeviceProtocol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero, 0, &lt;span style="color:blue;"&gt;ref &lt;/span&gt;queryData1, queryData1.Size, &lt;span style="color:blue;"&gt;out &lt;/span&gt;bytesReturned, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero);
                &lt;span style="color:blue;"&gt;return &lt;/span&gt;queryData1.ProtocolGuid.Equals(GuidSffProtocolSd);
            }
            &lt;span style="color:blue;"&gt;finally
            &lt;/span&gt;{
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(hVol != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
                {
                    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(!hVol.IsInvalid)
                    {
                        hVol.Close();
                    }
                    hVol.Dispose();
                }
            }
        }

        &lt;span style="color:blue;"&gt;public void &lt;/span&gt;RefreshData()
        {
            GetRegister(&lt;span style="COLOR: rgb(43,145,175)"&gt;Register&lt;/span&gt;.CID);
            GetRegister(&lt;span style="COLOR: rgb(43,145,175)"&gt;Register&lt;/span&gt;.CSD);
        }

        &lt;span style="color:green;"&gt;// Send the command in the array. On return the array will have any
        // response.
        &lt;/span&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;SendCommand(&lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] command)
        {
            &lt;span style="COLOR: rgb(43,145,175)"&gt;SafeFileHandle &lt;/span&gt;hVol = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
            &lt;span style="color:blue;"&gt;try
            &lt;/span&gt;{
                hVol = &lt;span style="COLOR: rgb(43,145,175)"&gt;NativeMethods&lt;/span&gt;.CreateFile(PhysicalDrivePath, &lt;span style="COLOR: rgb(43,145,175)"&gt;AccessRights&lt;/span&gt;.GenericRead  &lt;span style="COLOR: rgb(43,145,175)"&gt;AccessRights&lt;/span&gt;.GenericWrite, &lt;span style="COLOR: rgb(43,145,175)"&gt;ShareModes&lt;/span&gt;.FileShareRead  &lt;span style="COLOR: rgb(43,145,175)"&gt;ShareModes&lt;/span&gt;.FileShareWrite, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero, &lt;span style="COLOR: rgb(43,145,175)"&gt;CreationDisposition&lt;/span&gt;.OpenExisting, 0, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero);
                &lt;span style="color:blue;"&gt;int &lt;/span&gt;bytesReturned;
                &lt;span style="color:blue;"&gt;bool &lt;/span&gt;result = &lt;span style="COLOR: rgb(43,145,175)"&gt;NativeMethods&lt;/span&gt;.DeviceIoControl(hVol, &lt;span style="COLOR: rgb(43,145,175)"&gt;IoCtlCode&lt;/span&gt;.SffdiskDeviceCommand, command, command.Length, command, command.Length, &lt;span style="color:blue;"&gt;out &lt;/span&gt;bytesReturned, &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;.Zero);
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(!result) &lt;span style="color:blue;"&gt;throw new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;Win32Exception&lt;/span&gt;();
            }
            &lt;span style="color:blue;"&gt;finally
            &lt;/span&gt;{
                &lt;span style="color:blue;"&gt;if &lt;/span&gt;(hVol != &lt;span style="color:blue;"&gt;null&lt;/span&gt;)
                {
                    &lt;span style="color:blue;"&gt;if &lt;/span&gt;(!hVol.IsInvalid)
                    {
                        hVol.Close();
                    }
                    hVol.Dispose();
                }
            }
        }

        &lt;span style="color:green;"&gt;// Get the CID or CSD. They are almost identical commands...
        &lt;/span&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;GetRegister(&lt;span style="COLOR: rgb(43,145,175)"&gt;Register &lt;/span&gt;register)
        {
            &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] command = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;
            &lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskDeviceCommandData &lt;/span&gt;commandData = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskDeviceCommandData&lt;/span&gt;();
            &lt;span style="COLOR: rgb(43,145,175)"&gt;SdCmdDescriptor &lt;/span&gt;commandDescriptor = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;SdCmdDescriptor&lt;/span&gt;();
            commandData.Init();
            commandData.Command = &lt;span style="COLOR: rgb(43,145,175)"&gt;SffdiskDcmd&lt;/span&gt;.DeviceCommand;
            commandData.ProtocolArgumentSize = (&lt;span style="color:blue;"&gt;ushort&lt;/span&gt;)commandDescriptor.GetSize();
            commandData.DeviceDataBufferSize = 16;
            commandDescriptor.CommandCode = (&lt;span style="color:blue;"&gt;byte&lt;/span&gt;)register;   &lt;span style="color:green;"&gt;// &amp;lt;--- Not what the documentation indicates!
            &lt;/span&gt;commandDescriptor.CmdClass = &lt;span style="COLOR: rgb(43,145,175)"&gt;SdCommandClass&lt;/span&gt;.Standard;
            commandDescriptor.TransferDirection = &lt;span style="COLOR: rgb(43,145,175)"&gt;SdTransferDirection&lt;/span&gt;.Read;
            commandDescriptor.TransferType = &lt;span style="COLOR: rgb(43,145,175)"&gt;SdTransferType&lt;/span&gt;.CmdOnly;
            commandDescriptor.ResponseType = &lt;span style="COLOR: rgb(43,145,175)"&gt;SdResponseType&lt;/span&gt;.R2;

            &lt;span style="color:green;"&gt;// Now get the structs into the byte[]
            &lt;/span&gt;command = &lt;span style="color:blue;"&gt;new byte&lt;/span&gt;[commandData.Size + commandData.ProtocolArgumentSize + commandData.DeviceDataBufferSize];
            &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;hBuf = &lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.AllocHGlobal(command.Length);
            &lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.StructureToPtr(commandData, hBuf, &lt;span style="color:blue;"&gt;true&lt;/span&gt;);
            &lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr &lt;/span&gt;descriptorOffset = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;IntPtr&lt;/span&gt;(hBuf.ToInt32() + commandData.Size);
            &lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.StructureToPtr(commandDescriptor, descriptorOffset, &lt;span style="color:blue;"&gt;true&lt;/span&gt;);
            &lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.Copy(hBuf, command, 0, command.Length);
            &lt;span style="COLOR: rgb(43,145,175)"&gt;Marshal&lt;/span&gt;.FreeHGlobal(hBuf);

            SendCommand(command);
            &lt;span style="color:green;"&gt;// Strip out the return bytes that live at the end of the command byte array.
            &lt;/span&gt;&lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] regBytes = &lt;span style="color:blue;"&gt;new byte&lt;/span&gt;[16];
            &lt;span style="COLOR: rgb(43,145,175)"&gt;Buffer&lt;/span&gt;.BlockCopy(command, command.Length - 16, regBytes, 0, 16);

            &lt;span style="color:blue;"&gt;if &lt;/span&gt;(register == &lt;span style="COLOR: rgb(43,145,175)"&gt;Register&lt;/span&gt;.CID)
            {
                cid = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;CID&lt;/span&gt;(regBytes);
            }
            &lt;span style="color:blue;"&gt;else
            &lt;/span&gt;{
                csd = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="COLOR: rgb(43,145,175)"&gt;CSD&lt;/span&gt;(regBytes);
            }
        }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;iframe style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; MARGIN: 3px; WIDTH: 240px; PADDING-TOP: 0px; HEIGHT: 66px; BACKGROUND-COLOR: rgb(255,255,255)" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/JDMcF.SDCard.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;Formatting is awful...
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3825000455104564462?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3825000455104564462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-cid-and-csd-c-implementation.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3825000455104564462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3825000455104564462'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-cid-and-csd-c-implementation.html' title='Read CID and CSD C# implementation.'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3856137309153132214</id><published>2008-11-27T15:58:00.000Z</published><updated>2008-12-22T15:59:51.632Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS'/><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='PhysicalDrive'/><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Howto: Get the physical drive string //./PhysicalDriveX from a path</title><content type='html'>&lt;p&gt;There are lots of strings that you can feed CreateFile, if we are looking at volumes and drives then they include: &lt;/p&gt;  &lt;p&gt;&lt;u&gt;The Unique Volume Name:&lt;/u&gt; &lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Fixedsys;font-size:78%;"&gt;\\?\Volume{013eeefb-9b12-11dd-bee5-806e6f6e6963}\&lt;/span&gt; &lt;/p&gt;  &lt;p&gt;You can list those at the command prompt with: "&lt;span style="font-family:Fixedsys;font-size:78%;"&gt;mountvol&lt;/span&gt;". &lt;/p&gt;  &lt;p&gt;&lt;u&gt;The mount point:&lt;/u&gt; &lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Fixedsys;font-size:78%;"&gt;\\.\C:&lt;/span&gt; &lt;/p&gt;  &lt;p&gt;If you really want to list them at the command line, then "&lt;span style="font-family:Fixedsys;font-size:78%;"&gt;fsutil fsinfo drives&lt;/span&gt;" will do the trick. &lt;/p&gt;  &lt;p&gt;&lt;u&gt;The physical drive string (or whatever it is called)&lt;/u&gt; &lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Fixedsys;font-size:78%;"&gt;\\.\PhysicalDrive0&lt;/span&gt; &lt;/p&gt;  &lt;p&gt;command: "&lt;span style="font-family:Fixedsys;font-size:78%;"&gt;wmic diskdrive get name,size,model&lt;/span&gt;" &lt;/p&gt;  &lt;p&gt;But, how can we get all of the physical drive strings available? Well, the hint is in the &lt;a href="http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx" target="_blank"&gt;CreateFile documentation&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;To obtain the physical drive for a volume, open a handle to the volume and call the DeviceIoControl function with IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS. This control code returns the disk number of offset for each of the volume's extents; a volume can span disks.&lt;/em&gt; &lt;/p&gt;  &lt;p&gt;In .Net then, start by enumerating all the drives, and create strings like the mount points above "\\.\X:". Use this with CreateFile to get a handle to the volume. Then call DeviceIOControl with IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS. &lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:100%;"&gt;&lt;u&gt;The Class that does the hard work:&lt;/u&gt;&lt;/span&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Project type - vb.net class library (2005 or 2008) - name JdMcF.VolumeInfo:&lt;/p&gt;  &lt;pre&gt;&lt;span style="color:blue;"&gt;Option Strict On
Option Explicit On

Imports &lt;/span&gt;Microsoft.Win32.SafeHandles
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.IO
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.Runtime.InteropServices
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.ComponentModel

&lt;span style="color:blue;"&gt;Public Class &lt;/span&gt;VolumeInfo

   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;GenericRead &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= &amp;amp;H80000000
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;FileShareRead &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 1
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;Filesharewrite &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 2
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;OpenExisting &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 3
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;IoctlVolumeGetVolumeDiskExtents &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= &amp;amp;H560000
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;IncorrectFunction &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 1
   &lt;span style="color:blue;"&gt;Private Const &lt;/span&gt;ErrorInsufficientBuffer &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 122

   &lt;span style="color:blue;"&gt;Private Class &lt;/span&gt;NativeMethods
       &amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"kernel32"&lt;/span&gt;, CharSet:=CharSet.Unicode, SetLastError:=&lt;span style="color:blue;"&gt;True&lt;/span&gt;)&amp;gt; _
       &lt;span style="color:blue;"&gt;Public Shared Function &lt;/span&gt;CreateFile( _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;fileName &lt;span style="color:blue;"&gt;As String&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;desiredAccess &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;shareMode &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;securityAttributes &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;creationDisposition &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;flagsAndAttributes &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hTemplateFile &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle
       &lt;span style="color:blue;"&gt;End Function

       &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"kernel32"&lt;/span&gt;, SetLastError:=&lt;span style="color:blue;"&gt;True&lt;/span&gt;)&amp;gt; _
       &lt;span style="color:blue;"&gt;Public Shared Function &lt;/span&gt;DeviceIoControl( _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hVol &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;controlCode &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;inBuffer &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;inBufferSize &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;outBuffer &lt;span style="color:blue;"&gt;As &lt;/span&gt;DiskExtents, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;outBufferSize &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;bytesReturned &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;overlapped &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color:blue;"&gt;Boolean
       End Function

       &lt;/span&gt;&amp;lt;DllImport(&lt;span style="color: rgb(163, 21, 21);"&gt;"kernel32"&lt;/span&gt;, SetLastError:=&lt;span style="color:blue;"&gt;True&lt;/span&gt;)&amp;gt; _
       &lt;span style="color:blue;"&gt;Public Shared Function &lt;/span&gt;DeviceIoControl( _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;hVol &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;controlCode &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;inBuffer &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;inBufferSize &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;outBuffer &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;outBufferSize &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByRef &lt;/span&gt;bytesReturned &lt;span style="color:blue;"&gt;As Integer&lt;/span&gt;, _
           &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;overlapped &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr) &lt;span style="color:blue;"&gt;As &lt;/span&gt;&amp;lt;MarshalAs(UnmanagedType.Bool)&amp;gt; &lt;span style="color:blue;"&gt;Boolean
       End Function
   End Class

   &lt;/span&gt;&lt;span style="color:green;"&gt;' DISK_EXTENT in the msdn.
   &lt;/span&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
   &lt;span style="color:blue;"&gt;Private Structure &lt;/span&gt;DiskExtent
       &lt;span style="color:blue;"&gt;Public &lt;/span&gt;DiskNumber &lt;span style="color:blue;"&gt;As Integer
       Public &lt;/span&gt;StartingOffset &lt;span style="color:blue;"&gt;As Long
       Public &lt;/span&gt;ExtentLength &lt;span style="color:blue;"&gt;As Long
   End Structure

   &lt;/span&gt;&lt;span style="color:green;"&gt;' DISK_EXTENTS
   &lt;/span&gt;&amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
   &lt;span style="color:blue;"&gt;Private Structure &lt;/span&gt;DiskExtents
       &lt;span style="color:blue;"&gt;Public &lt;/span&gt;numberOfExtents &lt;span style="color:blue;"&gt;As Integer
       Public &lt;/span&gt;first &lt;span style="color:blue;"&gt;As &lt;/span&gt;DiskExtent &lt;span style="color:green;"&gt;' We can't marhsal an array if we don't know its size.
   &lt;/span&gt;&lt;span style="color:blue;"&gt;End Structure

   &lt;/span&gt;&lt;span style="color:green;"&gt;' A Volume could be on many physical drives.
   ' Returns a list of string containing each physical drive the volume uses.
   ' For CD Drives with no disc in it will return an empty list.
   &lt;/span&gt;&lt;span style="color:blue;"&gt;Public Shared Function &lt;/span&gt;GetPhysicalDriveStrings(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;driveInfo &lt;span style="color:blue;"&gt;As &lt;/span&gt;DriveInfo) &lt;span style="color:blue;"&gt;As &lt;/span&gt;List(&lt;span style="color:blue;"&gt;Of String&lt;/span&gt;)
       &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;sfh &lt;span style="color:blue;"&gt;As &lt;/span&gt;SafeFileHandle = &lt;span style="color:blue;"&gt;Nothing
       Dim &lt;/span&gt;physicalDrives &lt;span style="color:blue;"&gt;As New &lt;/span&gt;List(&lt;span style="color:blue;"&gt;Of String&lt;/span&gt;)(1)
       &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;path &lt;span style="color:blue;"&gt;As String &lt;/span&gt;= &lt;span style="color: rgb(163, 21, 21);"&gt;"\\.\" &lt;/span&gt;&amp;amp; driveInfo.RootDirectory.ToString.TrimEnd(&lt;span style="color: rgb(163, 21, 21);"&gt;"\"c&lt;/span&gt;)
       &lt;span style="color:blue;"&gt;Try
           &lt;/span&gt;sfh = NativeMethods.CreateFile(path, GenericRead, FileShareRead &lt;span style="color:blue;"&gt;Or &lt;/span&gt;Filesharewrite, IntPtr.Zero, _
                                                          OpenExisting, 0, IntPtr.Zero)
           &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;bytesReturned &lt;span style="color:blue;"&gt;As Integer
           Dim &lt;/span&gt;de1 &lt;span style="color:blue;"&gt;As &lt;/span&gt;DiskExtents = &lt;span style="color:blue;"&gt;Nothing
           Dim &lt;/span&gt;numDiskExtents &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 0
           &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;result &lt;span style="color:blue;"&gt;As Boolean &lt;/span&gt;= NativeMethods.DeviceIoControl(sfh, IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, _
                                                                 0, de1, Marshal.SizeOf(de1), bytesReturned, IntPtr.Zero)
           &lt;span style="color:blue;"&gt;If &lt;/span&gt;result = &lt;span style="color:blue;"&gt;True Then
               &lt;/span&gt;&lt;span style="color:green;"&gt;' there was only one disk extent. So the volume lies on 1 physical drive.
               &lt;/span&gt;physicalDrives.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;"\\.\PhysicalDrive" &lt;/span&gt;&amp;amp; de1.first.DiskNumber.ToString)
               &lt;span style="color:blue;"&gt;Return &lt;/span&gt;physicalDrives
           &lt;span style="color:blue;"&gt;End If
           If &lt;/span&gt;Marshal.GetLastWin32Error = IncorrectFunction &lt;span style="color:blue;"&gt;Then
               &lt;/span&gt;&lt;span style="color:green;"&gt;' The drive is removable and removed, like a CDRom with nothing in it.
               &lt;/span&gt;&lt;span style="color:blue;"&gt;Return &lt;/span&gt;physicalDrives
           &lt;span style="color:blue;"&gt;End If
           If &lt;/span&gt;Marshal.GetLastWin32Error &amp;lt;&amp;gt; ErrorInsufficientBuffer &lt;span style="color:blue;"&gt;Then
               Throw New &lt;/span&gt;Win32Exception
           &lt;span style="color:blue;"&gt;End If           
           &lt;/span&gt;&lt;span style="color:green;"&gt;' Houston, we have a spanner. The volume is on multiple disks.
           ' Untested...
           ' We need a blob of memory for the DISK_EXTENTS structure, and all the DISK_EXTENTS
           &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;blobSize &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= Marshal.SizeOf(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(DiskExtents)) + _
                                     (de1.numberOfExtents - 1) * Marshal.SizeOf(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(DiskExtent))
           &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;pBlob &lt;span style="color:blue;"&gt;As &lt;/span&gt;IntPtr = Marshal.AllocHGlobal(blobSize)
           result = NativeMethods.DeviceIoControl(sfh, IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, 0, pBlob, _
                                                  blobSize, bytesReturned, IntPtr.Zero)
           &lt;span style="color:blue;"&gt;If &lt;/span&gt;result = &lt;span style="color:blue;"&gt;False Then Throw New &lt;/span&gt;Win32Exception
           &lt;span style="color:green;"&gt;' Read them out one at a time.
           &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim &lt;/span&gt;pNext &lt;span style="color:blue;"&gt;As New &lt;/span&gt;IntPtr(pBlob.ToInt32 + 4) &lt;span style="color:green;"&gt;' is this always ok on 64 bit OSes? ToInt64?
           &lt;/span&gt;&lt;span style="color:blue;"&gt;For &lt;/span&gt;i &lt;span style="color:blue;"&gt;As Integer &lt;/span&gt;= 0 &lt;span style="color:blue;"&gt;To &lt;/span&gt;de1.numberOfExtents - 1
               &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;diskExtentN &lt;span style="color:blue;"&gt;As &lt;/span&gt;DiskExtent = &lt;span style="color:blue;"&gt;DirectCast&lt;/span&gt;(Marshal.PtrToStructure(pNext, &lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(DiskExtent)), DiskExtent)
               physicalDrives.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;"\\.\PhysicalDrive" &lt;/span&gt;&amp;amp; diskExtentN.DiskNumber.ToString)
               pNext = &lt;span style="color:blue;"&gt;New &lt;/span&gt;IntPtr(pNext.ToInt32 + Marshal.SizeOf(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(DiskExtent)))
           &lt;span style="color:blue;"&gt;Next
           Return &lt;/span&gt;physicalDrives
       &lt;span style="color:blue;"&gt;Finally
           If &lt;/span&gt;sfh &lt;span style="color:blue;"&gt;IsNot Nothing Then
               If &lt;/span&gt;sfh.IsInvalid = &lt;span style="color:blue;"&gt;False Then
                   &lt;/span&gt;sfh.Close()
               &lt;span style="color:blue;"&gt;End If
               &lt;/span&gt;sfh.Dispose()
           &lt;span style="color:blue;"&gt;End If
       End Try
   End Function

End Class
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;&lt;span style="font-size:100%;"&gt;The Test project:&lt;/span&gt;&lt;/u&gt; &lt;/p&gt;

&lt;p&gt;Project type: vb.net windows forms app (2005 or 2008) name: whatever.&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:blue;"&gt;Option Strict On
Option Explicit On
Option Infer Off

Imports &lt;/span&gt;JDMcF.VolumeInfo
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.IO
&lt;span style="color:blue;"&gt;Imports &lt;/span&gt;System.Text

&lt;span style="color:blue;"&gt;Public Class &lt;/span&gt;Form1

   &lt;span style="color:blue;"&gt;Private &lt;/span&gt;lv1 &lt;span style="color:blue;"&gt;As New &lt;/span&gt;ListView

   &lt;span style="color:blue;"&gt;Sub New&lt;/span&gt;()

       &lt;span style="color:green;"&gt;' This call is required by the Windows Form Designer.
       &lt;/span&gt;InitializeComponent()

       &lt;span style="color:green;"&gt;' Add any initialization after the InitializeComponent() call.
       &lt;/span&gt;&lt;span style="color:blue;"&gt;With &lt;/span&gt;lv1
           .View = View.Details
           .Columns.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;"Root"&lt;/span&gt;, 100, HorizontalAlignment.Left)
           .Columns.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;"Physical Drive String"&lt;/span&gt;, 200, HorizontalAlignment.Left)
           .Dock = DockStyle.Fill
       &lt;span style="color:blue;"&gt;End With
       Me&lt;/span&gt;.Controls.Add(lv1)       
   &lt;span style="color:blue;"&gt;End Sub

   Private Sub &lt;/span&gt;Form1_Load(&lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;sender &lt;span style="color:blue;"&gt;As &lt;/span&gt;System.Object, &lt;span style="color:blue;"&gt;ByVal &lt;/span&gt;e &lt;span style="color:blue;"&gt;As &lt;/span&gt;System.EventArgs) &lt;span style="color:blue;"&gt;Handles MyBase&lt;/span&gt;.Load
       &lt;span style="color:blue;"&gt;For Each &lt;/span&gt;di &lt;span style="color:blue;"&gt;As &lt;/span&gt;DriveInfo &lt;span style="color:blue;"&gt;In &lt;/span&gt;DriveInfo.GetDrives
           &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;drivesList &lt;span style="color:blue;"&gt;As &lt;/span&gt;List(&lt;span style="color:blue;"&gt;Of String&lt;/span&gt;) = VolumeInfo.GetPhysicalDriveStrings(di)

           &lt;span style="color:blue;"&gt;Dim &lt;/span&gt;drives &lt;span style="color:blue;"&gt;As New &lt;/span&gt;StringBuilder
           &lt;span style="color:blue;"&gt;If &lt;/span&gt;drivesList.Count &amp;gt; 0 &lt;span style="color:blue;"&gt;Then
               For Each &lt;/span&gt;s &lt;span style="color:blue;"&gt;As String In &lt;/span&gt;drivesList
                   drives.Append(s)
                   drives.Append(&lt;span style="color: rgb(163, 21, 21);"&gt;", "&lt;/span&gt;)
               &lt;span style="color:blue;"&gt;Next
               &lt;/span&gt;drives.Remove(drives.Length - 2, 2)
           &lt;span style="color:blue;"&gt;Else
               &lt;/span&gt;drives.Append(&lt;span style="color: rgb(163, 21, 21);"&gt;"n/a"&lt;/span&gt;)
           &lt;span style="color:blue;"&gt;End If
           Dim &lt;/span&gt;lvi &lt;span style="color:blue;"&gt;As New &lt;/span&gt;ListViewItem(di.RootDirectory.ToString)
           lvi.SubItems.Add(drives.ToString)
           lv1.Items.Add(lvi)
       &lt;span style="color:blue;"&gt;Next
   End Sub

End Class&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Linky to code:&lt;iframe style="margin: 3px; padding: 0px; width: 240px; height: 66px; background-color: rgb(255, 255, 255);" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/JDMcF.VolumeInfo.zip" scrolling="no" frameborder="0"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3856137309153132214?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3856137309153132214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/howto-get-physical-drive-string.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3856137309153132214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3856137309153132214'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/howto-get-physical-drive-string.html' title='Howto: Get the physical drive string //./PhysicalDriveX from a path'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3630456326553405434</id><published>2008-11-26T16:10:00.000Z</published><updated>2008-12-22T16:12:16.334Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SD Card'/><category scheme='http://www.blogger.com/atom/ns#' term='read serial number'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CID'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CSD'/><title type='text'>SD Card - Read CID/Serial number - Musings</title><content type='html'>&lt;p&gt;Well I discovered that my .Net app does actually work on 32 bit operating systems too. Assuming I'm reading the data correctly, I can read CIDs in XP SP2, on an old Asus W5 laptop. It also has an integral card reader. BUT: it didn't work at first. DeviceIOControl returned "Invalid Function" (Win32 Error code 1). I went in to device manager and changed the driver over: &lt;/p&gt;&lt;p&gt;&lt;a href="http://5ossfa.bay.livefilestore.com/y1pwT8E3Un89qN3VHGyeSUiicu3aw276Sns-5RKoJko7Gf-WwRysAB7tEgfT_kk0qOq04lXjcGCF-pw-ac8ucTz_A?PARTNER=WRITER"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="499" alt="1" src="http://5ossfa.bay.livefilestore.com/y1pbFkLbX3qI4ShVa7dT8-H2Ts3ArBb3tfJ8hX1FACZgf7lCU0LydvBqbZDvOSsdnI3t1kWpJtTTHm6cX-9G6rZCw?PARTNER=WRITER" width="644" border="0" /&gt;&lt;/a&gt;  &lt;/p&gt;&lt;p&gt;TO: &lt;/p&gt;&lt;p&gt;&lt;a href="http://5ossfa.bay.livefilestore.com/y1pADIYzP1HFWK_17bOBOVKLdsCS5WeDoFKuOrGfwM8XsSYxIHnzm93ty3eFjanT-b4o28guOGSH2hmF77zkHPBhQ?PARTNER=WRITER"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="460" alt="2" src="http://5ossfa.bay.livefilestore.com/y1p94hdI80Vma0D4gU_yppDaNgg_fnfRcImGOTyBnCrtPhwz9GtfV5HUeANwFwkeUTBE6BH9k2fNgIYYBV65Ew3nw?PARTNER=WRITER" width="773" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;So, It looks like the driver plays an important role too... &lt;/p&gt;&lt;p&gt;So to read the CID, so far I've found: &lt;/p&gt;&lt;p&gt;1) You can't get it if the reader is a USB device.
2) You can't get it if the driver doesn't like the DeviceIOControl call. &lt;/p&gt;&lt;p&gt;CreateFile path for the Volume: &lt;/p&gt;&lt;p&gt;There are 2 choices mentioned on forums/in documentation. "//./X:" or "//./PhysicalDriveX". There's another one with a guid too. &lt;/p&gt;&lt;p&gt;I've been using "//./X:" as it worked.
Maybe using the other path to get the handle will make a difference on the machine where I can't get it to work: &lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Fixedsys;font-size:100%;"&gt;C:\Users\SEP&amp;gt;wmic diskdrive get name,size,model
Model                 Name                Size
FUJITSU MHW2160BJ G2  \\.\PHYSICALDRIVE0  160039272960
SD Memory Card        \\.\PHYSICALDRIVE1  8225280&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;Edit: I'm now on about version 5 of my program and I'm using C#! So, I've moved from C++/CLI -&amp;gt; VB.Net -&amp;gt; C#...
It now works on the machine I mentioned above, and I'm using the physicaldrive string.
I'm trying to get Overlapped to work on x64 and x32, it seems there are some problems with NativeOverlapped. This will allow the call to read the CID and CSD to run on another thread, and the user to be notified when the results come back. (Reading the CID takes a noticable amount of time.) It requires a pointer, hence the move to C#. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3630456326553405434?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3630456326553405434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/sd-card-read-cidserial-number-musings.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3630456326553405434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3630456326553405434'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/sd-card-read-cidserial-number-musings.html' title='SD Card - Read CID/Serial number - Musings'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-4189092343611064377</id><published>2008-11-16T16:01:00.000Z</published><updated>2008-12-22T16:02:46.113Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='P/Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='C++ Invoke'/><category scheme='http://www.blogger.com/atom/ns#' term='FlashWindowEx'/><category scheme='http://www.blogger.com/atom/ns#' term='API'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>C++ Interop example. FlashWindowEx</title><content type='html'>&lt;p&gt;I've been using C++ occasionally instead of P/Invoke. I'm not a c++ programmer. &lt;/p&gt;  &lt;p&gt;Here's how to use c++ express 2008 and vb.net 2008 together to call a platform method. &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;First start C++.     
&lt;/li&gt;    &lt;li&gt;File-&amp;gt;New-&amp;gt;Project-&amp;gt; Project Type = CLR and use the Class Library template, set the project name to Flasher.    
&lt;/li&gt;    &lt;li&gt;Insert some code into Stdafx.h so that it looks like this:      &lt;blockquote&gt;       &lt;p&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;#pragma&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#000000;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;once            
#define&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color:#000000;"&gt; STRICT            
&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;#define&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color:#000000;"&gt; WIN32_LEAN_AND_MEAN            
&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#000000;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#a31515;"&gt;&lt;span style="font-size:85%;color:#a31515;"&gt;&amp;lt;windows.h&amp;gt;            
&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;using&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#000000;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;namespace&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color:#000000;"&gt; System;            
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;     &lt;/blockquote&gt;     &lt;span style="font-size:85%;"&gt;&lt;span style="color:#000000;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;/span&gt;      &lt;blockquote&gt;&lt;/blockquote&gt;      &lt;p&gt;      
You can see that we have included windows.h, which will give us access to many standard c++ types, such as BOOL.        
Windows.h is huge, so we set lean and mean too, which strips some infrequently used items -- they won't be included.       
#define STRICT is similar to Option Strict in vb.net. It stops you being lazy! &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Next we need to declare a class and a static method (which is a vb.net &lt;em&gt;Shared&lt;/em&gt; method):       
&lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;      &lt;blockquote&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;/span&gt;&lt;/span&gt;        &lt;p&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;// Flasher.h            
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;     &lt;/blockquote&gt;     &lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;#pragma&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#000000;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;once        
using&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#000000;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;namespace&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color:#000000;"&gt; System;        
&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;namespace&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color:#000000;"&gt; Flasher {        
   &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;ref&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;class&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; Flasher      
   {       
   &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;public&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;:      
      &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;static&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; Flash(IntPtr);      
   };       
}&lt;/span&gt; &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Now we add method code in the cpp file:      
&lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;      &lt;blockquote&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;/span&gt;&lt;/span&gt;        &lt;p&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;// This is the main DLL file.            
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;     &lt;/blockquote&gt;     &lt;span style="font-size:85%;color:#008000;"&gt;&lt;span style="font-size:85%;color:#008000;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#a31515;"&gt;&lt;span style="font-size:85%;color:#a31515;"&gt;"stdafx.h"        
&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;#include&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;span style="font-size:85%;color:#a31515;"&gt;&lt;span style="font-size:85%;color:#a31515;"&gt;"Flasher.h"        
        
&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;namespace&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; Flasher {      
   &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; Flasher::Flash(IntPtr hWndManaged)      
   {       
      FLASHWINFO info;       
      ZeroMemory(&amp;amp;info, &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;sizeof&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;(FLASHWINFO));      
      info.uCount = 5;       
      info.dwFlags = FLASHW_CAPTION;        
      info.dwTimeout = 0;       
      info.hwnd = (HWND) hWndManaged.ToPointer();       
      info.cbSize = &lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;sizeof&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;(info);      
      BOOL result = FlashWindowEx(&amp;amp;info);        
   } &lt;/span&gt;      &lt;p&gt;&lt;span style="font-size:85%;"&gt;}        
&lt;/span&gt;&lt;/p&gt;      &lt;p&gt;First we include those header files, so we get all of the methods and types declared in windows.h, and our own Flash method.      
Next we have the Flash method. To call FlashWindowEx you send a FLASHWINFO structure. If we were going to P/Invoke this,       
then we would need to declare our own versions of FlashWindowEx and FLASHWINFO. Here we don't have to, as we have the       
header files included. At the same time, this is a .Net dll, so our Flash method will be usable from VB.Net.       
      
After declaring a FLASHWINFO variable, we zero the memory. This is because C++ doesn't do it for us, we could get all sorts       
of junk in the new structure's fields if we don't do this. The &amp;amp; in &amp;amp;info is telling ZeroMemory the address where the info        
structure lives. We tell it to flash 5 times. We tell it to flash the caption. We tell it to flash at the default rate (= the systems        
cursor blink rate) by setting timeout to 0. Next we need to convert the managed IntPtr that is the windows Handle, into the        
unmanaged HWND type. This involves the ToPointer method, and a cast. Finally we set the structure size and send it off. &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Does it build? &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;No it doesn't. Unresolved token, and unresolved external symbol.       
There is a linker error, look at the &lt;a href="http://msdn.microsoft.com/en-us/library/ms679347%28VS.85%29.aspx"&gt;msdn page for FlashWindowEx&lt;/a&gt;:       
      
&lt;em&gt;Library: Use User32.lib        
        
&lt;/em&gt;This means that we need to link against User32.lib. We aren't, so we get the error.        
      
Right click the project name "Flasher" in the solution explorer. Click properties. Look at:       
      
Configuration Properties/Linker/Input/Additional Dependencies       
      
Make sure the additional dependencies line is selected and click the ellipsis (...).        
A quick glance makes you think user32 is linked, but actually the list is a list of thinks that can be inherited, but we have       
$(NoInherit) set. Add user32.lib to the listbox. Once done, click Ok, and you should see:       
Additional Dependencies: user32.lib $(NOINHERIT) &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Does it build? &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;No it doesn't.       
This time it's my antivirus software keeping the file open, causing a file access error:       
      
&lt;em&gt;"mt.exe : general error c101008d: Failed to write the updated manifest to the resource of file"&lt;/em&gt;        
      
One that's sorted, it builds. Add an antivirus exception for mt.exe.        
      
For me it lives here: (C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin) &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Start a new VB.Net project. Add a button.      
Click Project-&amp;gt;Add Reference, select the browse tab, navigate to the C++ dll that was built and add that. &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;Add the following to the button click code:&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;/p&gt;      &lt;p&gt;&lt;span style="font-size:85%;"&gt;Flasher.Flasher.Flash(&lt;/span&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;&lt;span style="font-size:85%;color:#0000ff;"&gt;Me&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;.Handle)&lt;/span&gt; &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;span style="font-size:85%;"&gt;Does it build? For me - yes!&lt;/span&gt; &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;Does it run? For me - no!        
      
I'm using Vista 64, and get:        
      
&lt;em&gt;"Could not load file or assembly 'Flasher, Version=1.0.3245.7081, Culture=neutral, PublicKeyToken=null'         
or one of its dependencies. An attempt was made to load a program with an incorrect format."         
&lt;/em&gt;       
This is fixed by setting the Target for the VB.Net program to x86, it was on AnyCPU, the dll is win32!       
      
In vb express you might need to do:       
Tools-&amp;gt;Options-&amp;gt;Projects and Solutions-&amp;gt;General-&amp;gt;Show Advanced Build Configurations       
      
then, you will need:       
Build-&amp;gt;Configuration Manager-&amp;gt;Active Solution Platform -- select &amp;lt;New&amp;gt; and x86 &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;It finally works. &lt;/p&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For a simple win32 api call this is too much work. It might be worth it for performance if you are calling something a lot.   
If you have a complicated api, then it pays off as you don't have to make managed versions of everything.    
If the method is in a static library then this is a good technique.     &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-4189092343611064377?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/4189092343611064377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/c-interop-example-flashwindowex.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4189092343611064377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/4189092343611064377'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/c-interop-example-flashwindowex.html' title='C++ Interop example. FlashWindowEx'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-7623224726911523699</id><published>2008-11-15T16:14:00.000Z</published><updated>2008-12-22T16:15:54.928Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SD Card'/><category scheme='http://www.blogger.com/atom/ns#' term='read serial number'/><category scheme='http://www.blogger.com/atom/ns#' term='SD Card CID'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Read secure digital (SD) card serial number from the CID</title><content type='html'>&lt;p&gt;(Quick link to an executable, this might read the serial number on Windows XP/Vista/32/64 when you are not using a USB card reader (so when you have the card in a slot on the side of a laptop it should work - though it depends on the driver!)). Requires .Net Framework 3.5.
&lt;iframe style="PADDING-RIGHT: 0pt; PADDING-LEFT: 0pt; PADDING-BOTTOM: 0pt; MARGIN: 3px; WIDTH: 240px; PADDING-TOP: 0pt; HEIGHT: 66px; BACKGROUND-COLOR: rgb(255,255,255)" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/ReadCID.zip" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;I got an email about a &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1044977&amp;amp;SiteID=1"&gt;post from ages ago on the msdn forums&lt;/a&gt; about reading the serial number from an SD Card. People want to do this as the number is factory stamped and unchangeable, so it could be used to protect programs from being copied. Distribute your program on an SD Card, have it check the serial, and have it fail if the number doesn't match a hard-coded version. Maybe there's more to it than that. But anyway the thread went along the lines of: &lt;/p&gt;&lt;p&gt;1) I want to read the serial
2) Someone suggested: Well use DeviceIOControl to send IOCTL_DISK_GET_STORAGEID to the drive. &lt;/p&gt;&lt;p&gt;At the time I'd just been playing with DeviceIOControl, and had spent ages working out how to use it from .Net. There weren't any useful examples that I could find. I was working at trying to make a CD Burner, using COM Interop to talk to IMAPI on XP (before IMAPI2). I'd learnt about DeviceIOControl, and how it can be used to send messages straight to a device. I used it to find out things that IMAPI couldn't tell you - like the exact media in the drive, and whether the drive was ready. I eventually got a vb.net program that could burn MP3s to CD. I never quite finished it though. I wasn't sure how to deal with all the possible errors during burning - there were so many! &lt;/p&gt;&lt;p&gt;I quickly wrote some code that demonstrated sending the message. I didn't know if the number was really the hardware stamped serial or whether it was just something windows dreamt up (like the volume serial you get with dir c:\). &lt;/p&gt;&lt;p&gt;I was asked again this week about this, and pointed in the direction of the concise SD specification (you can only see the big one if you pay $$$$, as it isn't an open standard). It's call the &lt;a href="http://www.sdcard.org/developers/tech/sdcard/pls/"&gt;simplified version of the physical layer spec&lt;/a&gt;. This describes various commands that can be sent. Command 10 returns the CID. The CID is the bit we are interested in, the Card IDentification register:
&lt;/p&gt;&lt;table cellspacing="0" cellpadding="2" width="382" border="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top" width="173"&gt;Name &lt;/td&gt;&lt;td valign="top" width="55"&gt;Field &lt;/td&gt;&lt;td valign="top" width="66"&gt;Width &lt;/td&gt;&lt;td valign="top" width="86"&gt;CID-slice &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;Manufacturer ID &lt;/td&gt;&lt;td valign="top" width="55"&gt;MID &lt;/td&gt;&lt;td valign="top" width="66"&gt;8 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[127:120] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;OEM/Application ID &lt;/td&gt;&lt;td valign="top" width="55"&gt;OID &lt;/td&gt;&lt;td valign="top" width="66"&gt;16 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[119:104] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;Product Name &lt;/td&gt;&lt;td valign="top" width="55"&gt;PNM &lt;/td&gt;&lt;td valign="top" width="66"&gt;40 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[103:64] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;Product Revision &lt;/td&gt;&lt;td valign="top" width="55"&gt;PRV &lt;/td&gt;&lt;td valign="top" width="66"&gt;8 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[63:56] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;Product Serial Number &lt;/td&gt;&lt;td valign="top" width="55"&gt;PSN &lt;/td&gt;&lt;td valign="top" width="66"&gt;32 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[55:24] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;reserved &lt;/td&gt;&lt;td valign="top" width="55"&gt;-- &lt;/td&gt;&lt;td valign="top" width="66"&gt;4 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[23:20] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;Manufacturing Date &lt;/td&gt;&lt;td valign="top" width="55"&gt;MDT &lt;/td&gt;&lt;td valign="top" width="66"&gt;12 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[19:8] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;CRC7 Checksum &lt;/td&gt;&lt;td valign="top" width="55"&gt;CRC &lt;/td&gt;&lt;td valign="top" width="66"&gt;7 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[7:1] &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top" width="174"&gt;not used, always 1 &lt;/td&gt;&lt;td valign="top" width="56"&gt;-- &lt;/td&gt;&lt;td valign="top" width="66"&gt;1 &lt;/td&gt;&lt;td valign="top" width="86"&gt;[0:0]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;There we have 128 bits used to identify the device. I was asked if the number that my earlier program grabbed was this number from the CID. I don't know...(edit - NO it isn't the same. &lt;span style="font-size:0;"&gt;&lt;span style="font-size:0;"&gt;IOCTL_DISK_GET_STORAGEID is useless - it gets a serial that Windows invents when it formats a volume.)
&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;I decided to try and get this CID number out, and I've managed to, &lt;strong&gt;but there are provisos&lt;/strong&gt;. My program (VB.Net) currently works only on Vista 64. Weirdly it only works when compiled for the x86 platform (the build target in visual studio). When I tried it on Vista 32 I got invalid handle errors. Sheesh. &lt;strong&gt;The other biggy is that it only works when the SD Card is plugged into a reader that is attached directly to the pci bus. If USB is involved in the chain, then the DeviceIOControl messages go to the USB host controller, and it doesn't understand them.&lt;/strong&gt; It works on my laptop's reader, but not on a fan controller/card reading gadget plugged in to my desktop as its card reader is attached via a USB header on the mobo.
&lt;/p&gt;&lt;p&gt;Here are some pics of the CIDs. They came out reversed, and the endianness of the serial number and manufacturer date were unhelpful. In the pics below, the 16 bytes are the ones I got in my buffer, but reversed order. They tally quite well with the above table. But, the leftmost byte (0 in each case) shouldn't be there, and we are missing the CRC and final bit. So it goes - Unspecified byte, MID, OID, OID, PNM, PNM, PNM, PNM, PNM, PRV, PSN, reserved+MDT, MDT. And the CRC is missing. &lt;/p&gt;&lt;p&gt;&lt;a href="http://byfiles.storage.msn.com/y1pAjsDh-RJG2mqvLodwLhtXxCzK0cKQlzAC8ush8xe1UnpdQXhUpXCrJXpAeuuLJna4h0bv-5ivOoSNF_mUwwzqg?PARTNER=WRITER"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="804" alt="CIDS" src="http://5ossfa.bay.livefilestore.com/y1pNCpDneCr_JnQJx6Gx1lwzk7TlgUr9cseSFJyR0Kj8WHXdAP20inn35iKe5SuOjg36g3rrS-1T3qZGqwHEDxtUg?PARTNER=WRITER" width="922" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;I bought the two Crucial 4GB cards at the same time, note the serial numbers are adrift by 2 - a good indication I'm not getting gobbledegook. The Manufacture date is mm/yyyy. Also the numbers tally with the hardware IDs found in Windows Device Manager, which are &lt;a href="http://www.blogger.com/Identifiers%20for%20Secure%20Digital%20%28SD%29%20Devices"&gt;described in the DDK&lt;/a&gt;, er WDK rather. &lt;a href="http://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx"&gt;Which you can get for free now&lt;/a&gt;. I bought the Veho card two weeks ago, looks like it was made just last month. It also looks like Vehos are made by Corsair - or maybe they are both made by some other company. Crucial don't fill in the product name or version, all the bytes were 0. &lt;/p&gt;&lt;p&gt;The bit where is says "This is an SD card", is because it also checks if the drive selected in the combobox is an SD card before attempting to get data. &lt;/p&gt;&lt;p&gt;So, how's it done? Well, you send an IOCTL specifying an SD Command with DeviceIOControl. Again it's &lt;a href="http://msdn.microsoft.com/en-us/library/ms789772.aspx"&gt;in the WDK&lt;/a&gt;. These are just user mode calls, so we aren't in the realms of writing a driver. The main difficulties were trying to decipher the documentation, which appears to be plain wrong in places. This lead to many many errors being returned by DeviceIOControl. Eventually I managed to send off command 0 without any complaint whatsoever, and figured I must be doing something right. I was using C++ code from &lt;a href="http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3979771&amp;amp;SiteID=1"&gt;elsewhere in the msdn forums&lt;/a&gt; and a bit of C++ Interop. I then got something back from cmd 10. I then went and did it in VB.Net instead as all this C++ was driving me mad. I can read it, but programming in it is a very laborious process for me. &lt;/p&gt;&lt;p&gt;I used IOCTL_SFFDISK_QUERY_DEVICE_PROTOCOL to check if a mount point was an SD card. Then IOCTL_SFFDISK_DEVICE_COMMAND to send cmd10. DeviceIOControl just takes the IOCTL code and a blob of memory - in .Net I used a byte array. The byte array contains a SFFDISK_DEVICE_COMMAND_DATA structure first, then the SDCMD_DESCRIPTOR. Both of these structures were 20 bytes big on x64 vista when using c++, so I made sure they were that size in .Net too. The Cmd field of SDCMD_DESCRIPTOR is very nasty. The documentation says to fill it with a value from the SD_COMMAND_CODE data type and lists two "allowed values". Well, both of those values give errors. Instead you should set the sd command code - i.e. 10 for command 10, 0 for command 0!!!!! After that structure I sent 16 bytes to receive the CID. And unfortunately I get 15 bytes of CID with a 00 in front and no CRC. Maybe I have some alignment problems with the structures. It might explain why my code isn't porting too. &lt;/p&gt;&lt;p&gt;I'll iron out the bugs and try and get it running on my dilapidated axim 50v too with the compact framework. I'm currently attempting to flash the rom on it to something newer. I nearly binned it last week in a grand tidy up. I'll have to download the academic version of Visual Studio, which is Pro, to do the windows mobile stuff. I've only got Standard (which was a MS freebie from the launch). Code to follow.



(note there are other, newer, posts on this on the blog, and some other code) &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-7623224726911523699?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/7623224726911523699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-secure-digital-sd-card-serial.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/7623224726911523699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/7623224726911523699'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/read-secure-digital-sd-card-serial.html' title='Read secure digital (SD) card serial number from the CID'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-2118237097543782060</id><published>2008-11-13T16:04:00.000Z</published><updated>2008-12-22T16:05:09.648Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='syncreon'/><category scheme='http://www.blogger.com/atom/ns#' term='dell'/><category scheme='http://www.blogger.com/atom/ns#' term='walsh western'/><category scheme='http://www.blogger.com/atom/ns#' term='call lock out'/><title type='text'>Dell Laptop - delivery tracking saying "call lock out"</title><content type='html'>&lt;p&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-family:Arial;font-size:100%;"&gt;&lt;span&gt;"This means your order is now ready for delivery and you will receive a call shortly to advise you of delivery date and options available for your order."&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt; &lt;/p&gt;  &lt;p&gt;That is an explanation of the strange "call lock out" stage you see when you use order tracking from &lt;span&gt;Syncreon (Walsh Western merged into this company) to see where your new dell gizmo is. I emailed them to find out what it meant. Whilst waiting for a reply, I got the automated call asking me to confirm the delivery time, and as soon as I hung up, a new bit had appeared on the tracking page showing the delivery date/time I arranged...&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-2118237097543782060?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/2118237097543782060/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/dell-laptop-delivery-tracking-saying.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2118237097543782060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/2118237097543782060'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/dell-laptop-delivery-tracking-saying.html' title='Dell Laptop - delivery tracking saying &amp;quot;call lock out&amp;quot;'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-3507596099748027556</id><published>2008-10-20T17:37:00.000+01:00</published><updated>2008-12-22T17:38:18.614Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open University'/><category scheme='http://www.blogger.com/atom/ns#' term='M366'/><category scheme='http://www.blogger.com/atom/ns#' term='exam'/><title type='text'>Open University M366 - exam post mortem</title><content type='html'>&lt;p&gt;The &lt;a href="http://www3.open.ac.uk/courses/bin/p12.dll?C01M366"&gt;M366&lt;/a&gt; results came in and I wrote a long post about it - but it disappeared. Great. &lt;/p&gt;  &lt;p&gt;  
M366 is an Open University course, level 3, 30 points (should be more!) entitled "Natural and Artificial Intelligence".    
I managed to get a distinction, with something like 96 in the continual assessment and 92 in the exam. It was hard work, so I'm glad the paper had no nasty surprises.    
&lt;/p&gt;  &lt;p&gt;So, for peeps thinking "Should I do M366"?  
Well - it depends.    
Are you interested and doing it for fun rather than aiming for a particular qualification? If so then yeah - have a go.    
Are you aiming for a degree and need a high mark to get the grade you want? If so then M366 might not be the best plan, the grade breakdown for our presentation (the first presentation) was: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://byfiles.storage.msn.com/y1p0Yo08j52_no03e7xEWS1jlXdshRD2djKyAfx13B1KuCuU9oQampG4RZbyIb4lzRCu6hyQsALycw?PARTNER=WRITER"&gt;&lt;img style="border: 0px none ;" alt="y1pCsc9c3qMQ0Nk-GV4-gJTc9lcRRtcUFlmcM9cBx6STg78u_rG9L8WuMPGvXsp1Hlp" src="http://byfiles.storage.msn.com/y1p_uCeOc7Dm_GnQGepynmg09prvJGygwDFtES-cu_XolPTIEqFKqv2CB6VqJ4SB6mjJCHhPXOdJ2U?PARTNER=WRITER" border="0" width="237" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;- so if you need a distinction there might be easier options. M366 is a lot more work than the other L3 I've taken so far (the &lt;a href="http://www3.open.ac.uk/courses/bin/p12.dll?C01M362" target="_blank"&gt;concurrency&lt;/a&gt; one).   
M366 is multidisciplinary - you have a bit of maths (quite light), logic, computer science, programming, history, &lt;a href="http://en.wikipedia.org/wiki/Philosophy_of_artificial_intelligence" target="_blank"&gt;philosophy of AI&lt;/a&gt;. Some people come in to the course wanting to read about themes of consciousness, and philosophy. Others come in wanting to learn algorithms to help with their programs. Two different camps, both find parts of the course unfamiliar and difficult.   
The dropout rate was high. &lt;/p&gt;  &lt;p&gt;  
If you do take M366 then... &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Read ahead early on, it doesn't matter if you fail to grasp 50% of it, just read it all early on to get the gist of the underlying themes. &lt;/li&gt;    &lt;li&gt;Allot more time to this than you usually do. I read the units twice before tackling the TMA, and again during the TMA. &lt;/li&gt;    &lt;li&gt;Don't go nuts. I did, I spent ages perfecting my TMAs, going much further than required with the coding section. We had a TMA question that asked for a &lt;a href="http://en.wikipedia.org/wiki/Heuristic_%28computer_science%29" target="_blank"&gt;heuristic for a search&lt;/a&gt; and I knew what they expected within a couple of minutes, but I didn't like it as a solution and spent days making a better version. It wasn't really worth the time. My heuristic was faster and found shorter solutions though - much better (their one overestimated - a cardinal sin!). &lt;/li&gt;    &lt;li&gt;Code some of it in &amp;lt;Insert you native programming language here&amp;gt;. I did some C# and VB.Net programs implementing search and genetic algorithms. It improved my understanding. &lt;/li&gt;    &lt;li&gt;Unit 6 is critical for the exam. There is a compulsory question. The subject matter is not maths/programming and so it needed a lot of work. Write notes on stuff like the &lt;a href="http://en.wikipedia.org/wiki/Chinese_Room" target="_blank"&gt;Chinese Room&lt;/a&gt;. Write an essay on the notes. Condense the essay down to something much shorter. Re-Write it the next day to reinforce your understanding. Do this for all the other junk in Unit 6. It will take a few days, but you will then be able to do the exam question easily. &lt;/li&gt;    &lt;li&gt;Netlogo. Many folk detested this. Some were not programmers, and so they were dunked in at the deep end. To those people, don't panic. You needn't write any code - if you can explain in words how it should work then you'll get marks. Once you work out that, you might be able to takle the coding. Some were programmers, and they hated the language. NetLogo is from a &lt;a href="http://www.levenez.com/lang/history.html"&gt;different branch of the programming language tree&lt;/a&gt; to most of the common programming languages - C, Java, VB, LoLCode, etc. You'll see it is a LISP-a-like. It is worth finding a tutorial on LISP and having a go at the basic syntax (or &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book.html"&gt;SICP&lt;/a&gt; if you are a glutton for punishment). I liked NetLogo. Write some simple programs - get used to lists of things and making your own data structures from lists.  &lt;/li&gt;    &lt;li&gt;Rote learn. Create some lists for the "compare and contrast" type questions and rote learn them... &lt;/li&gt;    &lt;li&gt;Don't leave TMAs until the last minute. You can't breeze through these ones as the Units are huge and complicated. I learnt miles more doing the TMAs than I did studying the units before doing the TMAs. &lt;/li&gt;    &lt;li&gt;Leave at least a fortnight of late nights for revision. &lt;/li&gt;    &lt;li&gt;Don't whinge if it is too hard. Take a look at the &lt;a href="http://ocw.mit.edu/OcwWeb/Electrical-Engineering-and-Computer-Science/6-034Fall-2006/CourseHome/index.htm"&gt;MIT courses&lt;/a&gt;...&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-3507596099748027556?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/3507596099748027556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/open-university-m366-exam-post-mortem.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3507596099748027556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/3507596099748027556'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/open-university-m366-exam-post-mortem.html' title='Open University M366 - exam post mortem'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-6973190765979956996</id><published>2008-10-15T17:18:00.000+01:00</published><updated>2008-12-22T17:20:18.112Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open University'/><category scheme='http://www.blogger.com/atom/ns#' term='MCQ'/><category scheme='http://www.blogger.com/atom/ns#' term='M256'/><category scheme='http://www.blogger.com/atom/ns#' term='M256/S'/><category scheme='http://www.blogger.com/atom/ns#' term='M362'/><title type='text'>Open University - M362/M256 exams over</title><content type='html'>&lt;p&gt;Exams finally over. I was a doofus and thought they were the coming Friday and Monday. I ended up with 4 nights for M362 and a weekend for M256 when I realised my mistake. I've no idea why, but I had the wrong date down on a bit of paper and I referred to the bit of paper whenever I wanted to work out how much longer I could procrastinate for. &lt;/p&gt;  &lt;p&gt;Anyway, the both went ok in the end. I'll guess a Grade 1 pass for M256, and a borderline 1/2 for M362. It would be very nice indeed for that to be a 1, as then I can relax for my 3 remaining Level 3s. Otherwise I'll need to concentrate hard on one of them to get a Grade 1 pass - you need 60 points at Grade 1 in Level 3 courses for a first. &lt;/p&gt;  &lt;p&gt;The past paper MCQ answers for M256, (Wednesday 17th October 2007 - M256/S) we reckoned to be: &lt;/p&gt;  &lt;table border="0" cellpadding="2" cellspacing="0" width="400"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="40"&gt;1 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;2 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;3 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;4 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;5 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;6 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;7 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;8 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;9 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;10 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="40"&gt;AD &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BD &lt;/td&gt;        &lt;td valign="top" width="40"&gt;DE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;CD &lt;/td&gt;        &lt;td valign="top" width="40"&gt;AE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BDF &lt;/td&gt;        &lt;td valign="top" width="40"&gt;CE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BC &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BF &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="40"&gt;11 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;12 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;13 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;14 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;15 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;16 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;17 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;18 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;19 &lt;/td&gt;        &lt;td valign="top" width="40"&gt;20 &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="40"&gt;BE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;CE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;C &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BD &lt;/td&gt;        &lt;td valign="top" width="40"&gt;ABF &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BD &lt;/td&gt;        &lt;td valign="top" width="40"&gt;BE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;AD &lt;/td&gt;        &lt;td valign="top" width="40"&gt;CE &lt;/td&gt;        &lt;td valign="top" width="40"&gt;C&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;5 - this is dumb, you read "an abstract class may have instances" and immediately think - "no way Hosé". But, in M256 parlance, they can have instances - these being instances of their concrete subclasses. Urgh. It's in the Glossary. &lt;/p&gt;  &lt;p&gt;M362 (2008) was deemed fair by most people taking it. Some bombed and are expecting re-sits. I did Q13, which was a bold move. The paper is available now. I reckoned I would drop 5 or 6 marks on Q12, especially as I didn't like the last part one bit (security managers / RMI). So, I took Q13 - I liked the last bit on JAAS, but now I'm not so sure. I found the terms &lt;em&gt;features&lt;/em&gt; and &lt;em&gt;resources&lt;/em&gt; in parts a and c confusing - too vague. I guess it will be a grade 2. Widdle. &lt;/p&gt;  &lt;p&gt;M256 (2008) was deemed unfair by most in the forum. A few people thought it went ok, I guess others are keeping quiet, not wanting to disturb the waters. The main complaints were the sheer volume of text you get for the main questions. They are pretty bulky, but most is just reference. Then folk didn't like the things you hand to copy out into your answer booklet and complete - a huge sequence diagram and a walk-through. I don't know if some people were using a ruler for their sequence diagrams. Don't, just scrawl it out. I ran out of room for mine. If your reading this with M256 approaching, then practice drawing a huge sequence diagram out on A4 - landscape, avoiding the edges (margins you can't write in). With 2 past papers available from the OU you should be in a better position to revise. I had a problem with Q23, I think there was a method missing in the protocol - so I had to make one up - a getter for something or other. I'll check when the paper comes out. I couldn't see another way of getting the information (alternative navigation of links, or cunning use of other methods), and the walk-through seemed to indicate that the thing was available without having to go via another object.    &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-6973190765979956996?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/6973190765979956996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/open-university-m362m256-exams-over.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/6973190765979956996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/6973190765979956996'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/open-university-m362m256-exams-over.html' title='Open University - M362/M256 exams over'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8214613500374285541.post-492340013011456258</id><published>2008-01-22T16:06:00.000Z</published><updated>2008-12-22T16:07:42.896Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='remove double space lines'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Macro'/><title type='text'>Visual studio macro to remove double spaced lines</title><content type='html'>&lt;div&gt;If you paste code into the MSDN forums straight from Visual Studio 2005, and then copy it back out and paste it in then you get double spaced lines. This is tedious as you often have to remove them to get the code to work.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;To fix it, posters can use a Macro to format the code as HTML: &lt;a href="http://www.codinghorror.com/blog/archives/000429.html" target="_blank"&gt;Coding Horror Copying Visual Studio Code Snippets to the Clipboard as HTML&lt;/a&gt;.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;If you want to strip the spaces from code you have pasted in then you can use a macro. I'll copy his ^^ instructions:&lt;/div&gt;  &lt;p&gt;Here's how to get started with this macro &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;go to Tools - Macros - IDE &lt;/li&gt;    &lt;li&gt;create a new Module named "DeDoubleSpace" under "MyMacros" &lt;/li&gt;    &lt;li&gt;Paste code into the module &lt;/li&gt;    &lt;li&gt;save and close the macro IDE window &lt;/li&gt;    &lt;li&gt;go to Tools - Macros - Macro Explorer &lt;/li&gt;    &lt;li&gt;The new macros will be under "DeDoubleSpace"; select the messy text and double click the macro.&lt;/li&gt; &lt;/ol&gt;  &lt;div    style=";font-family:monospace;font-size:10pt;color:white;"&gt;&lt;span style="color:blue;"&gt;Imports&lt;/span&gt;&lt;span style="color:black;"&gt; EnvDTE    
&lt;/span&gt;&lt;span style="color:blue;"&gt;Imports&lt;/span&gt;&lt;span style="color:black;"&gt; System    
&lt;/span&gt;&lt;span style="color:blue;"&gt;Imports&lt;/span&gt;&lt;span style="color:black;"&gt; System.Collections.Generic    
&lt;/span&gt;&lt;span style="color:blue;"&gt;Imports&lt;/span&gt;&lt;span style="color:black;"&gt; System.IO    
&lt;/span&gt;&lt;span style="color:blue;"&gt;Imports&lt;/span&gt;&lt;span style="color:black;"&gt; System.Text    
    
&lt;/span&gt;&lt;span style="color:blue;"&gt;Public&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Module&lt;/span&gt;&lt;span style="color:black;"&gt; DeDoubleSpace    
    
    &lt;/span&gt;&lt;span style="color:green;"&gt;' Remove double spaced lines from the selected text.    
&lt;/span&gt;&lt;span style="color:black;"&gt;    &lt;/span&gt;&lt;span style="color:blue;"&gt;Public&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;span style="color:black;"&gt; SelectedText()    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; textSelection1 &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; TextSelection = &lt;/span&gt;&lt;span style="color:blue;"&gt;DirectCast&lt;/span&gt;&lt;span style="color:black;"&gt;(DTE.ActiveDocument.Selection, TextSelection)    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; rawText &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;span style="color:black;"&gt; = textSelection1.Text    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; lines &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;New&lt;/span&gt;&lt;span style="color:black;"&gt; List(&lt;/span&gt;&lt;span style="color:blue;"&gt;Of&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;span style="color:black;"&gt;)    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Using&lt;/span&gt;&lt;span style="color:black;"&gt; sr &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;New&lt;/span&gt;&lt;span style="color:black;"&gt; StringReader(rawText)    
            lines = &lt;/span&gt;&lt;span style="color:blue;"&gt;New&lt;/span&gt;&lt;span style="color:black;"&gt; List(&lt;/span&gt;&lt;span style="color:blue;"&gt;Of&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;span style="color:black;"&gt;)    
            &lt;/span&gt;&lt;span style="color:blue;"&gt;Do&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;While&lt;/span&gt;&lt;span style="color:black;"&gt; sr.Peek &amp;gt; -1    
                lines.Add(sr.ReadLine())     
            &lt;/span&gt;&lt;span style="color:blue;"&gt;Loop    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Using    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;If&lt;/span&gt;&lt;span style="color:black;"&gt; lines.Count &amp;lt; 3 &lt;/span&gt;&lt;span style="color:blue;"&gt;Then&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Exit&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Sub    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:green;"&gt;' Find the first bit of text.    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; indexOfFirstLineWithText &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Integer&lt;/span&gt;&lt;span style="color:black;"&gt; = 0    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; done &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;&lt;span style="color:black;"&gt; = &lt;/span&gt;&lt;span style="color:blue;"&gt;False    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Do    
&lt;/span&gt;&lt;span style="color:black;"&gt;            &lt;/span&gt;&lt;span style="color:blue;"&gt;If&lt;/span&gt;&lt;span style="color:black;"&gt; lines(indexOfFirstLineWithText) &amp;lt;&amp;gt; &lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Then    
&lt;/span&gt;&lt;span style="color:black;"&gt;                done = &lt;/span&gt;&lt;span style="color:blue;"&gt;True    
&lt;/span&gt;&lt;span style="color:black;"&gt;            &lt;/span&gt;&lt;span style="color:blue;"&gt;Else    
&lt;/span&gt;&lt;span style="color:black;"&gt;                indexOfFirstLineWithText += 1    
            &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;If    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Loop&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Until&lt;/span&gt;&lt;span style="color:black;"&gt; done &lt;/span&gt;&lt;span style="color:blue;"&gt;Or&lt;/span&gt;&lt;span style="color:black;"&gt; indexOfFirstLineWithText = lines.Count    
        &lt;/span&gt;&lt;span style="color:green;"&gt;' Is the first line with text an odd or even line?    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; even &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;&lt;span style="color:black;"&gt; = (indexOfFirstLineWithText &lt;/span&gt;&lt;span style="color:blue;"&gt;Mod&lt;/span&gt;&lt;span style="color:black;"&gt; 2 = 0)    
        &lt;/span&gt;&lt;span style="color:green;"&gt;' If it is an even line, then check if all odd lines are blank    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:green;"&gt;' and vice versa.    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; allBlank &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;&lt;span style="color:black;"&gt; = &lt;/span&gt;&lt;span style="color:blue;"&gt;True&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:green;"&gt;' prove wrong    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; index &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Integer&lt;/span&gt;&lt;span style="color:black;"&gt; = IIf(even, 1, 0)    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Do    
&lt;/span&gt;&lt;span style="color:black;"&gt;            &lt;/span&gt;&lt;span style="color:blue;"&gt;If&lt;/span&gt;&lt;span style="color:black;"&gt; lines(index) &amp;lt;&amp;gt; &lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Then    
&lt;/span&gt;&lt;span style="color:black;"&gt;                allBlank = &lt;/span&gt;&lt;span style="color:blue;"&gt;False    
&lt;/span&gt;&lt;span style="color:black;"&gt;            &lt;/span&gt;&lt;span style="color:blue;"&gt;Else    
&lt;/span&gt;&lt;span style="color:black;"&gt;                index += 2    
            &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;If    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Loop&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Until&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Not&lt;/span&gt;&lt;span style="color:black;"&gt; allBlank &lt;/span&gt;&lt;span style="color:blue;"&gt;OrElse&lt;/span&gt;&lt;span style="color:black;"&gt; index &amp;gt; lines.Count - 1    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;If&lt;/span&gt;&lt;span style="color:black;"&gt; allBlank = &lt;/span&gt;&lt;span style="color:blue;"&gt;False&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Then&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Exit&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Sub    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:green;"&gt;' Create new text    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; sb &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;New&lt;/span&gt;&lt;span style="color:black;"&gt; StringBuilder    
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Dim&lt;/span&gt;&lt;span style="color:black;"&gt; i &lt;/span&gt;&lt;span style="color:blue;"&gt;As&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Integer    
&lt;/span&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;For&lt;/span&gt;&lt;span style="color:black;"&gt; i = IIf(even, 0, 1) &lt;/span&gt;&lt;span style="color:blue;"&gt;To&lt;/span&gt;&lt;span style="color:black;"&gt; lines.Count - 3 &lt;/span&gt;&lt;span style="color:blue;"&gt;Step&lt;/span&gt;&lt;span style="color:black;"&gt; 2    
            sb.AppendLine(lines(i))     
        &lt;/span&gt;&lt;span style="color:blue;"&gt;Next    
&lt;/span&gt;&lt;span style="color:black;"&gt;        sb.Append(lines(i))    
        &lt;/span&gt;&lt;span style="color:green;"&gt;' Alter the selection.  
&lt;/span&gt;&lt;span style="color:black;"&gt;        textSelection1.Delete()    
        textSelection1.Insert(sb.ToString)     
    &lt;/span&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Sub    
    
End&lt;/span&gt;&lt;span style="color:black;"&gt; &lt;/span&gt;&lt;span style="color:blue;"&gt;Module&lt;/span&gt; &lt;/div&gt; &lt;iframe style="border: 1px solid rgb(221, 229, 233); margin: 3px; padding: 0px; width: 240px; height: 66px; background-color: rgb(255, 255, 255);" marginwidth="0" marginheight="0" src="http://cid-862dee3ec267cb5c.skydrive.live.com/embedrowdetail.aspx/Public/DeDoubleSpace.vb" scrolling="no" frameborder="0"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8214613500374285541-492340013011456258?l=jo0ls-dotnet-stuff.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jo0ls-dotnet-stuff.blogspot.com/feeds/492340013011456258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/visual-studio-macro-to-remove-double.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/492340013011456258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8214613500374285541/posts/default/492340013011456258'/><link rel='alternate' type='text/html' href='http://jo0ls-dotnet-stuff.blogspot.com/2008/12/visual-studio-macro-to-remove-double.html' title='Visual studio macro to remove double spaced lines'/><author><name>jo0ls</name><uri>http://www.blogger.com/profile/15757538778397321155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_qnUNSzxixDU/SVGIwoV9siI/AAAAAAAAACg/gN9gKMQokLM/S220/p.jpg'/></author><thr:total>0</thr:total></entry></feed>
