Problem passing structs in C#?

S

Schorschi

Can someone please point out why I am getting an 87 error? I am sure
it is obvious, but I am new to C# and seem to be having a lot of
stress understanding managed versus unmanaged code when API calls are
needed!

//

using System;
using System.Runtime.InteropServices;

//

namespace DeviceClassLibrary
{
/// <summary>
/// Device Class Library.
/// </summary>

//

//typedef struct _SP_DEVINFO_DATA
// {
// DWORD cbSize;
// GUID ClassGuid;
// DWORD DevInst;
// ULONG_PTR Reserved;
// } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

[StructLayout(LayoutKind.Sequential)]
public struct _SP_DEVINFO_DATA
{
//

public Int32 theSize;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=16)]
public byte[] theClass;
public Int32 theInstance;
public Int64 theReserved;
}

//typedef struct _SP_DEVICE_INTERFACE_DATA
// {
// DWORD cbSize;
// GUID InterfaceClassGuid;
// DWORD Flags;
// ULONG_PTR Reserved;
// } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

[StructLayout(LayoutKind.Sequential)]
public struct _SP_DEVICE_INTERFACE_DATA
{
//

public Int32 theSize;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=16)]
public byte[] theClass;
public Int32 theFlags;
public Int64 theReserved;
}

//typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA
// {
// DWORD cbSize;
// TCHAR DevicePath[ANYSIZE_ARRAY];
// } SP_DEVICE_INTERFACE_DETAIL_DATA,
*PSP_DEVICE_INTERFACE_DETAIL_DATA;

[StructLayout(LayoutKind.Sequential)]
public struct _SP_DEVICE_INTERFACE_DETAIL_DATA
{
//

public int theSize;
public byte[] thePath;
}

//

public enum DeviceError
{
//

Success = 0
}

public class DeviceClass
{
//

[DllImport("SETUPAPI", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs (
byte[] theClass,
IntPtr theEnumerator,
IntPtr theOwner,
int theFlags);

[DllImport("SETUPAPI", SetLastError = true)]
private static extern bool SetupDiDestroyDeviceInfoList(
IntPtr theHandle
);

[DllImport("SETUPAPI", SetLastError = true)]
private static extern bool SetupDiEnumDeviceInfo(
IntPtr theHandle,
int theIndex,
_SP_DEVINFO_DATA theData);

// Constructor...

public DeviceClass()
{
//

}

// Destructor...

~DeviceClass()
{
//

}

public int Enumerate(string theClass, int theCode, ref IntPtr
theHandle)
{
int theResult = (int)DeviceError.Success;
Guid theGuid;

//


theGuid = new Guid(theClass);

theHandle = SetupDiGetClassDevs
(theGuid.ToByteArray(), IntPtr.Zero, IntPtr.Zero, theCode);

//

return (theResult);
}

public int UnEnumerate(ref IntPtr theHandle)
{
int theResult = (int)DeviceError.Success;

//

theHandle = IntPtr.Zero;

return (theResult);
}

public int RegistryProperty(IntPtr theHandle, int theIndex)
{
int theResult = (int)DeviceError.Success;
_SP_DEVINFO_DATA theData = new _SP_DEVINFO_DATA();
//Buffer theBuffer;
//int theSize;
bool thePropertyOrNot;

//

theData.theSize = Marshal.SizeOf(typeof(_SP_DEVINFO_DATA));

thePropertyOrNot = SetupDiEnumDeviceInfo(theHandle, theIndex,
theData);

theResult = Marshal.GetLastWin32Error();

return (theResult);
}
}
}
 
C

Chris LaJoie

what is SETUPAPI? is it a dll? If so, you should use the full name
SETUPAPI.dll.
Also, I wouldn't be able to test your code because I don't have that dll.
Do you have a C/C++ header file that you pulled those APIs from? if you do,
that would be extremely helpful in determining if your struct definitions
are correct.




Schorschi said:
Can someone please point out why I am getting an 87 error? I am sure
it is obvious, but I am new to C# and seem to be having a lot of
stress understanding managed versus unmanaged code when API calls are
needed!

//

using System;
using System.Runtime.InteropServices;

//

namespace DeviceClassLibrary
{
/// <summary>
/// Device Class Library.
/// </summary>

//

//typedef struct _SP_DEVINFO_DATA
// {
// DWORD cbSize;
// GUID ClassGuid;
// DWORD DevInst;
// ULONG_PTR Reserved;
// } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

[StructLayout(LayoutKind.Sequential)]
public struct _SP_DEVINFO_DATA
{
//

public Int32 theSize;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=16)]
public byte[] theClass;
public Int32 theInstance;
public Int64 theReserved;
}

//typedef struct _SP_DEVICE_INTERFACE_DATA
// {
// DWORD cbSize;
// GUID InterfaceClassGuid;
// DWORD Flags;
// ULONG_PTR Reserved;
// } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

