Calling Unmanaged C++ code with array of structure in C# - c#

The following is my C++ declaration of the function:
unsigned moduleDescription (unsigned modulnumber, char * const name, t_c_pindescription * const p_inputs, t_c_pindescription * const p_outputs, t_c_pindescription * const p_intern);
The following is my C++ Structure Definition:
#pragma pack(push,4)
typedef struct
{
char name[256];
char dim[64];
enum SigTypetype;
} t_c_pindescription;
typdef enum SigType
{
T_ANALOG = 1,
T_BINARY = 2,
T_OPTIONAL
};
#pragma pack(pop)
The following is my C# Client code:
public class Program
{
[StructLayoutAttribute(LayoutKind.Sequential,CharSet = CharSet.Unicode)]
public struct t_c_pindescription
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 256)]
public string pinname;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 64)]
public string Dimension;
public SigType mType;
}
public enumSigType
{
T_ANALOG = 1,
T_BINARY = 2,
T_OPTIONAL = 4,
}
[System.Runtime.InteropServices.DllImportAttribute("abc.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "moduleDescription",CharSet=CharSet.Ansi)]
public static extern int moduleDescription(int modulnumber,StringBuilder name,[Out] t_c_pindescription[] ppsainputs, [Out] t_c_pindescription[] ppsaoutputs, [Out] t_c_pindescription[] ppsaintern);
public static void Main(string[] args)
{
t_c_pindescription[] inputdesarray = new t_c_pindescription[200];
t_c_pindescription[] outputdesarray = new t_c_pindescription[200];
t_c_pindescription[] interndesarray = new t _c_pindescription[200];
StringBuilder sb = newStringBuilder();
for(int i = 0; i < 10; i++)
{
moduleDescription(i, sb, inputdesarray, outputdesarray, interndesarray);
}
}
}
Here I am unable to get my structure array values i.e values inside inputdesarray, outputdesarray and interndesarray.

Related

Trouble converting function from vmm.dll (C) to vmmsharp.dll (C#). (DMA) (PCILEECH) (C#)

I am attempting to bring over a function from vmmdll.h to vmmsharp.cs. In this case, I am trying to bring over Map_GetPool.
You can see here my implementation to C#:
//Please view the images:
Bringing function over
internal static uint VMMDLL_POOLMAP_FLAG_ALL = 0;
internal static uint VMMDLL_POOLMAP_FLAG_BIG = 1;
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOLENTRYTAG
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal char[] szTag;
//szTag struct
/*internal uint dwTag;
internal uint _Filler;
internal uint cEntry;
internal uint iTag2Map;*/
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOLENTRY
{
internal ulong va;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] internal char[] szTag;
//szTag struct
/*internal uint dwTag;
internal byte _ReservedZero;
internal byte fAlloc;
internal byte tpPool;
internal byte tpSS;*/
internal uint cb;
internal uint _Filler;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal unsafe struct VMMDLL_MAP_POOL
{
internal uint dwVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] internal uint[] _Reserved1;
internal uint cbTotal;
internal uint* piTag2Map;
internal VMMDLL_MAP_POOLENTRYTAG* pTag;
internal uint cTag;
internal uint cMap;
internal VMMDLL_MAP_POOLENTRY[] pMap;
}
[DllImport("vmm.dll", EntryPoint = "VMMDLL_Map_GetPoolEx")]
internal static extern unsafe bool VMMDLL_Map_GetPoolEx(
byte* pNetMap,
ref uint pcbNetMap);
Implementing it into c#
//My map pool
public unsafe struct MAP_POOL
{
public uint dwVersion;
public uint[] _Reserved1;
//public unsafe fixed uint _Reserved1[6];
public uint cbTotal;
public uint[] piTag2Map;
public MAP_POOLENTRYTAG* pTag;
public uint cTag;
public uint cMap;
public MAP_POOLENTRY[] pMap;
}
//szTag[5] -> POOLENTRY 4th tpPool MAP_POOL_TYPE 5th tpSS MAP_POOL_TYPE_SUBSEGMENT
public enum MAP_POOL_TYPE
{
MAP_POOL_TYPE_Unknown = 0,
MAP_POOL_TYPE_NonPagedPool = 1,
MAP_POOL_TYPE_NonPagedPoolNx = 2,
MAP_POOL_TYPE_PagedPool = 3
}
public enum MAP_POOL_TYPE_SUBSEGMENT
{
VMM_MAP_POOL_TYPE_SUBSEGMENT_UNKNOWN = 0,
VMM_MAP_POOL_TYPE_SUBSEGMENT_NA = 1,
VMM_MAP_POOL_TYPE_SUBSEGMENT_BIG = 2,
VMM_MAP_POOL_TYPE_SUBSEGMENT_LARGE = 3,
VMM_MAP_POOL_TYPE_SUBSEGMENT_VS = 4,
VMM_MAP_POOL_TYPE_SUBSEGMENT_LFH = 5
}
public unsafe struct MAP_POOLENTRYTAG
{
//union
public char[] szTag;
/*
* struct {
DWORD dwTag;
DWORD _Filler;
DWORD cEntry;
DWORD iTag2Map;
};
*/
}
public unsafe struct MAP_POOLENTRY
{
public ulong va;
public char[] szTag;
//public unsafe fixed char szTag[5];
public uint cb;
public uint _Filler;
}
Function
public static unsafe MAP_POOLENTRY[] Map_GetPoolEx()
{
bool result;
uint cb = 0;
int cbMAP = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOL));
int cbENTRY = System.Runtime.InteropServices.Marshal.SizeOf(typeof(vmmi.VMMDLL_MAP_POOLENTRY));
result = vmmi.VMMDLL_Map_GetPoolEx(null, ref cb);
if (!result || (cb == 0)) { return new MAP_POOLENTRY[0]; }
fixed (byte* pb = new byte[cb])
{
result = vmmi.VMMDLL_Map_GetPoolEx(pb, ref cb);
if (!result) { return new MAP_POOLENTRY[0]; }
vmmi.VMMDLL_MAP_POOL pm = Marshal.PtrToStructure<vmmi.VMMDLL_MAP_POOL>((System.IntPtr)pb);
if (pm.dwVersion != vmmi.VMMDLL_MAP_PHYSMEM_VERSION) { return new MAP_POOLENTRY[0]; }
MAP_POOLENTRY[] m = new MAP_POOLENTRY[pm.cMap];
for (int i = 0; i < pm.cMap; i++)
{
vmmi.VMMDLL_MAP_POOLENTRY n = Marshal.PtrToStructure<vmmi.VMMDLL_MAP_POOLENTRY>((System.IntPtr)(pb + cbMAP + i * cbENTRY));
MAP_POOLENTRY e;
e.va = n.va;
e.cb = n.cb;
e.szTag = n.szTag;
//m[i] = e;
}
return m;
}
}
As you can see, the pointer PVMMDLL -> VMMDLL* throws an error stating it can't do that.
For the function, for some reason, e is undefined even though it is indeed defined. Also, is my overall setup correct?
Thanks, I appreciate any help.
Here are the links again to the implementations if needed (This doesn't have my implementation in it, but it has other implementations for similar functions):
vmmdll: https://github.com/ufrisk/MemProcFS/blob/master/vmm/vmmdll.h#L1506
vmmsharp: https://github.com/ufrisk/MemProcFS/blob/master/vmmsharp/vmmsharp.cs

Marshall ioctl in C# Correctly

I'm trying to get Informations about DVDs by ioctl in C#
the C Structure Looks like this and is working in a mixed CLR C++ Library
typedef enum {
DvdChallengeKey = 0x01,
DvdBusKey1,
DvdBusKey2,
DvdTitleKey,
DvdAsf,
DvdSetRpcKey = 0x6,
DvdGetRpcKey = 0x8,
DvdDiskKey = 0x80,
DvdInvalidateAGID = 0x3f
} DVD_KEY_TYPE;
typedef struct DVD_COPY_PROTECT_KEY
{
ULONG KeyLength;
DVD_SESSION_ID SessionId;
DVD_KEY_TYPE KeyType;
ULONG KeyFlags;
union
{
struct
{
ULONG FileHandle;
ULONG Reserved; // used for NT alignment
};
LARGE_INTEGER TitleOffset;
} Parameters;
UCHAR KeyData[0];
} DVD_COPY_PROTECT_KEY, * PDVD_COPY_PROTECT_KEY;
My C# equivalent Looks
public enum DVD_KEY_TYPE
{
DvdChallengeKey = 0x01,
DvdBusKey1,
DvdBusKey2,
DvdTitleKey,
DvdAsf,
DvdSetRpcKey = 0x6,
DvdGetRpcKey = 0x8,
DvdDiskKey = 0x80,
DvdInvalidateAGID = 0x3f
}
[StructLayout(LayoutKind.Sequential)]
public struct DVD_COPY_PROTECT_KEY
{
public uint KeyLength;
public int SessionId;
public DVD_KEY_TYPE KeyType;
public uint KeyFlags;
[MarshalAs(UnmanagedType.Struct)]
public DVD_COPY_PROTECT_KEY_Parameters Parameters;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
private byte[] KeyData;
public DVD_COPY_PROTECT_KEY(DVD_KEY_TYPE keyType, int sessionId)
{
SessionId = sessionId;
KeyType = keyType;
KeyFlags = 0;
KeyData = new byte[10];
KeyLength = 32;//GetKeyLength(this);
Parameters = new DVD_COPY_PROTECT_KEY_Parameters();
var t = Marshal.SizeOf(Parameters);
var t1 = Marshal.SizeOf(Parameters.Inner);
var t2 = Marshal.SizeOf(Parameters.TitleOffset);
var challenge = GetChallenge();
/* Get challenge from host */
for (int i = 0; i < 10; ++i)
{
KeyData[9 - i] = challenge[i];
}
}
public static byte[] GetChallenge()
{
byte[] p_challenge = new byte[10];
/* Setup a challenge, any values should work */
for (int i = 0; i < 10; ++i)
{
p_challenge[i] = (byte)i;
}
return p_challenge;
}
public static uint GetKeyLength(DVD_COPY_PROTECT_KEY dcpk)
{
int size = Marshal.SizeOf(dcpk);
switch (dcpk.KeyType)
{
case DVD_KEY_TYPE.DvdChallengeKey:
return (uint)(12 + size); //36
case DVD_KEY_TYPE.DvdBusKey1:
return (uint)(8 + size); //32
case DVD_KEY_TYPE.DvdBusKey2:
return (uint)(8 + size);
default:
return 0;
}
}
}
[StructLayout(LayoutKind.Explicit)]
public struct DVD_COPY_PROTECT_KEY_Parameters
{
[FieldOffset(0)]
public DVD_COPY_PROTECT_KEY_Parameters_Inner Inner;
[FieldOffset(0)]
public int TitleOffset;
}
[StructLayout(LayoutKind.Sequential)]
public struct DVD_COPY_PROTECT_KEY_Parameters_Inner
{
public IntPtr FileHandle;
public uint Reserved;
}
If i call DeviceIoControl i get an Exception PInvokeStackImbalance, if i use classes instead i get ErrorCode 87 from Marshal.GetLastWin32Error();
Someone any Idea?
Update
My DeviceIoControl
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
public extern static int DeviceIoControl(IntPtr hDevice, uint IoControlCode, ref DVD_COPY_PROTECT_KEY dcpk, uint InBufferSize, ref DVD_COPY_PROTECT_KEY dcpk2, uint OutBufferSize, ref uint BytesReturned, IntPtr Overlapped);
I have add ref keywords now i get with structs no Exception but ErrorCode 87
My Code can be found here

Unmanaged to managed structs

I'm receiving in C# a structure pointer from a C++ library callback
C++ structure (the packing is 1):
typedef
{
int data1[8];
int data2[8];
int data3;
int data3;
} SomeStruct;
in C# I have this equivalent:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1), Serializable]
public struct SomeStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] data1
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int [] data2;
public int data3;
public int data4;
};
var data contains the right IntPtr
SomeStruct ss = (SomeStruct )Marshal.PtrToStructure(pointer, typeof(SomeStruct));
But I'm getting garbage, what I'm doing wrong?
Thanks!
Here's the simplest possible example that works, using VC++
You might want to check the following:
is everything correct in your code ?
are you using something else than VC++ ?
if so then check out the packing and alignment behavior of that compiler
The Win32 DLL project that exports symbols:
struct test
{
int data1[8];
int data2[8];
int data3;
int data4;
};
EXTERN_C MYDLL_API test* Test()
{
test* pTest = new test;
for (int i = 0; i < 8; i++)
{
pTest->data1[i] = i;
pTest->data2[i] = i;
}
pTest->data3 = 1234;
pTest->data4 = 5678;
return pTest;
}
The C# test program:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var intPtr = Test();
var ptrToStructure = Marshal.PtrToStructure<Test1>(intPtr);
}
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Test();
}
[StructLayout(LayoutKind.Sequential)]
internal struct Test1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly int[] data1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public readonly int[] data2;
public readonly int data3;
public readonly int data4;
}
}
Result:

