Reputation: 10954
I have some C code that compiles to a DLL. From C#, I need to pass an array of ints to it, and I need to get an array of ints out of it.
Here's what I have so far. From C#, the only function that works is bar(). It returns 22 and writes to a file as expected. The others write to their files properly but throw an exception when control is given back to C#. It reads,
"A call to PInvoke function 'irhax!irhax.App::foo' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature."
C (the DLL):
#define IG_API __declspec(dllexport)
IG_API void foo(int i) {
FILE *f = fopen("foo.txt", "a+");
fprintf(f, "%d\n", i);
fclose(f);
}
IG_API int bar(void) {
FILE *f = fopen("bar.txt", "a+");
fprintf(f, "bar!\n");
fclose(f);
return 22;
}
IG_API void transmitIR(unsigned *data, int length) {
FILE *f = fopen("transmit.txt", "a+");
for(int i = 0; i < length; ++i)
fprintf(f, "%d, ", data[i]);
fprintf(f, "\n");
fclose(f);
}
IG_API int receiveIR(unsigned *data, int length) {
for(int i = 0; i < length; ++i)
data[i] = 4;
return length;
}
C# (the caller):
[DllImport("Plugin.dll")]
static extern void foo(int i);
[DllImport("Plugin.dll")]
static extern int bar();
[DllImport("Plugin.dll")]
static extern void transmitIR(uint[] data, int length);
[DllImport("Plugin.dll")]
static extern int receiveIR(out uint[] data, int length);
I'm at a loss here. What am I doing wrong? Since I can't even get foo(int) to work, that seems like a good place to start.
Upvotes: 3
Views: 14033
Reputation: 4195
Do you know the calling convention of the C functions? Like the error said it is probably a mismatch. The default calling convention is stdcall but if those function use a cdecl convention you would likely get this error. Try
[DllImport("Plugin.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void foo(int i);
Upvotes: 1
Reputation: 612854
Your C code uses cdecl calling convention. The C# code uses stdcall.
All the DLLImport
attributes should be:
[DllImport("Plugin.dll", CallingConvention=CallingConvention.Cdecl)]
Of course you could alternatively switch the C code to stdcall using __stdcall
. But make sure you only do one of these!
receiveIR
doesn't need the out
. You should declare it:
static extern int receiveIR(uint[] data, int length);
Upvotes: 6