[StructLayout(LayoutKind.Sequential)]
public struct _SP_DEVICE_INTERFACE_DATA
{
//

public Int32 theSize;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=16)]
public byte[] theClass;
public Int32 theFlags;
public Int64 theReserved;
}

//typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA
// {
// DWORD cbSize;
// TCHAR DevicePath[ANYSIZE_ARRAY];
// } SP_DEVICE_INTERFACE_DETAIL_DATA,
*PSP_DEVICE_INTERFACE_DETAIL_DATA;

[StructLayout(LayoutKind.Sequential)]
public struct _SP_DEVICE_INTERFACE_DETAIL_DATA
{
//

public int theSize;
public byte[] thePath;
}

//

public enum DeviceError
{
//

Success = 0
}

public class DeviceClass
{
//

[DllImport("SETUPAPI", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs (
byte[] theClass,
IntPtr theEnumerator,
IntPtr theOwner,
int theFlags);

[DllImport("SETUPAPI", SetLastError = true)]
private static extern bool SetupDiDestroyDeviceInfoList(
IntPtr theHandle
);

[DllImport("SETUPAPI", SetLastError = true)]
private static extern bool SetupDiEnumDeviceInfo(
IntPtr theHandle,
int theIndex,
_SP_DEVINFO_DATA theData);

// Constructor...

public DeviceClass()
{
//

}

// Destructor...

~DeviceClass()
{
//

}

public int Enumerate(string theClass, int theCode, ref IntPtr
theHandle)
{
int theResult = (int)DeviceError.Success;
Guid theGuid;

//


theGuid = new Guid(theClass);

theHandle = SetupDiGetClassDevs
(theGuid.ToByteArray(), IntPtr.Zero, IntPtr.Zero, theCode);

//

return (theResult);
}

public int UnEnumerate(ref IntPtr theHandle)
{
int theResult = (int)DeviceError.Success;

//

theHandle = IntPtr.Zero;

return (theResult);
}

public int RegistryProperty(IntPtr theHandle, int theIndex)
{
int theResult = (int)DeviceError.Success;
_SP_DEVINFO_DATA theData = new _SP_DEVINFO_DATA();
//Buffer theBuffer;
//int theSize;
bool thePropertyOrNot;

//

theData.theSize = Marshal.SizeOf(typeof(_SP_DEVINFO_DATA));

thePropertyOrNot = SetupDiEnumDeviceInfo(theHandle, theIndex,
theData);

theResult = Marshal.GetLastWin32Error();

return (theResult);
}
}
}
 
W

Willy Denoyette [MVP]

One of the Win32 Function arguments is wrong (error code 87).

ULONG_PTR is a 32 bit pointer, you specified a Int64 (64 bits value).
as a result -
theData.theSize = Marshal.SizeOf(typeof(_SP_DEVINFO_DATA));
will return the wrong size.

Willy.


Schorschi wrote:
|| Can someone please point out why I am getting an 87 error? I am sure
|| it is obvious, but I am new to C# and seem to be having a lot of
|| stress understanding managed versus unmanaged code when API calls are
|| needed!
||
|| //
||
|| using System;
|| using System.Runtime.InteropServices;
||
|| //
||
|| namespace DeviceClassLibrary
|| {
|| /// <summary>
|| /// Device Class Library.
|| /// </summary>
||
|| //
||
|| //typedef struct _SP_DEVINFO_DATA
|| // {
|| // DWORD cbSize;
|| // GUID ClassGuid;
|| // DWORD DevInst;
|| // ULONG_PTR Reserved;
|| // } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
||
|| [StructLayout(LayoutKind.Sequential)]
|| public struct _SP_DEVINFO_DATA
|| {
|| //
||
|| public Int32 theSize;
|| [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=16)]
|| public byte[] theClass;
|| public Int32 theInstance;
|| public Int64 theReserved;
|| }
||
|| //typedef struct _SP_DEVICE_INTERFACE_DATA
|| // {
|| // DWORD cbSize;
|| // GUID InterfaceClassGuid;
|| // DWORD Flags;
|| // ULONG_PTR Reserved;
|| // } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
||
|| [StructLayout(LayoutKind.Sequential)]
|| public struct _SP_DEVICE_INTERFACE_DATA
|| {
|| //
||
|| public Int32 theSize;
|| [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst=16)]
|| public byte[] theClass;
|| public Int32 theFlags;
|| public Int64 theReserved;
|| }
||
|| //typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA
|| // {
|| // DWORD cbSize;
|| // TCHAR DevicePath[ANYSIZE_ARRAY];
|| // } SP_DEVICE_INTERFACE_DETAIL_DATA,
|| *PSP_DEVICE_INTERFACE_DETAIL_DATA;
||
|| [StructLayout(LayoutKind.Sequential)]
|| public struct _SP_DEVICE_INTERFACE_DETAIL_DATA
|| {
|| //
||
|| public int theSize;
|| public byte[] thePath;
|| }
||
|| //
||
|| public enum DeviceError
|| {
|| //
||
|| Success = 0
|| }
||
|| public class DeviceClass
|| {
|| //
||
|| [DllImport("SETUPAPI", SetLastError = true)]
|| private static extern IntPtr SetupDiGetClassDevs (
|| byte[] theClass,
|| IntPtr theEnumerator,
|| IntPtr theOwner,
|| int theFlags);
||
|| [DllImport("SETUPAPI", SetLastError = true)]
|| private static extern bool SetupDiDestroyDeviceInfoList(
|| IntPtr theHandle
|| );
||
|| [DllImport("SETUPAPI", SetLastError = true)]
|| private static extern bool SetupDiEnumDeviceInfo(
|| IntPtr theHandle,
|| int theIndex,
|| _SP_DEVINFO_DATA theData);
||
|| // Constructor...
||
|| public DeviceClass()
|| {
|| //
||
|| }
||
|| // Destructor...
||
|| ~DeviceClass()
|| {
|| //
||
|| }
||
|| public int Enumerate(string theClass, int theCode, ref IntPtr
|| theHandle)
|| {
|| int theResult = (int)DeviceError.Success;
|| Guid theGuid;
||
|| //
||
||
|| theGuid = new Guid(theClass);
||
|| theHandle = SetupDiGetClassDevs
|| (theGuid.ToByteArray(), IntPtr.Zero, IntPtr.Zero, theCode);
||
|| //
||
|| return (theResult);
|| }
||
|| public int UnEnumerate(ref IntPtr theHandle)
|| {
|| int theResult = (int)DeviceError.Success;
||
|| //
||
|| theHandle = IntPtr.Zero;
||
|| return (theResult);
|| }
||
|| public int RegistryProperty(IntPtr theHandle, int theIndex)
|| {
|| int theResult = (int)DeviceError.Success;
|| _SP_DEVINFO_DATA theData = new _SP_DEVINFO_DATA();
|| //Buffer theBuffer;
|| //int theSize;
|| bool thePropertyOrNot;
||
|| //
||
|| theData.theSize = Marshal.SizeOf(typeof(_SP_DEVINFO_DATA));
||
|| thePropertyOrNot = SetupDiEnumDeviceInfo(theHandle, theIndex,
|| theData);
||
|| theResult = Marshal.GetLastWin32Error();
||
|| return (theResult);
|| }
|| }
|| }
 
