how to call a C .dll from C#? - c#

I have tried to call the C struct from C#, but I failed to make it work.
My struct define in C is as follow:
struct GHX{
double output[28];
int val;
};
And a function that I’m using to calculate the output is
__declspec(dllexport) void GHXfunction(
double *XIN, double *parameter,
int mode, int hour, GHX *result)
{
/*...*/
}
In C#,
I tried the following method.
[StructLayout(LayoutKind.Sequential)]
public struct GHX
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 28)]
public double[] output;
public int val;
}
[DllImport("GHXDLL.dll", EntryPoint = "GHXfunction",
CallingConvention = CallingConvention.Cdecl)]
public static extern void GHXfunction(
IntPtr XIN, IntPtr parameter, int mode,
int hour , ref GHX result);
So far, I believe that everything is OK, because someone from stackoverflow has the same problem as me.
Then, I just test a simple scenario as follow.
static void Main()
{
IntPtr XIN= IntPtr.Zero;
IntPtr Par=IntPtr.Zero;
int mode=1;
int hour=0;
GHX test = new GHX();
GHXfunction(XIN, Par, mode, hour, ref test);
}
It then till me that
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Does anyone have idea about it?
Thanks.
Edit, I actually don't know how does IntPtr work. So I guessed IntPtr.Zero will return memory location with 0, maybe i was wrong.
In my original C code I call the function like this
double par[42], xin[5];
ptrxin = &xin[0];
ptrpara = &par[0];
struct GHX result;
GHXfunction(ptrxin, ptrpara, 0, 0,result);
I dont know how to call the function in C# with the pointer input.
Thanks.
Working code:
Basing on Ben's suggestion. I can call the struct in C#.
[StructLayout(LayoutKind.Sequential)]
public struct GHX
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 28)]
public double[] output;
public int val;
}
[DllImport("GHXDLL.dll", EntryPoint = "GHXfunction", CallingConvention = CallingConvention.Cdecl)]
public static extern void GHXfunction(double[] XIN, double[] parameter, int mode, int hour,ref GHX result);
static void Main()
{
double result;
double[] XIN= new double[5];
double[] Par = new double[42];
int mode = 1;
int hour=0;
GHX test = new GHX();
GHXfunction(XIN, Par, mode, hour,ref test);
result = test.output[0];
}

