I have a C++ (MSVS 2010) DLL from the samples MS give as:
namespace MathLibrary
{
double Functions::Add(double a, double b)
{
return a + b;
}
double Functions::Multiply(double a, double b)
{
return a * b;
}
double Functions::AddMultiply(double a, double b)
{
return a + (a * b);
}
}
dumpbin for the compiled DLL exports the following info:
1 0 00011078 ?Add#Functions#MathLibrary##SANNN#Z = #ILT+115(?Add#Functions#MathLibrary##SANNN#Z)
2 1 000110B9 ?AddMultiply#Functions#MathLibrary##SANNN#Z = #ILT+180(?AddMultiply#Functions#MathLibrary##SANNN#Z)
3 2 00011005 ?Multiply#Functions#MathLibrary##SANNN#Z = #ILT+0(?Multiply#Functions#MathLibrary##SANNN#Z)
So I've written C# code (.NET framework 4.5.2) to call the Add function as:
namespace ConsoleApplication5
{
class Program
{
[DllImport(#"MathLib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "#1")]
public static extern int Add(Int32 a, Int32 b);
public unsafe static void Main()
{
int i = Add( 1,3 );
Console.WriteLine(i);
Console.ReadLine();
}
}
}
When I run this console application, it always outputs
-858993460
regardless of the arguments passed to the Add function.
Can anyone suggest what this output represents, and how to fix my calling code?
-858993460 expressed in hexadecimal is 0xCCCCCCCC. This is the value that Microsoft C/C++ compiler uses for uninitialized variables in a Debug build. My initial suspicion is that the value returned from your DLL is a variable that never actually got assigned.
Also, the fact that your C# code is declaring the function to be using and returning integers, but the actual C++ code implementation is using doubles could also be the problem. MSVC Functions returning integers typically stuff the result into the EAX register, but I suspect that's not the case for functions that return a floating point value. That might explain it. But at best, this is "undefined behavior".
I suspect what you really need in the C# code is this declaration for Add:
[DllImport(#"MathLib.dll", CharSet = CharSet.Ansi, CallingConvention =
CallingConvention.Cdecl, EntryPoint = "#1")]
public static extern double Add(double a, double b);
Related
Im trying to return a struct from a call to a c++ dll from c#, and I get some complicated and bad behaviour that I dont understand. If my struct contains a constructor I get a memory access violation when returning it, if it is less than 12 bytes. If it is larger there is no problem. If I remove the constructor it works for all sizes. I suppose this could have something to do with my calls being c-style but I cannot find information about this. So it would be much appreciated if someone could explain or point my in a good direction of what is going on. Below are examples of code that does and does not work:
Code that works
C++ side header:
#define DLL_API __declspec(dllexport)
struct Struct4Byte
{
int x1;
};
struct Struct12Byte
{
int x1;
int x2;
int x3;
Struct12Byte() { x1 = 0; x2 = 1; x3 = 2; }
};
#ifdef __cplusplus
extern "C" {
#endif
DLL_API Struct4Byte Function4Byte(int x);
DLL_API Struct12Byte Function12Byte(int x);
#ifdef __cplusplus
}
#endif
C++ file:
Struct4Byte Function4Byte(int x)
{
Struct4Byte output;
output.x1 = 1 + x;
return output;
}
Struct12Byte Function12Byte(int x)
{
Struct12Byte output;
output.x1 = 1 + x;
output.x2 = 2 + x;
output.x3 = 3 + x;
return output;
}
On the calling side (C#) I do:
[StructLayout(LayoutKind.Sequential)]
internal struct Struct4Byte
{
public int x1;
}
[StructLayout(LayoutKind.Sequential)]
internal struct Struct12Byte
{
public int x1;
public int x2;
public int x3;
}
class Program
{
static void Main(string[] args)
{
Struct4Byte result1 = Function4Byte(3);
Struct12Byte result2 = Function12Byte(3);
}
[DllImport(#"PInvokeCheck.dll")]
internal static extern Struct4Byte Function4Byte(int x);
[DllImport(#"PInvokeCheck.dll")]
internal static extern Struct12Byte Function12Byte(int x);
}
Code that does not work
If I now change in the header file the definition of the Struct4Byte to:
struct Struct4Byte
{
int x1;
Struct4Byte(){ x1 = 0; }
};
then I get Memory Access violation.
I've noted something that might be of interest. The problem is already when calling Function4Byte. Putting a brakpoint and viewing x in the function (I put the function again below) shows that x get some random value.
Struct4Byte Function4Byte(int x)
{
Struct4Byte output;
output.x1 = 1 + x;
return output;
}
I might have found the issue. Their was a warning that I had missed that: warning C4190: 'Function4Byte' has C-linkage specified, but returns UDT 'Struct4Byte' which is incompatible with C. From this discussion it is clear that it can lead to some undefined behaviour and that the layout of the struct may change: Error in C++ code linkage: warning C4190: type has C-linkage specified, but returns UDT which is incompatible with C
So that seems explain the problem I've had.
Yea returning structs like that isn't supported and the none of Microsoft's mainline P/Invoke articles represent an example of returning structs like that. None that I read anyways.
Here's a git hub example of your project doing it the correct way.
https://github.com/ditchcode/PInvokeTesting
I found this article most helpful on the marshaling of Structs and Classes
https://learn.microsoft.com/en-us/dotnet/framework/interop/passing-structures
I think the reason is explained in the calling conventions.
x64 calling convention
User-defined types can be returned by value from global functions and static member functions. To return a user-defined type by value in RAX, it must have a length of 1, 2, 4, 8, 16, 32, or 64 bits. It must also have no user-defined constructor, destructor, or copy assignment operator. It can have no private or protected non-static data members, and no non-static data members of reference type. It can't have base classes or virtual functions. And, it can only have data members that also meet these requirements. (This definition is essentially the same as a C++03 POD type. Because the definition has changed in the C++11 standard, we don't recommend using std::is_pod for this test.) Otherwise, the caller must allocate memory for the return value and pass a pointer to it as the first argument. The remaining arguments are then shifted one argument to the right. The same pointer must be returned by the callee in RAX.
x86 calling convention
On x86 platforms, all arguments are widened to 32 bits when they are passed. Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register as pointers to hidden return structures. Parameters are pushed onto the stack from right to left. Structures that are not PODs will not be returned in registers.
Doing what is says for x64 is a good alternative solution.
the caller must allocate memory for the return value and pass a pointer to it as the first argument
So your code would look like this
Struct4Byte Function4Byte(Struct4Byte& output, int x)
{
output.x1 = 1 + x;
}
Struct12Byte Function12Byte(Struct12Byte& output, int x)
{
output.x1 = 1 + x;
output.x2 = 2 + x;
output.x3 = 3 + x;
}
class Program
{
static void Main(string[] args)
{
Struct4Byte = Function4Byte(out var result1, 3);
Function12Byte(out var result2, 3);
}
[DllImport(#"PInvokeCheck.dll")]
internal static extern void Function4Byte(out Struct4Byte result, int x);
[DllImport(#"PInvokeCheck.dll")]
internal static extern void Function12Byte(out Struct12Byte result, intx);
}
In my attempt to use a DLL having mangled names I see an odd, but consistent, behaviour where the last argument passed is corrupted/uninitialized.
When I compile the code below using 'extern "C"' it works fine, but I would very much like the possibility of overloaded methods hence the use of mangled names. Everything is compiled in 64-bit.
MyDll.h:
#define MYDLL_API __declspec(dllexport)
class myDll
{
public:
MYDLL_API int Add(int, int);
MYDLL_API int Sub(int, int);
};
myDll.cpp:
int myDll::Add(int a, int b)
{
printf("a is %d, b is %d\n", a, b);
return a + b;
}
int myDll::Sub(int a, int b)
{
printf("a is %d, b is %d\n", a, b);
return a - b;
}
Output from dumpbin:
Dump of file .\myDll.dll
File Type: DLL
Section contains the following exports for myDll.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 0001101E ?Add#myDll##QEAAHHH#Z = #ILT+25(?Add#myDll##QEAAHHH#Z)
2 1 0001131B ?Sub#myDll##QEAAHHH#Z = #ILT+790(?Sub#myDll##QEAAHHH#Z)
The application where I import the DLL is written in C#
namespace UseMyDll
{
class Program
{
static void Main(string[] args)
{
int a = Add(1, 2);
int b = Sub(2, 1);
}
[DllImport("myDll.dll",
EntryPoint = "?Add#myDll##QEAAHHH#Z",
ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
[DllImport("myDll.dll",
EntryPoint = "?Sub#myDll##QEAAHHH#Z",
ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
public static extern int Sub(int a, int b);
}
}
Output from running the C# program:
a is 2, b is -1588955232
a is 1, b is -1588955232
As can be seen from the program output the last parameter passed is not quite what I expect. Any hints on what I'm doing wrong?
I am very new to c++ so I might have some mistakes on this side.
So I started with writing simple C++ function that will contain struct as return type:
my c++ struct:
struct a {
int i;
};
my c++ function declaration in library.h file:
extern "C" __declspec(dllexport) struct a retNumber();
my c++ function description in library.cpp file:
struct a retNumber()
{
struct a r = a();
r.i = 22;
return r;
}
So I just want to compile it and then use it in c# code, I am getting following compile errors:
error C2371: 'retNumber' : redefinition; different basic types
error C2526: 'retNumber' : C linkage function cannot return C++ class
error C2556: 'a retNumber(void)' : overloaded function differs only by return type from 'void retNumber(void)'
That's the first part of my question and if you guys will help me to solve it, I will really appreciate it, once it's solved, I am going to declare the same struct in my c# code:
struct a1
{
int i;
}
Then I am going to import my c++ function:
[DllImport("library.dll")]
public static extern a1 retNumber();
Once it's done, I will create GCHandle:
a1 test = retNumber();
GCHandle handle = GCHandle.Alloc(test, GCHandleType.Pinned);
and then I will try to convert my actual result and release memory:
Object temp = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(a1));
handle.Free();
So by this time I should have object that is of type a1 and contains variable i with value 22.
If anyone can please delagate through this process I will greatly appreciate it!
Thank you very much in advance!!!
On the C++ side, you need to wrap everything in extern "C", including the struct:
extern "C" {
struct a {
int i;
};
};
On the C# side, you'll need to specify the calling convention properly:
[DllImport("library.dll", CallingConvention=CallingConvention.Cdecl))]
public static extern a1 retNumber();
Once you do that, there is no need for the Marshal.PtrToStructure call. Just do:
a1 test = retNumber();
Console.WriteLine(a1.i); // Should print 22
What's the appropiate signature/marshall attribute to be able to get output params using pointers params? So far I tried this:
// Function to calculate the norm of vector. !0 on error.
// int err_NormVec(int size, double * vector, double * norm)
[DllImport("vectors.dll")]
int err_NormVec(int size, double[] vector, ref double norm)
The previous approach doesn't pop back the value to .NET from C. I also tried to use pinned GCHandle, with the IntPtr signature.
[DllImport("vectors.dll")]
int err_NormVec(int size, double[] vector, IntPtr norm)
public void doSomething()
{
double norm = 0;
// ...
GCHandle handle = GCHandle.Alloc(norm, GCHandleType.Pinned);
int status = err_NormVec(vector.Lenght, vector, handle.AddrOfPinnedObject());
// ... clean gchandle, check status and so on
}
In this case I got the value back but on the GCHandle.Target, not on the original norm. Which is annoying. I would like to be able to pin the intptr of the norm it self not just a copy.
What is the appropiate signature to return a value using a pointer? Is there a supported way to get a IntPtr to an int value?
This works for me (as it should):
//C++ DLL (__stdcall calling convention)
extern "C" __declspec(dllexport) void Foo(double *result) {
*result = 1.2;
}
//C#
class Program
{
[DllImport( "Snadbox.dll", CallingConvention=CallingConvention.StdCall )]
static extern void Foo( ref double output );
static void Main( string[] args )
{
double d = 0;
Foo( ref d );
Console.WriteLine( d ); // prints "1.2"
}
}
Passing the double using the ref keyword is sufficient. So, I am led to believe that there is something wrong (or misunderstood) in the implementation. Can you post the implementation for us?
Also, perhaps you are building the C++ version using the default calling convention (cdecl), but .NET is using StdCall. Have you made sure that these line up? You may crash if they are mixed, but there is no guarantee. For instance, in my example, if I change the C++ side to cdecl then the out parameter is read back as 0.
I have some problems working with boolean types and marshalling this in a struct back and forth between C# and C. I am very rusty in C but hopefully there's nothing crucially wrong in that part.
As far as I've read/seen, .NET Boolean and C# bool type is 4 bytes long whilst the C type bool is only 1 byte. For memory footprint reasons, I do not which to use the defined BOOL 4 bytes version in the C code.
Here is some simple test code that hopefully will make my questions clear:
C code:
typedef struct
{
double SomeDouble1;
double SomeDouble2;
int SomeInteger;
bool SomeBool1;
bool SomeBool2;
} TestStruct;
extern "C" __declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs);
__declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs)
{
return structs;
}
I call this code in C# using the following definitions:
[StructLayout(LayoutKind.Explicit)]
public struct TestStruct
{
[FieldOffset(0)]
public double SomeDouble1;
[FieldOffset(8)]
public double SomeDouble2;
[FieldOffset(16)]
public int SomeInteger;
[FieldOffset(17), MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[FieldOffset(18), MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
[DllImport("Front.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr TestGetBackStruct([MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] TestStruct[] structs);
and here is the actual test function in C#:
[Test]
public void Test_CheckStructParsing()
{
var theStruct = new TestStruct();
theStruct.SomeDouble1 = 1.1;
theStruct.SomeDouble2 = 1.2;
theStruct.SomeInteger = 1;
theStruct.SomeBool1 = true;
theStruct.SomeBool2 = false;
var structs = new TestStruct[] { theStruct };
IntPtr ptr = TestGetBackStruct(structs);
var resultStruct = (TestStruct)Marshal.PtrToStructure(ptr, typeof(TestStruct));
}
This works in the sense that I do get a struct back (using the debugger to inspect it), but with totally wrong values. I.e. the marshalling does not work at all. I've tried different version of the C# struct without success. So here are my questions (1 & 2 most important):
Is the C function correct for this purpose?
How is the struct to be written correctly in order to get me the correct values in the struct back to C#? (Is it even necessary to define the struct with the StructLayout(LayoutKind.Explicit) attribute using the FieldOffset values or can I use StructLayout(LayoutKind.Sequential) instead)?
Since I am returning a pointer to the TestStruct in C, I guess it should be possible to get back an array of TestStructs in C#. But this does not seem to be possible using the Marshal.PtrToStructure function. Would it be possible in some other way?
Apparantly it is possible to use something called unions in C by having multiple struct fields point to the same memory allocation using the same FieldOffset attribute value. I understand this, but I still don't get yet when such scenario would be useful. Please enlighten me.
Can someone recommend a good book on C# P/Invoke to C/C++? I am getting a bit tired of getting pieces of information here and there on the web.
Much obliged for help with these questions. I hope they were not too many.
Stop using LayoutKind.Explicit and get rid of the FieldOffset attributes and your code will work. Your offsets were not correctly aligning the fields.
public struct TestStruct
{
public double SomeDouble1;
public double SomeDouble2;
public int SomeInteger;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
Declare the function in C# like this:
public static extern void TestGetBackStruct(TestStruct[] structs);
The default marshalling will match your C++ declaration (your code is C++ rather than C in fact) but you must make sure that your allocate the TestStruct[] parameter in the C# code before calling the function. Normally you would also pass the length of the array as a parameter so that the C++ code knows how many structs there are.
Please don't try to return the array of structures from the function. Use the structs parameter as an in/out parameter.
I know of no book with an emphasis on P/Invoke. It appears to be something of a black art!