Reputation: 631
I am working on a C# app that is trying to use functionality provided via a C++ DLL. I am having a bit of a hard time getting the DLLImport definitions to work right at the moment.
Here's the C++ side of the equation:
struct Result
{
FLOAT first;
FLOAT second;
};
struct ResultData
{
UINT uint1;
UINT uint2;
Result result;
Result* pResults;
};
#define DllImport __declspec(dllimport)
extern "C"
{
DllImport HRESULT APIENTRY Process(const PCWSTR FileName, const PCWSTR logfileFileName, const PCWSTR DataFileName, ResultData** ppResults);
DllImport HRESULT APIENTRY Release(ResultData* pResults);
}
On the C# side, here's what I have done so far:
[StructLayout(LayoutKind.Sequential)]
public struct Result
{
public float first;
public float second;
}
[StructLayout(LayoutKind.Sequential)]
public struct ResultData
{
public uint uint1;
public uint uint2;
public Result result;
public Result[] Results;
}
DllImport("MyDLL.dll")]
static extern uint Release(ResultData pResults);
[DllImport("MyDLL.dll")]
static extern uint Process(string FileName, string logfileFileName, string DataFileName, ref ResultData ppResults);
Is this the correct way to do it? The thing I am most concerned about is that pResults member of the ResultData structure. I don't want that copied by value as it will be a large amount of data and I don't want to replicate memory... how can I make sure that doesn't happen?
I appreciate your help.
Upvotes: 4
Views: 1088
Reputation: 21801
If you can keep the interface to pure C primitive types, you won't have to do any marshalling. This will save you a lot of heartache.
Upvotes: 0
Reputation: 754853
The most immediate problem that jumps out at me is the Results member in ResultData. The native type is a Result*
but you've translated it as an array. This may or may not work (can't remember off the top of my head). What will work though is marshalling it as an IntPtr
type.
[StructLayout(LayoutKind.Sequential)]
public struct ResultData
{
public uint uint1;
public uint uint2;
public Result result;
public IntPtr RawResults;
public Result Results { get { return (Result)Marshal.PtrToStructure(RawResults,typeof(Result)); }
}
This is assuming that it's a single value. If it's more than one value a more complex marshalling will be needed.
Also the native Release method takes a ResultData*
but you have a simple by value ResultData
type in the managed signature. It needs to have the same level of indirection. You can achieve this by making it a ref param.
DllImport("MyDLL.dll")]
static extern uint Release(ref ResultData pResults);
Upvotes: 5