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:
Related
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
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.
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
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.
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;
}
}
}
}