Question

Problem using DeviceIoControl from C#

Asked by: idelson3647

I am converting a C++ application to C#.  The original code contains a number of Win32API calls that must be marshalled.  I have successfully gotten them all to work except the DeviceIoControl calls.  I have gotten some of my DeviceIoControl calls to work but I still can't get 3 of them to work and I don't understand why.  (What I haven't shown is that I call the CreateFile function before the DeviceIoControl call as the CreateFile call works propertly)
For reference the IOWrap in the code is the class where I declare the structures to be used in the marshalled calls.

Below I have listed the structure definitions I'm using, the declaration for the DeviceIoControl import and the code I am having trouble with.  In the code below I have listed the in the appropriate places the error messages I receive from the calls.  Any help would be appreciated as I am out of ideas.

// these struct definitions are in the class IOWrap
    [StructLayout(LayoutKind.Sequential)]
    public struct STORAGE_PROPERTY_QUERY 
    {
        public STORAGE_PROPERTY_ID PropertyId;          // ID of the property being retrieved
        public STORAGE_QUERY_TYPE QueryType;        // Flags indicating the type of query being performed
        public byte[] AdditionalParameters;                 // Space for additional parameters if necessary
    }
 
    [StructLayout(LayoutKind.Sequential)]
    public struct STORAGE_DEVICE_DESCRIPTOR 
    {
        ulong Version;              
        ulong Size;                
        byte DeviceType;            
        byte DeviceTypeModifier;   
        bool RemovableMedia;        
        bool CommandQueueing;      
        ulong ProductIdOffset;      
        ulong ProductRevisionOffset
        ulong SerialNumberOffset;   
        STORAGE_BUS_TYPE BusType;  device.
        ulong RawPropertiesLength;  
        byte RawDeviceProperties;  
} 
 
    [StructLayout(LayoutKind.Sequential)]
    public struct STORAGE_ADAPTER_DESCRIPTOR
    {
        public uint Version;
        public uint Size;
        public uint MaximumTransferLength;
        public uint MaximumPhysicalPages;
        public uint AlignmentMask;
        public bool AdapterUsesPio;
        public bool AdapterScansDown;
        public bool CommandQueueing;
        public bool AcceleratedTransfer;
        public byte BusType;
        public ushort BusMajorVersion;
        public ushort BusMinorVersion;
 
    }