S

Schorschi

Willy,

Thx. Will fix that and try again. Hey do you know of any offical
SetupDi API call examples in VB .NET or C# .NET? Writing in straight
C is where all the examples are on Google, MSDN, etc. How do we
request of Microsoft to do a write-up on this? Maybe a rewrite of
EnumDisks? The official SetupDi API example in the DDK? In .NET C#
or VB? It is only in straight C.

Seems like a look of interest in this based on all the questions
asking for help?

Schor-
 
W

Willy Denoyette [MVP]

Schorschi wrote:
|| Willy,
||
|| Thx. Will fix that and try again. Hey do you know of any offical
|| SetupDi API call examples in VB .NET or C# .NET? Writing in straight
|| C is where all the examples are on Google, MSDN, etc. How do we
|| request of Microsoft to do a write-up on this? Maybe a rewrite of
|| EnumDisks? The official SetupDi API example in the DDK? In .NET C#
|| or VB? It is only in straight C.
||
|| Seems like a look of interest in this based on all the questions
|| asking for help?
||
|| Schor-

Schor,

The Device management API's are specialized API's written to be used from an interactive management application (more specifically
the "control panel" Devices applets and the Device Manager application), some API's expect a UI (HWND) to send messages to .
Don't expect MSFT will ever release Managed classes wrapping this (and many other) API set.

I would never use these API's from C# (or VB.NET) using PInvoke, instead I would:

1 - use ME C++ to write a managed wrapper class if I need additional functionality not offered by 2
2 - use the System.Management namespace classes and WMI.

Following is a small sample using the latter:

using System;
using System.Management;
// Enum Pnp Registered devices using WMI class Win32_PnPentity
class App {
public static void Main() {
ManagementPath path = new ManagementPath();
ManagementClass devs = null;
path.Server = "."; // local machine
path.NamespacePath = @"root\CIMV2";
path.RelativePath = @"Win32_PnPentity";
using(devs = new ManagementClass(new ManagementScope(path), path, new ObjectGetOptions(null, new TimeSpan(0,0,0,2), true)))
{
ManagementObjectCollection moc = devs.GetInstances();
foreach(ManagementObject mo in moc) {

PropertyDataCollection devsProperties = mo.Properties;
foreach (PropertyData devProperty in devsProperties ) {
Console.WriteLine("Property = {0}\t Value = {1}", devProperty.Name, devProperty.Value);
}
}

}

}
}

Hope this helps.

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top