Marshalling array of structures from c++ to c# in WinCE

I'm trying to Marshal the following structures from c++ to c# on a Windows CE program and compact framework 2.0. I'm having a lot of difficulties with the marshalling of strings.
I have this c++ code:
#define Console_Parameters_MAX 50
struct AllParameters {
Parameter Parameters[Console_Parameters_MAX];
} ;
struct Parameter {
int Index;
int Id;
char Value[20];
};
extern "C" {
BOOL GetAllConsoleParameters(AllParameters *pItem);
}
and this are the corresponding c# code:
[StructLayout(LayoutKind.Sequential)]
public struct AllParameters {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public Parameter[] Parameters
}
[StructLayout(LayoutKind.Sequential)]
public struct Parameter {
public int Index;
public int Id;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public byte[] Value;
}
[DllImport("exemple.dll", SetLastError = true)]
public static extern bool GetAllConsoleParameters([MarshalAs(UnmanagedType.Struct)] ref AllParameters pItem);
and this is how I invoke it:
AllParameters item = new AllParameters();
if (AppAPI.GetAllConsoleParameters(ref item)) {
var array = item.Parameters;
}
When I call the GetAllConsoleParameters I get exception NotSupportedException. I've tried many configurations but with no success.
Can anyone advise on how to achieve it?
Thanks in advance
This works for me on a Windows Desktop. You might have to change the calling convention to Cdecl in the C DLL and the C# DllImport attribute, because I read here that Cdecl is standard on Windows CE: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx
C code:
extern "C" {
__declspec(dllexport) BOOL __stdcall GetAllConsoleParameters(AllParameters *pItem)
{
pItem->Parameters[0].Index = 0;
pItem->Parameters[0].Id = 42;
CopyMemory(&pItem->Parameters[0].Value[0], "Hello World", 12);
pItem->Parameters[1].Index = 1;
pItem->Parameters[1].Id = 43;
CopyMemory(&pItem->Parameters[1].Value[0], "Hello World 43", 15);
return TRUE;
}
}
C# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct Parameter
{
int Index;
int Id;
//char Value[20];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
string Value;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct AllParameters
{
//Parameter Parameters[Console_Parameters_MAX];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
Parameter[] Parameters;
};
class Program
{
[DllImport("MarshalC.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetAllConsoleParameters(ref AllParameters pItem);
static void Main(string[] args)
{
var size = Marshal.SizeOf<AllParameters>();
AllParameters all = new AllParameters();
bool result = GetAllConsoleParameters(ref all);
}
}
I would do it like this
[StructLayout(LayoutKind.Sequential)]
public struct AllParameters {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public Parameter[] Parameters;
}
[StructLayout(LayoutKind.Sequential)]
public struct Parameter {
public int Index;
public int Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] Value;
}
[DllImport("exemple.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern bool GetAllConsoleParameters(ref IntPtr pItem);
static void Main(string[] args)
{
AllParameters allParameters = new AllParameters();
allParameters.Parameters = new Parameter[50];
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(allParameters));
int z = Marshal.SizeOf(allParameters);
if (GetAllConsoleParameters(ref ptr))
{
Marshal.PtrToStructure(ptr, allParameters);
Parameter[] parameters = allParameters.Parameters;
}
}
following my solution, c++ code:
/* - not used
#define Console_Parameters_MAX 50
struct AllParameters {
Parameter Parameters[Console_Parameters_MAX];
} ;
*/
struct Parameter {
int Index;
int Id;
char Value[20];
};
extern "C" {
BOOL GetAllConsoleParameters(Parameter pItem[], int size);
}
and corresponding c# code:
/* - not used
[StructLayout(LayoutKind.Sequential)]
public struct AllParameters {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public Parameter[] Parameters
}
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Parameter {
public int Index;
public int Id;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] Value;
}
[DllImport("exemple.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetAllConsoleParameters([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] ConsoleParameter[] myStruct, int size);
and code invoke:
ConsoleParameter[] item = new ConsoleParameter[50];
if (AppAPI.GetAllConsoleParameters(item, 50)) {
var array = item;
}
thanks a lot for help

Using pinvoke to pass embedded array of C structs inside struct array to c#

I am attempting to use an array of structures to pass data to/fro my C# ui and my C dll.
Further complicating matters is that the structure contains another array of structures.
I have figured out how to the simpler stuff using pinvoke, but how do I declare
the embedded structures, and how do I pass them?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class csForm {
public int endDate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] formId;
}
[DllImport("myDll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void fillForm([In, Out] csForm data, 5);
// c code
typedef struct s_ptxRow {
int ptxNumber;
char primitive[128];
int primitiveParams[128];
} ptxRow;
typedef struct s_workSpace{
char formId[128];
int endDate;
ptxRow PtxRow[128];
} cForm;
extern "C" __declspec(dllexport) fillForm(cForm csForm[], interface csFormCount)
{
for (int i = 0, j = 0; i < csFormCount; ++i)
{
j = int / 2;
csForm[i].endDate = i;
strcpy(csForm[i].formId, "formId here");
csForm[i].PtxRow[j].ptxNumber = i;
csForm[i].PtxRow[j].primitiveParams[i] = i;
strcpy(csForm[i].PtxRow[j].primitive, "someText");
}
}
You were going in the right direction. You just needed to declare the ptxRow structure in C# and then add an array of it to csForm. You even don't need to allocate any arrays beforehand - apparently P/Invoke does it for you since it knows their sizes. The entire sample code is included because there were minute errors in some declarations.
Note: When I tried to use classes in C# I got strange results (e.g. incorrect member and pointer values in the C++ code) which led to various errors. Switching to structs made the problem go away. I think this has something to do with reference and value types, but would appreciate input from more knowledgeable people. I'm testing with .NET 3.5 if it matters.
#include <string.h>
typedef struct s_ptxRow {
int ptxNumber;
char primitive[128];
int primitiveParams[128];
} ptxRow;
typedef struct s_workSpace {
char formId[128];
int endDate;
ptxRow PtxRow[128];
} cForm;
extern "C" __declspec(dllexport) void fillForm(cForm csForm[], int csFormCount)
{
for (int i = 0, j = 0; i < csFormCount; ++i)
{
j = i / 2;
csForm[i].endDate = i;
strcpy(csForm[i].formId, "formId here");
csForm[i].PtxRow[j].ptxNumber = i;
csForm[i].PtxRow[j].primitiveParams[i] = i;
strcpy(csForm[i].PtxRow[j].primitive, "someText");
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace PInvokeStructsCS
{
class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PtxRow
{
public int ptxNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] primitive;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public int[] primitiveParams;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct csForm
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] formId;
public int endDate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public PtxRow[] ptxRow;
}
[DllImport("PInvokeStructsC.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern void fillForm([In, Out]csForm[] data, int count);
static void Main(string[] args)
{
csForm[] forms = new csForm[2];
try
{
fillForm(forms, 2);
}
catch (Exception e)
{
Console.Out.WriteLine(e.Message);
return;
}
}
}
}

Categories