[StructLayout(LayoutKind.Sequential)]
        public struct DRIVE_LAYOUT_INFORMATION
        {
            public uint PartitionCount;
            public uint Signature;
            public PARTITION_INFORMATION PartitionEntry;
        }
 
 
   [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public extern static bool DeviceIoControl(IntPtr hDevice,
                                                   uint IoControlCode,
                                                   IntPtr lpInBuffer,
                                                   int InBufferSize,
                                                   IntPtr lpOutBuffer,
                                                   int OutBufferSize,
                                                   ref int lpBytesReturned,
                                                   IntPtr lpOverlapped);
 
STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY();
           query.PropertyId = STORAGE_PROPERTY_ID.StorageDeviceProperty;
           query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery;
           query.AdditionalParameters = new byte[1];
 
           int returnedLength = 0;
           int nPtrQryBytes = Marshal.SizeOf(query);
           IntPtr ptrQry = Marshal.AllocHGlobal(nPtrQryBytes);
 
           STORAGE_DEVICE_DESCRIPTOR device = new STORAGE_DEVICE_DESCRIPTOR();
           int nDevicePtrBytes = Marshal.SizeOf(device);
           IntPtr ptrDevice = Marshal.AllocHGlobal(nDevicePtrBytes);
 
 
           bool status = IOWrap.DeviceIoControl(hDevice, IOWrap.IOCTL_STORAGE_QUERY_PROPERTY,
                                                ptrQry, nPtrQryBytes,
                                                ptrDevice, 512, //nDevicePtrBytes,
                                                ref returnedLength,
                                                IntPtr.Zero);
 
           string errMsg = new Win32Exception(Marshal.GetLastWin32Error()).Message;
// this errMsg says "The operation completed successfully"   HOWEVER, the value for returnedLength is 0 and the ptrDevice buffer has not been populated
 
STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY();
            query.PropertyId = STORAGE_PROPERTY_ID.StorageAdapterProperty;
            query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery;
            query.AdditionalParameters = new byte[1];
 
            // create ptr to query for DeviceIoControl
            int nPtrQryBytes = Marshal.SizeOf(query);
            IntPtr ptrQuery = Marshal.AllocHGlobal(nPtrQryBytes);
 
            STORAGE_ADAPTER_DESCRIPTOR adpDesc = new STORAGE_ADAPTER_DESCRIPTOR();
            int nAdpDescBytes = Marshal.SizeOf(adpDesc);
            IntPtr ptrAdpDesc = Marshal.AllocHGlobal(nAdpDescBytes);
            status = IOWrap.DeviceIoControl(hDevice,
                                            IOWrap.IOCTL_STORAGE_QUERY_PROPERTY,                                                ptrQuery,                                                                           
nPtrQryBytes,
  ptrAdpDesc,                                                                          512,                                                           
ref returnedLen,                                                                   I
ntPtr.Zero);
 
 
            
            string errMsg = new Win32Exception(Marshal.GetLastWin32Error()).Message;
           // note this call returns the following error - "An attempt was made to reference a token that does not exist"
 
// This following call works successfully every time
 IOWrap.DISK_GEOMETRY diskGeometry = new IOWrap.DISK_GEOMETRY();
           int nBytes = Marshal.SizeOf(diskGeometry);
           IntPtr pDiskGeometry = Marshal.AllocHGlobal(nBytes);
 
           status = IOWrap.DeviceIoControl(hDevice, (uint)IOWrap.EIOControlCode.DiskGetDriveGeometry,
                                           IntPtr.Zero, 0,
                                           pDiskGeometry, nBytes,
                                           ref returnedLength, IntPtr.Zero);
 
IOWrap.DRIVE_LAYOUT_INFORMATION layoutInfo = new IOWrap.DRIVE_LAYOUT_INFORMATION();
           nBytes = Marshal.SizeOf(layoutInfo);
           IntPtr pLayoutInfo = Marshal.AllocHGlobal(nBytes);
           returnedLength = 0;
 
           status = IOWrap.DeviceIoControl(hDevice, (uint)IOWrap.EIOControlCode.DiskGetDriveLayout,
                                           IntPtr.Zero, 0, 
                                           pLayoutInfo, 512,
                                           ref returnedLength,
                                           IntPtr.Zero);
 
 
// the following call sometimes works and sometimes throws an OutOfMemory Exception
IOWrap.DRIVE_LAYOUT_INFORMATION layoutInfo = new IOWrap.DRIVE_LAYOUT_INFORMATION();
           nBytes = Marshal.SizeOf(layoutInfo);
           IntPtr pLayoutInfo = Marshal.AllocHGlobal(nBytes);
           returnedLength = 0;
 
          status = IOWrap.DeviceIoControl(hDevice, (uint)IOWrap.EIOControlCode.DiskGetDriveLayout,
                                           IntPtr.Zero, 0, 
                                           pLayoutInfo, 512,
                                           ref returnedLength,
                                           IntPtr.Zero);
                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:

Select allOpen in new window

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2009-08-28 at 05:35:47ID24689546
Tags

C# .NET Runtime.Interop.Services Marshal Win32API

Topics

.NET

,

Microsoft Visual C#.Net

,

Microsoft Visual C++.Net

Participating Experts
1
Points
500
Comments
22

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. CreateFile
    If I open a serial port by CreateFile, do I have to use COM1 or //./COM1 ? Andrew
  2. How to use Win32API function ReadFile to check floppy di…
    I use CreateFile(), DeviceIoControl(), VirtualAlloc(), etc to check Floppy disk data's integrity without any problem in my VC++ 6.00 project. However, when I need to convert my VC++ project to VB 6.00, I use those Win32API function to do the same thing, I got unexpected probl...
  3. Shell Execute Simple Problem(In Win32Api)
    I want to Execute a .exe file placed at c:\games\duke.exe , tell me the routine or syntax of shellExecute in win32Api that execute duke.exe. Note that the program that execute Duke.exe may terminate after launching duke but duke will be terminatedmanually bu user. Plz also t...
  4. Win32API:: How to append data to an existing file
    My question is how useing Win32API functions CreateFile, WriteFile... Can I append to a existing text file. I wrote some code for (int nCount = 0; nCount < 3; nCount++){ fileLen = GetFileSize(hTmpBatch, NULL); ReadFile(hTmpBatch, buffer, fileLen, &len, NULL); WriteF...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: TheLearnedOnePosted on 2009-08-30 at 07:49:19ID: 25217840

Rather than use Win32 API calls that need to be marshalled, there might be an easier way to approach your problem with native C# code, but that would require understanding what the code is doing.

 

by: idelson3647Posted on 2009-08-30 at 16:05:59ID: 25219782

I have a lot of other Win32 API calls working successfully in the app already, including other calls using DeviceIoControl.  It is just the 2 DeviceIoControl calls that use the structure, STORAGE_PROPERTY_QUERY, as one of the parameters that I am having trouble with.  

Maybe down the road as a last resort I might try what you suggest, but not at this point.

Thanks.

 

by: TheLearnedOnePosted on 2009-08-31 at 06:22:59ID: 25222539

Well, the real problem is that I don't have enough understanding of what you are trying to do, in order to test and help.

Have you looked at pinvoke.net to see if there is a signature problem with the call?

 

by: idelson3647Posted on 2009-08-31 at 07:44:34ID: 25223192

Yes.  I loooked at pinvoke.net.  There are no entries for this structure, nor any of the others that are involved in my problem areas STORAGE_DEVICE_DESCRIPTOR and STORAGE_ADAPTER_DESCRIPTOR.  One needs to be careful when using pinvoke.net.  While it is helpful, it is after all, a WIKI, and there is a lot of false, contradicting or just plain wrong info on the site.

>Well, the real problem is that I don't have enough understanding of what you are trying to do
I will explain in more detail.  Tell me what it is that you need explained.  A 40,000 ft view of what I'm trying to do is get the properties of the USB devices attached to the computer - i.e. Partiton info, geometry, storage adapter info

Thanks

 

by: TheLearnedOnePosted on 2009-08-31 at 08:40:53ID: 25223686

Which calls are you having a problem with?

 

by: idelson3647Posted on 2009-08-31 at 10:06:13ID: 25224433

Two of  my DeviceIoControl calls are failing.  I have others that execute successfully.  The common link between the 2 failing calls is that they both have the structure IOCTL_STORAGE_QUERY_PROPERTY as a parameter.  I don't know if it is that parameter, or one of the structures I am trying to fill with data that is causing the problem.

One failing call is -


STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY();
query.PropertyId = STORAGE_PROPERTY_ID.StorageAdapterProperty;
query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery;
query.AdditionalParameters = new byte[1];
// create ptr to query for DeviceIoControl
int nPtrQryBytes = Marshal.SizeOf(query);
IntPtr ptrQuery = Marshal.AllocHGlobal(nPtrQryBytes);


// Get StorageAdapterProperty
STORAGE_ADAPTER_DESCRIPTOR adpDesc = new STORAGE_ADAPTER_DESCRIPTOR();
int nAdpDescBytes = Marshal.SizeOf(adpDesc);
IntPtr ptrAdpDesc = Marshal.AllocHGlobal(nAdpDescBytes);
status = IOWrap.DeviceIoControl(hDevice,
IOWrap.IOCTL_STORAGE_QUERY_PROPERTY, // Operation to perform
ptrQuery, // STORAGE_PROPERTY_QUERY
nPtrQryBytes,
ptrAdpDesc, // Output buffer
512, // Output buf size
ref returnedLen, // bytes returned
IntPtr.Zero);

errMsg = new Win32Exception(Marshal.GetLastWin32Error()).Message;
if (status == false)
return false;

The returned value of status is false and GetLastWin32Error returns "the parameter is incorrect".

the other call that fails is -


STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY();
query.PropertyId = STORAGE_PROPERTY_ID.StorageAdapterProperty;
query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery;
query.AdditionalParameters = new byte[1];
// create ptr to query for DeviceIoControl
int nPtrQryBytes = Marshal.SizeOf(query);
IntPtr ptrQuery = Marshal.AllocHGlobal(nPtrQryBytes);
// Get StorageAdapterProperty
STORAGE_ADAPTER_DESCRIPTOR adpDesc = new STORAGE_ADAPTER_DESCRIPTOR();
int nAdpDescBytes = Marshal.SizeOf(adpDesc);
IntPtr ptrAdpDesc = Marshal.AllocHGlobal(nAdpDescBytes);
status = IOWrap.DeviceIoControl(hDevice,
IOWrap.IOCTL_STORAGE_QUERY_PROPERTY, // Operation to perform
ptrQuery, // STORAGE_PROPERTY_QUERY
nPtrQryBytes,
ptrAdpDesc, // Output buffer
512, // Output buf size
ref returnedLen, // bytes returned
IntPtr.Zero);

// TODO: ILI ==> for test / debug
errMsg = new Win32Exception(Marshal.GetLastWin32Error()).Message;
if (status == false)
return false;

this returns a status value of true and the GetLastWin32Error returns "The operation completed successfully" but the value for returnedLen is 0 and the ptrAdpDesc buffer has not been populated.

All the structure definitions and dll imports are in the original code snippets I submitted.

Please note, that as I mentioned before, I have other DeviceIoControl calls that execute properly.  Only the ones that use the IOCTL_STORAGE_PROPERTY_QUERY structure fail.  It may be that structure or one of the other structures in those calls that are causing the problem.

thanks

 

by: TheLearnedOnePosted on 2009-08-31 at 10:32:34ID: 25224652

One problem that I have seen with Win32 API calls is the calculation of size from the Marshal.SizeOf method.  I would suggest that you compare the results to what you would expect from a structure.

Example:

            STORAGE_ADAPTER_DESCRIPTOR adapter = new STORAGE_ADAPTER_DESCRIPTOR();
            int size = Marshal.SizeOf(adapter);


Result = 44

        public struct STORAGE_ADAPTER_DESCRIPTOR
        {
            public uint Version;                //4
            public uint Size;                   //4
            public uint MaximumTransferLength;  //4
            public uint MaximumPhysicalPages;   //4
            public uint AlignmentMask;          //4
            public bool AdapterUsesPio;         //1
            public bool AdapterScansDown;       //1
            public bool CommandQueueing;        //1
            public bool AcceleratedTransfer;    //1
            public byte BusType;                //1
            public ushort BusMajorVersion;      //2
            public ushort BusMinorVersion;      //2
 
        }
 
Result = 29
 
 
            unsafe
            {
                Console.WriteLine("sbyte: {0}", sizeof(sbyte));
                Console.WriteLine("byte: {0}", sizeof(byte));
                Console.WriteLine("short: {0}", sizeof(short));
                Console.WriteLine("ushort: {0}", sizeof(ushort));
                Console.WriteLine("int: {0}", sizeof(int));
                Console.WriteLine("uint: {0}", sizeof(uint));
                Console.WriteLine("long: {0}", sizeof(long));
                Console.WriteLine("ulong: {0}", sizeof(ulong));
                Console.WriteLine("char: {0}", sizeof(char));
                Console.WriteLine("float: {0}", sizeof(float));
                Console.WriteLine("double: {0}", sizeof(double));
                Console.WriteLine("decimal: {0}", sizeof(decimal));
                Console.WriteLine("bool: {0}", sizeof(bool));
 
            }
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:

Select allOpen in new window

 

by: idelson3647Posted on 2009-08-31 at 12:31:52ID: 25225627

it is a possibility.  I'll look in to it.

thanks

 

by: idelson3647Posted on 2009-09-01 at 05:40:17ID: 25230910

I don't know why there is a difference in size between the marshalled and unmarshalled structure sizes (29 manually totaled vs 44 using Marshal.sizeof()).  I tried the call using both values, and neither one returned any data in the buffer

Thanks

 

by: TheLearnedOnePosted on 2009-09-01 at 06:42:23ID: 25231464

To understand that SizeOf problem, you have to think about how bytes are stored in the structure value type.  If you don't use explicit layout rules, then bytes are aligned on "natural offsets".  You can change that behavior with StructLayout(LayoutKind.Explicit), and set byte offsets for each field, or set Pack = 1 ([StructLayout(LayoutKind.Sequential, Pack = 1)].   The structure will now be organized so that each field is on a byte boundary and can be read a byte at a time.

 

by: idelson3647Posted on 2009-09-01 at 09:21:59ID: 25233152

Thanks for the explanation, but unfortunately, I still have the problem.

 

by: TheLearnedOnePosted on 2009-09-01 at 12:36:35ID: 25235127

It can be quite troublesome to get everything just right when converting from C++ to C#.  I have seen others who create VC++.NET managed wrappers in .NET to unmanaged C++ code, and then call that from C# applications.

I am a big proponent for getting hardware information with WMI.  I put together some test code to show you what I mean:

            Win32_DiskDrive drive = UsbDeviceHelper.DriveList[1];

            long size = drive.Size;
            int bytesPerSector = drive.BytesPerSector;
            int totalHeads = drive.TotalHeads;
            long totalCylinders = drive.TotalCylinders;
            long totalSectors = drive.TotalSectors;
            long totalTracks = drive.TotalTracks;
            int tracksPerCylinder = drive.TracksPerCylinder;
            string caption = drive.PartitionList[0].Caption;
            bool bootable = (int)drive.PartitionList[0].Bootable;

// Add a reference to System.Management.dll. 
 
using System;
using System.Management;
using System.Reflection;
using System.Collections.Generic;
 
 
public class UsbDeviceHelper
{
 
    private static Dictionary<int, Win32_DiskDrive> _driveList;
 
    static UsbDeviceHelper()
    {
        Win32_DiskDrive driveHelper = new Win32_DiskDrive();
 
        Dictionary<int, Win32_DiskDrive> allDrives = driveHelper.GetList();
 
        _driveList = new Dictionary<int, Win32_DiskDrive>();
 
        foreach (Win32_DiskDrive drive in allDrives.Values)
        {
            if (drive.InterfaceType == "USB")
            {
                _driveList.Add(drive.Index, drive);
            }
        }
 
    }
 
    public static Dictionary<int, Win32_DiskDrive> DriveList
    {
        get { return _driveList; }
    }
 
}
 
public class Win32_DiskPartition
{
    public ushort Access;
    public ushort Availability;
    public ulong BlockSize;
    public bool Bootable;
    public bool BootPartition;
    public string Caption;
    public uint ConfigManagerErrorCode;
    public bool ConfigManagerUserConfig;
    public string CreationClassName;
    public string Description;
    public string DeviceID;
    public uint DiskIndex;
    public bool ErrorCleared;
    public string ErrorDescription;
    public string ErrorMethodology;
    public uint HiddenSectors;
    public uint Index;
    public DateTime InstallDate;
    public uint LastErrorCode;
    public string Name;
    public ulong NumberOfBlocks;
    public string PNPDeviceID;
    public bool PrimaryPartition;
    public string Purpose;
    public bool RewritePartition;
    public ulong Size;
    public ulong StartingOffset;
    public string Status;
    public ushort StatusInfo;
    public string SystemCreationClassName;
    public string SystemName;
    public string Type;
 
    public static List<Win32_DiskPartition> GetList(int driveIndex)
    {
        string query = "Select * From Win32_DiskPartition Where DiskIndex=" + driveIndex;
 
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
 
        List<Win32_DiskPartition> list = new List<Win32_DiskPartition>();
 
        foreach (ManagementObject obj in searcher.Get())
        {
            Win32_DiskPartition entry = new Win32_DiskPartition();
 
            foreach (FieldInfo field in typeof(Win32_DiskPartition).GetFields())
                field.SetValue(entry, Conversion.ConvertValue(obj[field.Name], field.FieldType));
 
            list.Add(entry);
        }
        return list;
    }
 
}
 
public class Win32_DiskDrive
{
 
    public short Availability;
    public int BytesPerSector;
    public string CompressionMethod;
    public long DefaultBlockSize;
    public string Description;
    public string DeviceID;
    public bool ErrorCleared;
    public string ErrorDescription;
    public string ErrorMethodology;
    public int Index;
    public DateTime InstallDate;
    public string InterfaceType;
    public string Manufacturer;
    public long MaxBlockSize;
    public long MaxMediaSize;
    public bool MediaLoaded;
    public string MediaType;
    public long MinBlockSize;
    public string Model;
    public string Name;
    public bool NeedsCleaning;
    public int NumberOfMediaSupported;
    public int Partitions;
    public string PNPDeviceID;
    public bool PowerManagementSupported;
    public int SCSIBus;
    public short SCSILogicalUnit;
    public short SCSIPort;
    public short SCSITargetId;
    public int SectorsPerTrack;
    public long Signature;
    public long Size;
    public string Status;
    public short StatusInfo;
    public long TotalCylinders;
    public int TotalHeads;
    public long TotalSectors;
    public long TotalTracks;
    public int TracksPerCylinder;
 
    private List<Win32_DiskPartition> _partitionList;
 
    public List<Win32_DiskPartition> PartitionList
    {
        get { return _partitionList; }
    }
 
    public Dictionary<int, Win32_DiskDrive> GetList()
    {
        string query = "Select * From Win32_DiskDrive";
 
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
 
        Dictionary<int, Win32_DiskDrive> list = new Dictionary<int, Win32_DiskDrive>();
 
        foreach (ManagementObject obj in searcher.Get())
        {
            Win32_DiskDrive entry = new Win32_DiskDrive();
 
            foreach (FieldInfo field in typeof(Win32_DiskDrive).GetFields())
                field.SetValue(entry, Conversion.ConvertValue(obj[field.Name], field.FieldType));
 
            entry._partitionList = Win32_DiskPartition.GetList(entry.Index);
 
            list.Add(entry.Index, entry);
        }
        return list;
    }
 
}
 
internal class Conversion
{
 
    internal static object ConvertValue(object value, Type type)
    {
        if (value != null)
        {
            if (type == typeof(DateTime))
            {
                string time = value.ToString();
                time = time.Substring(0, time.IndexOf("."));
                return DateTime.ParseExact(time, "yyyyMMddHHmmss", null);
            }
            else if (type == typeof(long))
                return Convert.ToInt64(value);
            else if (type == typeof(int))
                return Convert.ToInt32(value);
            else if (type == typeof(short))
                return Convert.ToInt16(value);
            else if (type == typeof(string))
                return value.ToString();
        }
        return null;
    }
 
 
}

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:

Select allOpen in new window

 

by: idelson3647Posted on 2009-09-01 at 13:57:12ID: 25235972

I want the new app to be all in C# so I want to avoid created a Managed C++.NET wrapper.  As this problem has dragged on, I have been entertaining the idea of switching to WMI.  Your test code may be just the push I needed to switch gears.  As soon as I get a chance I will incorporate your test code in to an app and test it out.

 

by: TheLearnedOnePosted on 2009-09-01 at 14:18:27ID: 25236282

By the way, I just picked out a random sample of property values from the Win32_DiskDrive and Win32_DiskPartition classes that might be the type of values that you would be looking for.  

 

by: idelson3647Posted on 2009-09-03 at 12:38:30ID: 25254182

Hi,
I have looked over the WMI info you sent me and I think that is the way I am going to go.  I have even gone so far as to implement a simple WMI query in to my app.  I have the PNPDeviceID and I want the DeviceID so I used the query -
SELECT * FROM Win32_DiskDrive WHERE PNPDeviceID = "ide\\diskwdc_wd800aajs-00psa0____________________05.06h05\\5&1327b7ae&0&0.0.0"

I have some other info that I need to get about the device that I am not sure how to get.  For example, I need the bus type for the same device.  I am currently doing it in my code with DeviceIoControl like so -
 STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY();
            query.PropertyId = STORAGE_PROPERTY_ID.StorageAdapterProperty;
            query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery;
            query.AdditionalParameters = new byte[1];

            // create ptr to query for DeviceIoControl
            int nPtrQryBytes = Marshal.SizeOf(query);
            IntPtr ptrQuery = Marshal.AllocHGlobal(nPtrQryBytes);

            // Get StorageAdapterProperty
            STORAGE_ADAPTER_DESCRIPTOR adpDesc = new STORAGE_ADAPTER_DESCRIPTOR();
            int nAdpDescBytes = Marshal.SizeOf(adpDesc);
            IntPtr ptrAdpDesc = Marshal.AllocHGlobal(nAdpDescBytes);
            Marshal.StructureToPtr(adpDesc, ptrAdpDesc, true);
            status = IOWrap.DeviceIoControl(hDevice,
                                            IOWrap.IOCTL_STORAGE_QUERY_PROPERTY,    // Operation to perform
                                            ptrQuery,                               // STORAGE_PROPERTY_QUERY
                                            nPtrQryBytes,
                                            ptrAdpDesc,                             // Output buffer
                                            29,                                    // Output buf size
                                            ref returnedLen,                        // bytes returned
                                            IntPtr.Zero);


          adpDesc = (STORAGE_ADAPTER_DESCRIPTOR)Marshal.PtrToStructure(ptrAdpDesc, typeof(STORAGE_ADAPTER_DESCRIPTOR));
           
and then I can get the bus type form adpDesc.

I do not see a bus type as part of the Win32_DiskDrive class.   I Do see a Win32_Bus class, that has a BusType member.  I wonder if there is a way to do a join in a WMI query so that I can get the bus type given I have some other piece of data, in this case I have the PNPDeviceID.

I am also tryin to get RemovableMedia info, VendorIdOffset, ProductIdOffset, SerialNumberOffset among other things.  I was trying to use the following DeviceIoControl code -
 
              STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY();
           query.PropertyId = STORAGE_PROPERTY_ID.StorageDeviceProperty;
           query.QueryType = STORAGE_QUERY_TYPE.PropertyStandardQuery;
           query.AdditionalParameters = new byte[1];


           int nPtrQryBytes = Marshal.SizeOf(query);
           IntPtr ptrQry = Marshal.AllocHGlobal(nPtrQryBytes);

           IOWrap.STORAGE_DEVICE_DESCRIPTOR device = new IOWrap.STORAGE_DEVICE_DESCRIPTOR();
           int nDevicePtrBytes = Marshal.SizeOf(device);
           IntPtr ptrDevice = Marshal.AllocHGlobal(nDevicePtrBytes);


           bool status = IOWrap.DeviceIoControl(hDevice, IOWrap.IOCTL_STORAGE_QUERY_PROPERTY,
                                                ptrQry, nPtrQryBytes,
                                                ptrDevice, 512, //nDevicePtrBytes,
                                                ref returnedLength,
                                                IntPtr.Zero);

       
           errMsg = new Win32Exception(Marshal.GetLastWin32Error()).Message;

 device = (IOWrap.STORAGE_DEVICE_DESCRIPTOR)Marshal.PtrToStructure(ptrDevice, typeof(IOWrap.STORAGE_DEVICE_DESCRIPTOR));

and then would get the VendorIdOffset, ProductIdoffset etc from the device buffer.

Again, those values are not in the Win32_DiskDrive or Win32_Partition so would I have to make a join in my query?

Thanks

 

by: idelson3647Posted on 2009-09-03 at 12:51:30ID: 25254290

Hi,
I found that the Win32_Bus class does have a PNPDeviceID property so that problem is solved.  I'm still however need to get the VendorIdOffset, ProductIDOffset RemovableMedi info among other data but I just don't know what Win32_xxxx class it would be in.

thanks

 

by: idelson3647Posted on 2009-09-03 at 13:06:23ID: 25254402

Hi,
I've looked in to the Win32_Bus class and ran some queries through a query tool but it doesn't seem to be what I want.  when I run the query SELECT * FROM Win32_Bus where PNPDevice ID = (my device ID) it returns nothing.  If I run the query SELECT * FROM Win32_Bus, I get about 6 or 7 objects, only one of which has a PNPDeviceId and it does not match any of the USB devices I'm interested in.  I"m guessing that this PNPDeviceID is not the same PNPDeviceID I use in the Win32_DiskDrive query.  So that brings me back to my original question, of how to find the bus type

 

by: TheLearnedOnePosted on 2009-09-08 at 07:11:03ID: 25282024

Drive serial number:  Win32_PhysicalMedia
Manufacturer:  Win32_PhysicalMedia, Win32_DiskDrive
Product:  ?

 

by: idelson3647Posted on 2009-09-09 at 05:00:42ID: 25290218

Drive serial number:  Win32_PhysicalMedia
Manufacturer:  Win32_PhysicalMedia, Win32_DiskDrive
Product:  ?

I've looked at the Win32_DiskDrive and it seems that most of what I need (information similar to that that was being colleced with DeviceIoControl in the old code) is there but with names quite different than I was looking for.

I was unaware of the win32_PhysicalMedia class.  that looks like it would provide the info I need but when I run a query on my system - Select * from Win32_PhysicalMedia - the only field that gets populated is the tag (\\.\PhysicalDrive0, \\.\PhysicalDrive2, etc). None of the other fields return data?  Any thoughts.

You've been quite helpful.   How do I mark this issue closed and make sure you get the points associated with this issue?

thanks

 

by: TheLearnedOnePosted on 2009-09-09 at 09:35:08ID: 25292977

You can accept a comment as a solution.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...