How do I convert this to c# (Marshalling) - c#

I have these declarations (DLL) and tried to convert it in C# so i can call the functions from the DLL.
Same for struct1 to struct3
typedef struct1
{
int num;
char chars[25];
short shrt;
union
{
struct4 objstruct4;
}
}
typedef struct
{
Long Length;
short Type;
union
{
struct1 objStruct1;
struct2 objStruct2;
struct3 objStruct3;
}Data;
} Msg;
In C#, i converted these...same for struct1 to struct3
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct struct1
{
[MarshalAs(UnmanagedType.I4)]
public Int32 num;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = size + 1)]
public string chars;
[MarshalAs(UnmanagedType.I2)]
public short shrt;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct struct4
{
[MarshalAs(UnmanagedType.Struct)]
public ...
...
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
protected struct Msg
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.I4)]
public int Length;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.I2)]
public short Type;
[FieldOffset(6)]
[MarshalAs(UnmanagedType.Struct)]
public Data MsgData;
}
[StructLayout(LayoutKind.Explicit, Pack = 1, CharSet = CharSet.Ansi)]
public struct Data
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public struct1 objStruct1;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public struct2 objStruct2;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.Struct)]
public struct3 objStruct3;
}
Problem is when I tried to call a function from the DLL and passed the struct MSG as REF,
some member variables of the inner structs/union (struct1 to struct3) don't have values.
Its like they are rumbled inside the memory...
But when I remove the struct1 or struct2 in struct MSG, all of the member variables inside the remaining inner structs/union were successfully retrieved.
Can I ask your advice if my conversion is correct or did i missed something...
Or is there a better way to convert this or you have answers why this problem occur.
One thing that I suspect is the size of the struct, ANSI or Unicode, and the arrangement of the variables, structs.
Please advise - thanks.
sample 2:
////////////////
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct struct1
{
[MarshalAs(UnmanagedType.I4)]
public Int32 num1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = size + 1)]
public string chars;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct struct2
{
[MarshalAs(UnmanagedType.I4)]
public Int32 num2;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct struct3
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = size + 1)]
public string chars;
[MarshalAs(UnmanagedType.I4)]
public Int32 num3;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct struct4
{
[MarshalAs(UnmanagedType.I4)]
public Int32 num4;
[MarshalAs(UnmanagedType.Struct)]
public Data DataMsg;
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Data
{
//[FieldOffSet(0)]
public struct1 str1;
//[FieldOffSet(0)]
public struct2 str2;
//[FieldOffSet(0)]
public struct3 str3;
}
}
////////////////

There's no obvious reason why you chose Pack=1, the default for most C compilers is 8, just like .NET. MsgData at offset 6 is iffy. Use sizeof and offsetof() in a test C program to find out where everything is located. Compare with Marshal.SizeOf and OffsetOf() in a test C# program. This isn't going to work until they agree exactly.

Related

Call function in unmanaged DLL from C# with custom parameter

