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.
Related
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:
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
I got following definition for a function in a c-based DLL (no source available):
uint MakeReference(MemBlock* ipReferenceMemBlock);
MemBlock is defined as:
typedef struct {
HANDLE_TAG dTag;
long dLength;
BYTE* dpReference;
} MemBlock;
HANDLE_TAG is defined as:
typedef char HANDLE_TAG[10 + 1];
My take on this in a C# Wrapper Class is:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MemBlock
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string dTag;
public uint dLength;
[MarshalAs(UnmanagedType.LPStr)]
public string dpReference;
}
[DllImport("lib.dll", CharSet = CharSet.Ansi, EntryPoint = "MakeReference#24", CallingConvention = CallingConvention.StdCall)]
public static extern uint MakeReference(ref IntPtr pDDipMemBlock);
public static uint FAPIMakeReference(ref MemBlock ipMemBlock)
{
uint error = 0;
IntPtr pDDipMemBlock = Marshal.AllocHGlobal(Marshal.SizeOf(ipMemBlock));
try
{
Marshal.StructureToPtr(ipMemBlock, pDDipMemBlock, false);
error = MakeReferenceEx(ref pDDipMemBlock);
ipMemBlock = (MemBlock)Marshal.PtrToStructure(pDDipMemBlock, typeof(MemBlock));
}
finally
{
Marshal.FreeHGlobal(pDDipMemBlock);
}
return error;
}
calling this with:
MemBlock refMemBlock = new MemBlock();
uint error = MakeReferenceEx(ref refMemBlock);
resulting in an Access Violation Expection
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.
Apologies for duplicate posting.
Hi
I am having trouble marshalling a linked list from a DLL.
------C++ Structure and Function--------
struct localeInfo {
WCHAR countryName[BUFFER_SIZE];
WCHAR localeName[BUFFER_SIZE];
localeInfo *next;
}
int GetSystemLocales(localeInfo **ppList);
-----------C# Declarations-----------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct LocaleInfo {
public string countryName;
public string localeName;
public IntPtr next;
};
[DllImport("systemLocales.dll")]
private static extern int GetSystemLocales(ref IntPtr ppList);
int main()
{
var pListHead = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
try
{
GetSystemLocales(ref pListHead);
var deref1(IntPtr)Marshal.PtrToStructure(pListHead, typeof(IntPtr));
var deref2 = (LocaleInfo)Marshal.PtrToStructure(deref1, typeof(LocaleInfo));
}
finally
{
Marshal.FreeHGlobal(pListHead);
}
}
I get an FatalExecutionEngine Exception at deref2 declaration. I can't figure out how to get the linked list back and access its contents.
Here is the C++ code that I wrote to get the linked list. I want something similar to work in C#.
localeInfo *pHead = NULL;
localeInfo *pTemp;
GetSystemLocales(&pHead);
for(pTemp = pHead; pTemp!=NULL; pTemp = pTemp->next)
{
wprintf(L"Display Name : %s (%s) \n", pTemp->countryName, pTemp->localeName);
}
try this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct LocaleInfo {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
public string countryName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
public string localeName;
public IntPtr next;
};
I answered on your other question along these lines. Shay's struct definition is part of it, but I've corrected Main also.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct LocaleInfo
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
public string countryName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
public string localeName;
public IntPtr next;
};
[DllImport("systemLocales.dll")]
private static extern int GetSystemLocales(ref IntPtr ppList);
static void Main()
{
IntPtr pList = IntPtr.Zero;
GetSystemLocales(ref pList);
while (pList != IntPtr.Zero)
{
var info = (LocaleInfo)Marshal.PtrToStructure(pList, typeof(LocaleInfo));
Console.WriteLine("Display Name : {0} ({1}) ", info.countryName, info.localeName);
Marshal.FreeHGlobal(pList);
pList = info.next;
}
}
You ought to close the other question really - I only noticed by luck that you had posted this one too.