A C type of double* should be translated as either
ref double
or
double[]
Since your comments say those are arrays, try:
[DllImport("GHXDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GHXfunction(double[] XIN, double[] parameter, int mode,
int hour , ref GHX result);
P/invoke will take care of pinning the array and passing the address of the first element.

Related

Wrapping c++ function to c# with total dynamic size of struct

I'm struggling with wrapping C++ function to C#.
I have very basic knowledge about these sort of wrapping but here i'm trying to find the "best solution".
Let's say I only have a .dll that contains C++ function. I only know there is a function with this signature :
static void GetInfos(LibraryInfo& infos);
And of course I know there is a class LibraryInfos
class LIBRARY_EXPORT_CLASS LibraryInfo
{
public:
const char* libVersion;
const char* libName;
const char* libDate;
};
};
Now I try to use this function in a C# test project :
static void Main(string[] args)
{
// Create Pointer
IntPtr ptr;
// Call function
GetInfos(out ptr);
// Get the 100 first byte (used only to demonstrate)
byte[] buffer = new byte[100];
Marshal.Copy(ptr, buffer, 0, 100);
// Display memory content
Console.WriteLine(Encoding.ASCII.GetString(buffer));
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);
This code give me as output
v.1.2.5 ?I9
First : I know this is the really bad way of doing it, marshalling an
arbitrary length as a byte[] is only here just for demonstration.
Second : I only have the version, but if I'm calling the same dll
from a C++ project, I have the 3 field with data.
Third : Why did I use Marshal copy, and this arbitrary length of 100
? Because I didn't succeed in calling PtrToStruct, here is what I
tried :
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version; // I tried, char[], string, and IntPtr
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create Pointer
IntPtr ptr;
// Call function
GetInfos(out ptr);
if (ptr != IntPtr.Zero)
{
LibInformation infos = (LibInformation)Marshal.PtrToStructure(ptr, typeof(LibInformation));
}
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);
Then I'm not able to retrieve my Version, Name and Date.
If I use IntPtr in my struct, I dont have the length of the String so
I can't realy marshal.Copy, nor PtrToStringAuto.
If I use Char[] or string it doesn't work.
I think my issue is about not knowing the size of the final response. so my best option for now is to make C++ project, calling this function from there then wrap this struct in a better one , that I can Marshal on the other side (with Length of each member as other member).
Any thought ?
[EDITS 1 Based on jdweng comment]
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version; // I tried, char[], string, and IntPtr
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create Pointer
IntPtr ptr;
// Call function
GetInfos(out ptr);
var data = Marshal.PtrToStructure<LibInformation>(ptr);
var version = Marshal.PtrToStringAnsi(data.Version);
Console.WriteLine(version) // result : ""
// Use Ptr directly as string instead of struct
var version2 = Marshal.PtrToStringAnsi(ptr);
Console.WriteLine(version2) // result : "v1.2.5" but how can i access other field ?
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);
[EDITS 2 Based on jdweng 2snd comment]
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version;
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create Pointer for my structure
IntPtr ptr;
// Create 3 pointers and allocate them
IntPtr ptrVersion = Marshal.AllocHGlobal(100);
IntPtr ptrName = Marshal.AllocHGlobal(100);
IntPtr ptrDate = Marshal.AllocHGlobal(100);
// Then declare LibInformation and assign
LibInformation infos = new LibInformation();
// Here is probably my missunderstanding (an my error)
// As I need a ptr to call my function I have to get the Ptr of my struct
IntPtr ptr = Marshal.AllocHGlobal(300);
Marshal.StructureToPtr(infos, ptr, false);
// Assign
infos.Version = ptrVersion;
infos.Name = ptrName;
infos.Date = ptrDate;
// Call function
GetInfos(out ptr);
var data = Marshal.PtrToStructure<LibInformation>(ptr);
var version = Marshal.PtrToStringAnsi(data.Version);
Console.WriteLine(version) // result : still ""
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out IntPtr test);
I finally found the way to do it, thanks to the explanation of #jdweng and the link of #PaulF
The only bad news is that I have to arbitrary allocate n bytes before calling my functions
Link :
MSDN : marshaling-classes-structures-and-unions
Explanations (jdweng):
The parameter list of a method is on the execution stack. Once you return from the method the parameters list is not valid because it can be over written by the parent code. Only the return value of a method is valid. So you have to Allocate all the data before calling the method. So you need to allocate the variables version, name, and date in unmangaged memory. Then declare LibInformation and set version, name, and date to the memory locations allocated. Finally call the method. Then to get the three variables you have to call Marshal.PtrToStruct to copy results from unmanaged memory.
Final code :
[StructLayout(LayoutKind.Sequential)]
private struct LibInformation
{
public IntPtr Version;
public IntPtr Name;
public IntPtr Date;
}
static void Main(string[] args)
{
// Create 3 pointers and allocate them
IntPtr ptrVersion = Marshal.AllocHGlobal(100);
IntPtr ptrName = Marshal.AllocHGlobal(100);
IntPtr ptrDate = Marshal.AllocHGlobal(100);
// Then declare LibInformation and assign
LibInformation infos = new LibInformation();
// Assign
infos.Version = ptrVersion;
infos.Name = ptrName;
infos.Date = ptrDate;
// Call function
GetInfos(out infos);
var version = Marshal.PtrToStringAnsi(data.Version);
var name = Marshal.PtrToStringAnsi(data.Name);
var date = Marshal.PtrToStringAnsi(data.Date);
Console.ReadLine();
}
[DllImportAttribute("MyLibrary.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "GetInfos")]
private static extern void GetInfos(out LibInformation test); // Changing IntPtr to LibInformation
[Edit 1 based on David Heffernan comment]
Here is the C code of a calling sample :
HComplexCTXPoint::LibraryInfo versionInfo;
HComplexCTXPoint::GetInfos(versionInfo);
std::cout << versionInfo.libName << std::endl;

Getting a complex struct from C++ to C#

Days ago I made this question: Passing a complex Struct (with inner array of struct) from C# to C++
Fortunately it as been answered and the code seems to work.
Now I need to do the oposite case, I mean, I need to get the struct from the C++ dll to my C# code.
I was researching in this site, trying the use of the IntPtr type, but didnt work. Then as my struct in C# was defined correctly I tried to use an out reference.
As a sumary, gonna repost the structs defined in both languages
typedef struct _ImParam
{
UINT Format;
UINT Resolution;
UINT ColorDepth;
} IM_PARAM;
typedef struct _sValues
{
UINT Xpos;
UINT Ypos;
UINT Width;
UINT Height;
BOOL Milli;
} S_VALUES;
typedef struct _sProperties
{
BOOL Enable;
S_VALUES Properties;
} S_PROPERTIES;
typedef struct _DevParam
{
BOOL Enable;
UINT Font;
char Symbol;
IM_PARAM Image1;
IM_PARAM Image2;
S_PROPERTIES Properties[10];
UINT FeedMode;
} DevParam;
// more code, comments, etc. etc.
// The function I want to use
BOOL GetParameters( DWORD ID, DevParam *dParam );
This is how I build the structs in C#
[StructLayout(LayoutKind.Sequential)]
public struct ImParam
{
public uint Format;
public uint Resolution;
public uint ColorDepth;
public ImParam(uint n)
{
Format = n;
Resolution = 300;
ColorDepth = 256;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sValues
{
public uint Xpos;
public uint Ypos;
public uint Width;
public uint Height;
public bool Milli;
public sValues(uint n)
{
Xpos = n;
Ypos = n;
Width = n;
Height = n;
Milli = false;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sProperties
{
public bool Enable;
public sValues Properties;
public sProperties(int n)
{
Enable = false;
Properties = new sValues(n);
}
};
[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
public bool Enable;
public uint Font;
public char Symbol;
public ImParam Image1;
public ImParam Image2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public sProperties[] Properties;
public uint FeedMode;
public DeviceParameters(int n)
{
Enable = true;
Font = 0;
Symbol = '?';
Image1 = new ImParam(3);
Image2 = new ImParam(3);
Properties = new sProperties[10];
for(int i = 0; i < 10; i++)
Properties[i] = new sProperties(n);
FeedMode = 1;
}
};
// This is the method imported from the C++ dll
[DllImport(path, EntryPoint = "?GetParameters##YGHKPAU_DevParam###Z")]
public static extern bool GetParameters(int ID, out DevParam dParam);
And here's the call
// Already got ID from somewhere else
DevParam DP;
bool res = Class1.GetParameters(ID, out DP);
Console.WriteLine("Result: " + res);
The code seems to work, since I'm getting a "true" as result. The problem is it's getting wrong values in the structs members, placing the default ones (always 0 the numbers, always false the booleans), even if I use the SetParam(..) method before (and I know that one works because when I change the image format scanner decreases scanning speed).
What am I missing?
Note: I dont have source code of the .dll
Edited:
Been trying with these modifications:
// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters##YGHKPAU_DevParam###Z")]
public static extern bool GetParameters(int ID, ref IntPtr dParam);
// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, ref Ptr);
Console.WriteLine("Result: " + res);
var test = Marshal.PtrToStructure(Ptr, typeof(DevParam));
// No idea what I'll do here
Marshal.FreeHGlobal(Ptr);
If I try to print "test", it should give an adress, since it's a pointer, but it's null. Neither know how can I extract the data from the struct.
Any ideas?
Solved!
// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters##YGHKPAU_DevParam###Z")]
public static extern bool GetParameters(int ID, IntPtr dParam);
// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, Ptr);
DevParam test = (DevParam)Marshal.PtrToStructure(Ptr, typeof(DevParam));
// For testing purpoises, previously changed the default values with another method
Console.WriteLine(test.Enable);
Marshal.FreeHGlobal(Ptr);
Had to remove the ref keyword.

AccessViolationException using unmanaged C++ DLL

I'm trying, for the first time, to use an unmanaged C++ DLL ("res_lib") in a C# application. I've used cppsharp to generate the PInvoke code: for example, one of the functions/methods I'm trying to call is get_system_snapshot. From the .h file, this is defined as
SYS_INT SYS_ERR get_system_snapshot(SNAPSHOT_PARMS* snapshotp);
SYS_INT and SYS_ERR equate to a int32_t. SNAPSHOT_PARMS is
typedef struct SNAPSHOT_PARMS
{
SYS_ULONG size;
SYS_UINT count;
SYS_CHAR serial_no[600];
} SYS_PACK_DIRECTIVE SYS_SNAPSHOT_PARMS;
cppsharp has turned this into the following code snippets:
DllImport
[SuppressUnmanagedCodeSecurity]
[DllImport("res_lib", CallingConvention = CallingConvention.StdCall,
EntryPoint="get_system_snapshot")]
internal static extern int GetSystemSnapshot(IntPtr snapshotp);
Object
public unsafe partial class SNAPSHOT_PARMS : IDisposable
{
[StructLayout(LayoutKind.Explicit, Size = 608)]
public partial struct __Internal
{
[FieldOffset(0)]
internal uint size;
[FieldOffset(4)]
internal uint count;
[FieldOffset(8)]
internal fixed sbyte serial_no[600];
[SuppressUnmanagedCodeSecurity]
[DllImport("res_lib", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall,
EntryPoint="??0SNAPSHOT_PARMS##QAE#ABU0##Z")]
internal static extern global::System.IntPtr cctor(global::System.IntPtr instance, global::System.IntPtr _0);
}
}
public SNAPSHOT_PARMS()
{
__Instance = Marshal.AllocHGlobal(sizeof(global::res_lib.SNAPSHOT_PARMS.__Internal));
__ownsNativeInstance = true;
NativeToManagedMap[__Instance] = this;
}
Main code
static void Main(string[] args)
{
SNAPSHOT_PARMS p = new SNAPSHOT_PARMS();
var result = res_lib.res_lib.GetSystemSnapshot(p);
}
public static unsafe int GetSystemSnapshot(global::res_lib.SNAPSHOT_PARMS snapshotp)
{
var __arg0 = ReferenceEquals(snapshotp, null) ? global::System.IntPtr.Zero : snapshotp.__Instance;
var __ret = __Internal.GetSystemSnapshot(out __arg0);
return __ret;
}
When calling the function, I get the infamous:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I've tried changing the CallingConvention from StdCall to Cdecl, introducing [In] and [Out] to the DllImport etc, but all to no avail. Can anyone see anything obviously wrong with the code - as may be apparent, this is all new to me, and perhaps I'm asking a bit much for cppsharp to generate code that won't need tweaked.
EDIT The original C++ documentation has an example, where the struct is initialised by
#define INIT_STRUCT(struct_p) { memset(struct_p, 0, sizeof(*(struct_p))); (struct_p)->size = sizeof(*(struct_p)); }
and is used
SNAPSHOT_PARMS snapshot_parms;
SYS_ERR result;
INIT_STRUCT(&snapshot_parms);
result = get_system_snapshot(&snapshot_parms);
From the C++ declarations, this should suffice:
[StructLayout(LayoutKind.Sequential)]
unsafe struct SNAPSHOT_PARMS {
public int size;
public int count;
public fixed byte serial_no[600];
}
[DllImport("res_lib", EntryPoint = "get_system_snapshot")]
static extern int GetSystemSnapshot(ref SNAPSHOT_PARMS snapshot);
Use as
var s = new SNAPSHOT_PARMS { size = Marshal.SizeOf<SNAPSHOT_PARMS>() };
int result = GetSystemSnapshot(ref s);
// check result, use s

passing float pointer as IntPtr (pinvoke)

Ok I have a DLL function declared as:
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParam(string param_name, ref IntPtr param_value);
This function takes many different params i.e in C++ this is how you would use it.
int i=2;
setParam("width", &i);
float k=2.5f;
setParam("factor", &f);
So I am trying to declare a C# functions to call this DLL api, I have got one working for the pointer to integer case:
public static void setWidth(int width)
{
IntPtr w = new IntPtr(width);
setParam("width", ref w);
}
But I cannot figure out how to do the second one where I pass a pointer to a float as IntPtr. Any ideas?
public static void setFactor(float f)
{
IntPtr w = new IntPtr(f); // WHAT GOES HERE??
setParam("factor", ref w);
}
Unless there's too many combinations, I'd say the best way is to simply have multiple DllImports for the various argument types. For example:
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParamInt32(string param_name, ref int param_value);
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParamSingle(string param_name, ref float param_value);
You can then call them properly as
var intVal = 42;
setParamInt32("param", ref intVal);
var floatVal = 42.0f;
setParamSingle("param", ref floatVal);
Using ref IntPtr is wrong in either case - the only reason it works at all is that in 32-bit applications, IntPtr is a 32-bit integer internally. However, it's supposed to be a pointer. A proper use would be something like this:
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParam(string param_name, IntPtr param_value);
Note that the ref isn't there - IntPtr is already an indirection.
To call this, you'll need to allocate some memory, and get a pointer to that - or, use a GCHandle to refer directly to a managed object:
var intValue = 42;
var handle = GCHandle.Alloc(intValue, GCHandleType.Pinned);
setParam("param", handle.AddrOfPinnedObject());
Make sure to dispose of the managed handle properly, of course - pinned handles are a huge pain for the GC.
Manually copying the data to unmanaged memory and back also isn't exactly hard:
var ptr = Marshal.AllocCoTaskMem(sizeof(int));
try
{
Marshal.WriteInt32(ptr, 42);
setParam("param", ptr);
// If you need to read the value back:
var result = Marshal.ReadInt32(ptr);
}
finally
{
Marshal.FreeCoTaskMem(ptr);
}
But I'd simply stick with automatic marshalling unless you have a very good reason not to.
If you absolutely have to use IntPtr and can't just pass a floatparameter then you can use unsafe coding to pass a float pointer as IntPtr takes a void pointer as a parameter in one of its constructor. However the corresponding unmanaged function must also take a void pointer.
There is two ways you can deal with this, passing void* or passing IntPtr*. I would say passing void* is probably better, since you in general will be doing the same with IntPtr except for that IntPtr will be passed with the pointer instead of the function.
Option 1 - IntPtr
You first have to correct the p/invoke declaration by removing the erroneous ref
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParam(string param_name, IntPtr param_value);
You do not pass IntPtr as ref either, just simply pass the instance of your IntPtr
public static unsafe void setFactor(float f)
{
IntPtr w = new IntPtr(&f);
setParam("factor", w);
}
Or if you want the unsafe declaration in the body
public static void setFactor(float f)
{
unsafe
{
IntPtr w = new IntPtr(&f);
setParam("factor", w);
}
}
Option 2 - void*
[DllImport(mDllName, EntryPoint = "SetParam")]
public unsafe static extern bool setParam(string param_name, void* param_value);
Then you can set it like
public static unsafe void setWidth(int width)
{
int* w = &width;
setParam("width", w);
}
And for the float
public static unsafe void setFactor(float f)
{
float* fptr = &f;
setParam("factor", fptr);
}
You can theoretically declare different DllImport entries for "safe" automatic marshalling:
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParam(string param_name, ref int param_value);
[DllImport(mDllName, EntryPoint = "SetParam")]
public static extern bool setParam(string param_name, ref float param_value);
And use it like:
public static void setFactor(float f)
{
setParam("factor", ref f);
}
I have done this for other functions using void * as a signature and it works just fine, the ref <value_type> gets correctly passed in as a pointer.
Also, ref IntPtr should be for void ** (you'd use IntPtr for void *, not ref IntPtr)
If you are ok with unsafe, then you can use #Bauss solution
Furthermore, using the constructor IntPtr(int) is giving a location for the pointer, not the value at the location

dllimport : c code affect a struct passed by reference (c#)

I've got a c dll that contains an exposed function, that takes three parameters :
int ParseInput(char* opt_path, char* input, SENNA_RESULT_ARRAY* result);
I want to call this from C#, which actually works. The problem is that the result struct is not affected.
Here is the structure defined in c code :
typedef struct RESULT_
{
char* word;
int pos_start;
int pos_end;
char* pos;
char* chk;
char* ner;
char* psg;
} RESULT;
typedef struct RESULT_ARRAY_
{
int size;
RESULT* Results;
} RESULT_ARRAY;
and my c# code :
[StructLayout(LayoutKind.Sequential)]
public struct SENNA_RESULT
{
[MarshalAs(UnmanagedType.LPStr)]
public string word;
[MarshalAs(UnmanagedType.I4)]
public int pos_start;
[MarshalAs(UnmanagedType.I4)]
public int pos_end;
[MarshalAs(UnmanagedType.LPStr)]
public string pos;
[MarshalAs(UnmanagedType.LPStr)]
public string chk;
[MarshalAs(UnmanagedType.LPStr)]
public string ner;
[MarshalAs(UnmanagedType.LPStr)]
public string psg;
}
[StructLayout(LayoutKind.Sequential)]
public struct SENNA_RESULT_ARRAY
{
public SENNA_RESULT[] Results;
public int size;
}
[DllImport("Senna-32.dll", CharSet = CharSet.Ansi)]
static extern int Parse(string msg, string stream, ref SENNA_RESULT_ARRAY results);
Parse(#"path", "sentence", ref result_array)
I've tried many things, like :
1-use classes instead of struct without ref keyword
2-use a pointer instead of passing a struct
Each time i got a different error like
array is not of the specified type
low level error( corrupted heap)
even if i don't specify the array in the first struct, the size member has not the correct value (the C code prints the value in the console)
Any advice ?
Thanks
Consider using code below.
[StructLayout(LayoutKind.Sequential)]
public struct SENNA_RESULT
{
public IntPtr word;
public int pos_start;
public int pos_end;
public IntPtr pos;
public IntPtr chk;
public IntPtr ner;
public IntPtr psg;
}
[StructLayout(LayoutKind.Sequential)]
public struct SENNA_RESULT_ARRAY
{
public IntPtr Results;
public int size;
}
[DllImport("Senna-32.dll")]
static extern int Parse(string msg, string stream, out SENNA_RESULT_ARRAY results);
Here is usage example
SENNA_RESULT_ARRAY array = new SENNA_RESULT_ARRAY();
int result = Parse("path", "sentence", out array);
if (result == SUCCESS && array.Results != IntPtr.Zero)
{
for (int index = 0; index < array.size; index++)
{
IntPtr offset = (IntPtr)((int)array.Results + index * Marshal.SizeOf(typeof(SENNA_RESULT)));
SENNA_RESULT senna = (SENNA_RESULT)Marshal.PtrToStructure(offset, typeof(SENNA_RESULT));
}
}
I hope that you understand that it is just idea. Make sure that code is working properly and then improve it to make it more comfotable to use. I talking about replacing IntPtr with string.

Categories