I've been trying to call from my C# application, a function in a C++ dll. This is what I have so far, but I don't know if I am on the right way or if I am doing something wrong. Since the function parameter is of custom type, I don't know how to proceed.
This is the function definition in C++
int GetDeviceList(
PRINTER_LIST* pList
);
and these are the parameters
#define MAX_PRINTER 32
typedef struct {
WCHAR name[128]; // printer name
WCHAR id[64]; // printer ID
WCHAR dev[64]; // device connection
WCHAR desc[256]; // description
int pid; // USB product ID
} PRINTER_ITEM;
typedef struct {
int n;
PRINTER_ITEM item[MAX_PRINTER];
} PRINTER_LIST;
So far I was able to convert the parameters
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct PrinterItem {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public string name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public string id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public string dev;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public string desc;
public int pid;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct PrinterList {
public int n;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public PrinterItem[] item;
}
and I have been trying to implement it into my program
public
class Program
{
[DllImport("dllName.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int GetDeviceList(_____);
static void Main(string[] args)
{
var deviceList = GetDeviceList(____);
}
}
I assume that your intent is to pass a single PrinterList by reference.
public
class Program
{
[DllImport("dllName.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int GetDeviceList(ref PrinterList list);
static void Main(string[] args)
{
PrinterList list = new PrinterList();
var deviceList = GetDeviceList(ref list);
}
}
Ensure that unmanaged dll uses Standard call invocation (your C declaration doesn't state it).
It should work.

Assigning values to the address user defined structure in c# called from unmanaged cpp

Consider the Following structure
/*Structure defined in unmanaged dll written in cpp*/
struct NSCASR_RCG_RES_ST
{
unsigned int ulSizeBytes;
unsigned int ulWarnings;
unsigned short usNumPhrases;
wchar_t* pstrWaveformURI;
unsigned int ulWaveformSizeBytes;
unsigned int ulWaveformDuration;
};
/*Structure defined in c#*/
struct NSCASR_RCG_RES_ST
{
unsigned int ulSizeBytes;
unsigned int ulWarnings;
unsigned short usNumPhrases;
String pstrWaveformURI;
unsigned int ulWaveformSizeBytes;
unsigned int ulWaveformDuration;
};
In my unmagaed DLL(cpp) I am calling the fucntion by passng the address of the structure as follows :
NSCASR_RCG_RES_ST result_recognize;
ASR_Recognize_ResultsGet(&result_recognize);
In my managed DLL the definition is like
void ASR_Recognize_ResultsGet(NSCASR_RCG_RES_ST *recognize)
{
/*MRCP_MD_TO_ASR is namespace and Constants is class name
which consists of structure NSCASR_RCG_RES_ST */
MRCP_MD_TO_ASR::Constants::NSCASR_RCG_RES_ST *pRecognitionResults;
pRecognitionResults = (MRCP_MD_TO_ASR::Constants::NSCASR_RCG_RES_ST *)recognize;
MRCP_MD_TO_ASR::ASR_API::ASR_Recognize_ResultsGet(*pRecognitionResults);
}
In c# code I am assigning the following members
public static int ASR_Recognize_ResultsGet(ref Constants.NSCASR_RCG_RES_ST pRecognitionResults)
{
pRecognitionResults = speech_results;
pRecognitionResults.ulSizeBytes = 200;
return 0;
}
But when I see the content of result_recognize after execution of statement
the value 200 is getting assigned to usNumPhrases variable instead of ulSizeBytes
I got the solution by adding structlayout as explicit and using charset as c# uses unicode 16 , we have to make it unicode 8 if we are using IntPtr concepts
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct NSCASR_RCG_PHRASE_ST
{
[FieldOffset(0)]
public ushort usConfidence;
[FieldOffset(2)]
public ushort usNumItems;
[FieldOffset(4)]
public short sGrammarIndex;
[FieldOffset(6)]
public short sGrammarType;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public unsafe struct NSCASR_RCG_RES_ST
{
[FieldOffset(0)]
public uint ulSizeBytes;
[FieldOffset(4)]
public uint ulWarnings;
[FieldOffset(8)]
public ushort usNumPhrases;
[FieldOffset(12)]
public IntPtr pstrWaveformURI;
[FieldOffset(16)]
public uint ulWaveformSizeBytes;
[FieldOffset(20)]
public uint ulWaveformDuration;
}

How to pass a structure to a c++ function and return the same with some modifications?

I have following struct in my c++ function.
struct Cam
{
char ip[16];
char login[16];
char pass[16];
char name[16];
};
Following is the method I have exposed from my cpp class-
extern "C" __declspec(dllexport) Cam* AddCameraStruct1(Cam cam)
{
//modify the cam object
}
Here is how I am defining the struct and function in c#.
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct Cam
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ip;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string login;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string pass;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string name;
}
[DllImport(#"mydll.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStruct)]
internal static extern IntPtr AddCameraStruct1(DPAPI.Cam*);
I am not getting how to consume this in c#.Please suggest if something is wrong.
unsafe
{
DPAPI.Cam cam = new DPAPI.Cam();
cam.ip = "192.168.0.232";
cam.login = "admin";
cam.pass = "admin";
cam.name = "kekekeke";
DPAPI.Cam* cam1 = (DPAPI.Cam*)DPAPI.AddCameraStruct1(cam);
}
I am getting following errors -
Pointers and fixed size buffers may only be used in an unsafe context
Cannot take the address of, get the size of, or declare a pointer to a managed type
You can't return structs from functions like you do, you can simply pass the struct by reference (this is how the whole Windows API is defined BTW).
Here is how to declare the struct, don't forget to indicate the charset is Ansi:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct Cam
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ip;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string login;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string pass;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string name;
}
Here is how to declare the method (the ref argument is like using a *):
[DllImport(#"mydll.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void AddCameraStruct1(ref Cam pcam);
Here is how to declare it in C/C++:
extern "C" __declspec(dllexport) void AddCameraStruct1(Cam *pcam)
{
strcpy_s(pcam->name, "hello"); // for example
}
Here is how you would call it now:
var cam = new Cam();
cam.ip = "192.168.0.232";
cam.login = "admin";
cam.pass = "admin";
cam.name = "kekekeke";
AddCameraStruct1(ref cam);
// cam.name is now "hello"
Note you don't need to use the unsafe keyword at all in your code.

How to PInvoke GetVirtualDiskInformation in C#

Full minimalist (non-working) code: http://pastebin.com/GPdSxyrt
I'm trying to PInvoke GetVirtualDiskInformation (https://msdn.microsoft.com/en-us/library/windows/desktop/dd323670(v=vs.85).aspx) and have my code as such:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfo
{
public GetVirtualDiskInfoVersion Version; //GET_VIRTUAL_DISK_INFO_VERSION
public GetVirtualDiskInfoUnion Union;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoUnion
{
[FieldOffset(0)] public GetVirtualDiskInfoSize Size;
[FieldOffset(0)] public Guid Identifier; //GUID
[FieldOffset(0)] public GetVirtualDiskInfoParentLocation ParentLocation;
[FieldOffset(0)] public Guid ParentIdentifier; //GUID
[FieldOffset(0)] public uint ParentTimestamp; //ULONG
[FieldOffset(0)] public VirtualStorageType VirtualStorageType; //VIRTUAL_STORAGE_TYPE
[FieldOffset(0)] public uint ProviderSubtype; //ULONG
[FieldOffset(0)] public bool Is4kAligned; //BOOL
[FieldOffset(0)] public bool IsLoaded; //BOOL
[FieldOffset(0)] public GetVirtualDiskInfoPhysicalDisk PhysicalDisk;
[FieldOffset(0)] public uint VhdPhysicalSectorSize; //ULONG
[FieldOffset(0)] public ulong SmallestSafeVirtualSize; //ULONGLONG
[FieldOffset(0)] public uint FragmentationPercentage; //ULONG
[FieldOffset(0)] public Guid VirtualDiskId; //GUID
[FieldOffset(0)] public GetVirtualDiskInfoChangeTrackingState ChangeTrackingState;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoSize
{
public ulong VirtualSize; //ULONGLONG
public ulong PhysicalSize; //ULONGLONG
public uint BlockSize; //ULONG
public uint SectorSize; //ULONG
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoParentLocation
{
public bool ParentResolved; //BOOL
public char ParentLocationBuffer; //WCHAR[1] //TODO
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoPhysicalDisk
{
public uint LogicalSectorSize; //ULONG
public uint PhysicalSectorSize; //ULONG
public bool IsRemote; //BOOL
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoChangeTrackingState
{
public bool Enabled; //BOOL
public bool NewerChanges; //BOOL
public char MostRecentId; //WCHAR[1] //TODO
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct VirtualStorageType
{
public VirtualStorageDeviceType DeviceId; //ULONG
public Guid VendorId; //GUID
}
public enum GetVirtualDiskInfoVersion
{
Unspecified = 0,
Size = 1,
Identifier = 2,
ParentLocation = 3,
ParentIdentifier = 4,
ParentTimestamp = 5,
VirtualStorageType = 6,
ProviderSubtype = 7,
Is4KAligned = 8,
PhysicalDisk = 9,
VhdPhysicalSectorSize = 10,
SmallestSafeVirtualSize = 11,
Fragmentation = 12,
IsLoaded = 13,
VirtualDiskId = 14,
ChangeTrackingState = 15
}
public enum VirtualStorageDeviceType
{
Unknown = 0,
Iso = 1,
Vhd = 2,
Vhdx = 3,
Vhdset = 4
}
[DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
public static extern uint GetVirtualDiskInformation
(
[In] VirtualDiskSafeHandle virtualDiskHandle,
[In, Out] ref uint virtualDiskInfoSize,
[In, Out] ref GetVirtualDiskInfo virtualDiskInfo,
[In, Out] ref uint sizeUsed
);
And I'm calling GetVirtualDiskInformation like so:
var info = new GetVirtualDiskInfo {Version = infoVersion};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);
Obviously handle does contain a valid VirtualDiskSafeHandle here.
The problem with this is that my out struct is all screwed up. The data is all over the place. According to it the VHD's LogicalSectorSize is 257 for example, and it has a negative VirtualSize.
What am I doing wrong and how can I get this to work properly?
EDIT:
A concrete example of what is going wrong:
I created a brand new VHDX as differencing (no parent, no source), set its max size to 50MB, LogicalSectorSize to 512, PhysicalSectorSize to 4096, BlockSize to 2MB and it's VendorId (GUID) to new Guid("EC984AEC-A0F9-47e9-901F-71415A66345B"). It has never been attached, it's size on disk stands at exactly 4096KB.
I would expect that when performing:
var info = new GetVirtualDiskInfo {Version = GetVirtualDiskInfoVersion.Size};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);
That info.Union.Size would return:
VirtualSize = 52428800
PhysicalSize = 4194304
BlockSize = 2097152
SectorSize = 512
What I get is "close enough". All values are correct with the exception of VirtualSize, which returns 52428801. Now the extra one byte could be something that is expected, but I doubt it. Regardless, the next couple of examples produces far worse results:
var info = new GetVirtualDiskInfo {Version = GetVirtualDiskInfoVersion.VirtualStorageType};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);
Expected results for info.Union.VirtualStorageType:
DeviceId = 2 //2 Symbolizes VHDX, which is how I created it
VendorId = "EC984AEC-A0F9-47e9-901F-71415A66345B" //As a GUID
Actual results:
DeviceId = 257
VendorId = "EC984AEC-A0F9-47e9-901F-71415A66345B" //As a GUID
In other words, the GUID is fine, the DeviceId is not. 257 is not even a valid value.
Last example:
var info = new GetVirtualDiskInfo {Version = GetVirtualDiskInfoVersion.PhysicalDisk};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);
Expected info.Union.PhysicalDisk to return:
LogicalSectorSize = 512
PhysicalSectorSize = 4096
IsRemote = false
Actual results:
LogicalSectorSize = 257
PhysicalSectorSize = 512
IsRemote = false
So again the very first value is completely wrong. 257 is not an accepted value, second value is also wrong, I'd expect 4096.
EDIT2 ADded VirtualStorageDeviceType to initial code.
EDIT3 Full example here: http://pastebin.com/GPdSxyrt
EDIT4
I worked out that the problem is with the fields that in C are WCHAR[1]. If I comment out the ChangeTrackingState in the struct GetVirtualDiskInfoUnion, then things work just fine.
Still, I'm not sure what to set them as in C#, they don't appear to be char nor IntPtr from what I tried, so what does that translate to exactly?
i do not have solution but noticed that if you add any uint field as last in structure it is also working correctly. My definition is:
public struct GetVirtualDiskInfoUnion
{
[FieldOffset(0)] public GetVirtualDiskInfoSize Size;
[FieldOffset(0)] public Guid Identifier; //GUID
[FieldOffset(0)] public GetVirtualDiskInfoParentLocation ParentLocation;
[FieldOffset(0)] public Guid ParentIdentifier; //GUID
[FieldOffset(0)] public uint ParentTimestamp; //ULONG
[FieldOffset(0)] public VirtualStorageType VirtualStorageType; //VIRTUAL_STORAGE_TYPE
[FieldOffset(0)] public uint ProviderSubtype; //ULONG
[FieldOffset(0)] public bool Is4kAligned; //BOOL
[FieldOffset(0)] public bool IsLoaded; //BOOL
[FieldOffset(0)] public GetVirtualDiskInfoPhysicalDisk PhysicalDisk;
[FieldOffset(0)] public uint VhdPhysicalSectorSize; //ULONG
[FieldOffset(0)] public ulong SmallestSafeVirtualSize; //ULONGLONG
[FieldOffset(0)] public uint FragmentationPercentage; //ULONG
[FieldOffset(0)] public Guid VirtualDiskId; //GUID
[FieldOffset(0)] public GetVirtualDiskInfoChangeTrackingState ChangeTrackingState;
[FieldOffset(0)] public uint Reserved; //ULONG
}

SetupDiEnumDeviceInterfaces on 64bit architecture on C#

I try to call Window API function SetupDiEnumDeviceInterfaces from C# on 64bits architecture.
I import function and declare additional structures.
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern bool SetupDiEnumDeviceInterfaces(
IntPtr deviceInfoSet,
SP_DEVINFO_DATA deviceInfoData,
ref Guid interfaceClassGuid,
int memberIndex,
SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVINFO_DATA
{
internal int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
internal Guid classGuid = Guid.Empty; // temp
internal int devInst = 0; // dumy
internal int reserved = 0;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal int cbSize;
internal short devicePath;
}
Then I call this function as follows:
int index = 0;
Guid _classGuid = Guid.Empty;
IntPtr _deviceInfoSet = IntPtr.Zero;
Native.SP_DEVICE_INTERFACE_DATA interfaceData = new Native.SP_DEVICE_INTERFACE_DATA();
if (!Native.SetupDiEnumDeviceInterfaces(_deviceInfoSet, null, ref _classGuid, index, interfaceData))
{
int error = Marshal.GetLastWin32Error();
if (error != Native.ERROR_NO_MORE_ITEMS)
throw new Win32Exception(error);
break;
}
If runnig on 32bits architecture then all is well.
If runnig on 64bits architecture then SetupDiEnumDeviceInterfaces return false with last win error equal 1784.
The reason is that in struct interfaceData field cbSize has not valid value for 64bits architecture(as int alias Int32).
From official documentation
DeviceInterfaceData [out] A pointer to a caller-allocated buffer that
contains, on successful return, a completed SP_DEVICE_INTERFACE_DATA
structure that identifies an interface that meets the search
parameters. The caller must set DeviceInterfaceData.cbSize to
sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function.
Trying to replace the type int(alias Int32) of the type Int64 for fields: cbSize, devInt, reserved.
How Can I replace class Guid for 64bits architecture?
If I try replace Guid simply of the type long:
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVICE_INTERFACE_DATA
{
internal Int64 cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
internal long interfaceClassGuid = 0; // temp
internal Int64 flags = 1;
internal Int64 reserved = 0;
}
With such a structure definition all works but I lose the convenience of working with a special class for guid. In the class definition Guid also used the type int so the right size will not be calculated on 64bits architecture.
You need to use uint in all fields(not int), and IntPtr in Reserved field.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVINFO_DATA
{
public uint cbSize;
public Guid ClassGuid;
public uint DevInst;
public IntPtr Reserved;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DATA
{
public uint cbSize;
public Guid InterfaceClassGuid;
public uint Flags;
public IntPtr Reserved;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public uint cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DevicePath;
}
To set cbSize in code use this:
Win32.SP_DEVICE_INTERFACE_DATA did = new Win32.SP_DEVICE_INTERFACE_DATA();
did.cbSize = (uint)Marshal.SizeOf(did);
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)Marshal.SizeOf(didd);
You might try setting your
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
to:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
From what I've read, Pack = 8 for 32 bit, Pack = 1 for 64 bit.
The problem is not your GUID declarations; the reason SetupDiEnumDeviceInterfaces is failing out on 64-bit platforms is that you're not using the correct data type for the reserved field on each of SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA.
The structure definitions for SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA show that the reserved fields are declared as UINT_PTR, which is a pointer type. These should be declared in your P/Invoke types as IntPtr.
(Also, all of your int fields should instead be defined as uint, as those fields map to the DWORD native type.)
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVINFO_DATA
{
internal uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
internal Guid classGuid;
internal uint devInst;
internal IntPtr reserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal uint cbSize;
internal short devicePath;
}
[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVICE_INTERFACE_DATA
{
internal uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
internal Guid interfaceClassGuid;
internal uint flags;
internal IntPtr reserved;
}

Categories