Reputation: 2302
I have some of unmanaged C++ dynamic library and C# GUI application, using it. I need to pass a pointer to structure with embedded buffer and some integral meta data members. Structure allocated on C# side to C++ library. Then library populates it, returns to C# application and application uses it in some ways, releasing finally.
My first approach was using StringBuilder
as embedded string buffer, but i receive an exception on runtime which says it is not allowed to use StringBuilder
as structure member. Also I got advice to use string preinited with suitable buffer size. I've tryed this approach, but it seems bufefr passed via string cannot be modified on C++ part. Is it right?
// C++
typedef struct SomeStruct{
wchar_t* stringBuffer; // buffer
uint64_t size; // some additional integral fields
int64_t mTime; // some additional integral fields
};
// Native library API method
MYCDLL_API uint8_t __stdcall getSomeStructures(uint32_t index,
SomeStruct* struct,
uint64_t stringBufferSize);
// C# part
[DllImport(myLibraryname, CallingConvention = CallingConvention.StdCall)]
static extern RetCode getSomeStructures(UInt32 index,
ref SomeStruct someStruct,
UInt64 stringBufferSize);
How this task could be solved? As, I mentioned I need to pass a reference to structure with embedded modifyable character buffer from C# to C++.
Upvotes: 0
Views: 783
Reputation: 1430
Try to use following declaration of structure:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SomeStruct
{
[MarshalAs(UnmanagedType.LPWStr)]
public string stringBuffer;
public UInt64 size;
public Int64 mTime;
};
[DllImport("Win32Project1.dll", EntryPoint = "GetSomeStructures")]
static extern int GetSomeStructures(
uint index, ref SomeStruct str, ulong stringBufferSize);
static void Main(string[] args)
{
var a = new SomeStruct(){
stringBuffer = "asd",
size=10,
mTime = 20
};
Console.WriteLine(GetSomeStructures(1, ref a, 1));
}
Upvotes: 0
Reputation: 612854
I'd declare that field as IntPtr
.
struct SomeStruct
{
IntPtr stringBuffer;
ulong size;
long mTime;
}
Declare the function like this:
[DllImport(myLibraryname)]
static extern byte getSomeStructures(
uint index,
ref SomeStruct someStruct,
ulong stringBufferSize
);
Use Marshal.AllocHGlobal()
and Marshal.FreeHGlobal()
to allocate and free the buffer. Use Marshal.PtrToStringUni()
to create a string from the pointer.
SomeStruct someStruct;
someStruct.stringBuffer = Marshal.AllocHGlobal(1024);
try
{
// initialize the rest of someStruct
byte retval = getSomeStructures(index, ref someStruct, 1024);
// check retval for errors
string str = Marshal.PtrToStringUni(someStruct.stringBuffer);
}
finally
{
Marshal.FreeHGlobal(someStruct.stringBuffer);
}
I've assume that the parameter named size is a byte size. If it is actually a length, then you need to account for the characters being 16 bytes wide, and you should change the parameter name to length rather than size.
Upvotes: 1