how to call a C++ dll exported function from c# - c#

This is the first time I'm trying to mix c# an unmanaged C++ so this might be a very simple question , but I don't get it.
I need to call some functions from a C++ dll into C# code. Here is the code for the dll project:
the .h file :
#pragma once
#include <iostream>
#if defined FIRSTDLL_EXPORTS
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR int Add( int a, int b );
DECLDIR void Function( void );
}
the .cpp file
#include "stdafx.h"
#include "myFct.h"
#include <iostream>
extern "C"
{
DECLDIR int Add( int a, int b )
{
return( a + b );
}
DECLDIR void Function( void )
{
std::cout << "DLL Called!" << std::endl;
}
}
I compiled this for both the debug and releas and copied it in the debug folder of my C# project. Neither version worked.
Here is the c# code:
[DllImport("firstDLL.Dll")]
public static extern int Add(int a, int b);
var cyu = Add(3, 5);
And when I try to run this I get
"Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\Program Files\Microsoft Office\Office14\WINWORD.EXE'.
Additional Information: A call to PInvoke function 'MyAddin!MyAddin.ThisAddIn::Add' 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."
But as I see the signatures are the same. What am I missing??
Thanks!

The default calling convention for DLLImport is stdcall, but the default of your C++ code is cdecl. The error message you have seen is what is shown when the calling conventions don't match. The parameter stack cleanup requirements are different for these two calling conventions, and the P/Invoke marshaller detects and reports this.
The fix is to make your calling conventions match.
For example you could change your P/Invoke like so:
[DllImport("firstDLL.Dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
The other option is to change your C++:
#if defined FIRSTDLL_EXPORTS(returntype)
#define DECLDIR __declspec(dllexport) returntype __stdcall
#else
#define DECLDIR __declspec(dllimport) returntype __stdcall
#endif
Clearly you should only do one of these. If you change both C# and C++ you'll have the same problem in reverse!
If I were you I would leave the C++ code as cdecl and change the C# to match.

Related

Passing List<int*[]> from c# to c++ dll

I have spent a lot of days trying to solve this problem. I have a c++ dll function that takes as a parameter a "std::vector<int*> *list", I need to pass a compatible pointer from c# in Unity.
I tried in this way:
UPDATE
c++ code:
#include <stdio.h>
#include <array>
#include <vector>
#if _MSC_VER
#define EXPORT_API
#else
#define EXPORT_API __declspec(dllexport)
#endif
extern "C"{
/* Other function */
EXPORT_API void GetBlocks(std::vector<int*> *list, int* listSize){
list->push_back(std::vector<int>(16*16*16, 1).data());
(*block_size)++;
}
}
c# code:
[DllImport("dllLib", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
unsafe private static extern void GetBlocks(ref List<int*[]> block, ref int blockSize);
void Start() {
int blockSize = 0;
List<int*[]> block = new List<int*[]>();
unsafe
{
GetBlocks(ref block, ref blockSize);
}
}
Unity returns this error:
MarshalDirectiveException: Type System.Collections.Generic.List`1<int[]> which is passed to unmanaged code must have a StructLayout attribute.
*
I suppose that I have to manage somehow the conversion using Marshal, but right now I don't know.
Maybe there could be another type instead of List<int*[]> to pass a list of the pointer to an array.
Can you help me?
Thanks

BadImageFormatException when trying to call dll from C#

I am writing a simple dll using opencv library.
The code for the dll is as follows :
Dll header file -
#pragma once
#include "stdafx.h"
#ifndef _DLL_TUTORIAL_H_
#define _DLL_TUTORIAL_H_
#include <iostream>
#include "opencv2\opencv.hpp"
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR int Add(int a, int b);
DECLDIR void Function(void);
}
#endif
Dll source file -
#define DLL_EXPORT
#include <iostream>
#include "ConsoleApplication3.h"
#include "opencv2\opencv.hpp"
extern "C"
{
DECLDIR int Add(int a, int b)
{
//cv::Mat c(100, 100, CV_8UC1);
return(a + b);
}
DECLDIR void Function(void)
{
std::cout << "DLL Called!" << std::endl;
}
}
C# script to call the method in the dll -
using System;
using System.Runtime.InteropServices;
class Sample
{
[DllImport ("ConsoleApplication3.dll")]
public static extern void Function();
public static void Main()
{
System.Console.WriteLine("hello world");
Function();
}
}
The problem is :-
Error :
Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
at Sample.Function()
at Sample.Main() in c:\Users\supertramp\Documents\Projects\opencv_dll\opencv_dll\filedll.cs:line 13
1) When I generate a 64-bit dll in VS 2015 the error is thrown.
2) When I generate a 32-bit dll , the error is thrown when I uncomment the line in which I define a cv::Mat variable in the Add method.
I am not able to understand where is the problem. I read other posts related to this mention that the error is related to the 32 or 64 bit dll build, but in my case commenting the line where cv::Mat is defined makes the dll run fine.
What might be the issue ?

Use Java DLL in c++ program

I created a simple DLL in Java with JNI . It contains one function the return a string "hello from java dll".
The dll works fine when i use "java " in the cmd.
Now I'm trying to load this DLL in another DLL that I wrote using c++ which already contains 2 working functions.
So I did this:
char* MyFunctions::HelloFromJava() {
HMODULE myDll = LoadLibrary(L"TestJavaDll.dll");
if (myDll != NULL) {
auto fun = (fun_ptr)GetProcAddress(myDll,"HelloFromJava");
if (fun != NULL)
return fun();
else
return "Can't find HelloFromJava";
FreeLibrary(myDll);
}
else {
return "Can't find TestJavaDll.dll";
return "GetLastError()=";
}
}
And in the header:
static __declspec(dllexport) char* HelloFromJava();
And the cpp and header files of the Java dll are:
#include <jni.h>
#include <stdio.h>
#include <windows.h>
#include "TestJavaDll.h"
JNIEXPORT jstring JNICALL
Java_TestJavaDll_HelloFromJava(JNIEnv *env, jobject obj)
{
return env->NewStringUTF("Hello From Java Dll");
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestJavaDll */
#ifndef _Included_TestJavaDll
#define _Included_TestJavaDll
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: TestJavaDll
* Method: HelloFromJava
* Signature: ()V
*/
JNIEXPORT jstring JNICALL Java_TestJavaDll_HelloFromJava
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
To test the c++ DLL i created a .net application that imports all methods in the c++ DLL. So, in this case, I am doing this:
[DllImport("HELLODLL3", EntryPoint = "?HelloFromJava#MyFunctions#HelloCPPLibrary##SAPADXZ")]
public static extern IntPtr HelloFromJava();
And then i print the message:
Console.WriteLine(Marshal.PtrToStringAnsi(HelloFromJava()));
But i get the error:
Unable to find an entry point named '?' in DLL 'HELLODLL3'
where HELLODLL3 is the name of the c++ DLL.
You do not have the correct mangled name for the DllImport:
?HelloFromJava#MyFunctions#HelloCPPLibrary##SAPADXZ
See here for details of how to get it.

Dll Import : Unable to find Entry Point "fnMultiply" in DLL "ImportDLL"

I am trying to use DLLImport for using Win32 dll method in C#.
Win32 dll C++
// .h file
#ifdef IMPORTDLL_EXPORTS
#define IMPORTDLL_API __declspec(dllexport)
#else
#define IMPORTDLL_API __declspec(dllimport)
#endif
// This class is exported from the ImportDLL.dll
class IMPORTDLL_API CImportDLL {
public:
CImportDLL(void);
// TODO: add your methods here.
int Add(int a , int b);
};
extern IMPORTDLL_API int nImportDLL;
IMPORTDLL_API int fnImportDLL(void);
IMPORTDLL_API int fnMultiply(int a,int b);
// .cpp file
// ImportDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "ImportDLL.h"
// This is an example of an exported variable
IMPORTDLL_API int nImportDLL=0;
// This is an example of an exported function.
IMPORTDLL_API int fnImportDLL(void)
{
return 42;
}
IMPORTDLL_API int fnMultiply(int a , int b)
{
return (a*b);
}
Once i build this i get ImportDLL.dll
Now i create Windows Application and add this dll in debug folder and try to use this method using DLLImport
[DllImport("ImportDLL.dll")]
public static extern int fnMultiply(int a, int b);
And I try to call this in C#
int a = fnMultiply(5, 6); // This line gives error Unable to find an entry point
Can any body tell what i am missing?
Thanks.
If you are exporting a C function from a native DLL, you may want to use the __stdcall calling convention (which is equivalent to WINAPI, i.e. the calling convention used by most Win32 API C-interface functions, and which is the default for .NET P/Invoke):
extern "C" MYDLL_API int __stdcall fnMultiply(int a, int b)
{
return a*b;
}
// Note: update also the .h DLL public header file with __stdcall.
In addition, if you want to avoid name mangling, you may want to export using .DEF files.
e.g. Add a .DEF file to your native DLL project, and edit its content something like this:
LIBRARY MYDLL
EXPORTS
fnMultiply #1
...
(You can use the command line tool DUMPBIN/EXPORTS, or a GUI tool like Dependency Walker, to check the actual name with which the function is exported from the DLL.)
Then you can use P/Invoke like this from C#:
[DllImport("MyDLL.dll")]
public static extern int fnMultiply(int a, int b);
Turn off name mangling for the function your exporting. Should assist greatly. Alternative you could load the name mangled (there is a way to config the DllImport attribute to do this, so I hear, but I'm not a C# engineer, so I leave that to you to find if it exists).
extern "C" IMPORTDLL_API int fnMultiply(int a , int b)
{
return (a*b);
}

This simple C++ DLL is not working in C#

I have been spending the day working on come c++ code that I need to run in c#. I ran through this DLL tutorial and have been having trouble using it in my c# app. I will post all the code below.
I am getting this PInvokeStackImbalance error: 'A call to PInvoke function 'frmVideo::Add' 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.'
Thanks as always,
Kevin
DLLTutorial.h
#ifndef _DLL_TUTORIAL_H_
#define _DLL_TUTORIAL_H_
#include <iostream>
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C"
{
DECLDIR int Add( int a, int b );
DECLDIR void Function( void );
}
#endif
DLLTutorial.cpp
#include <iostream>
#define DLL_EXPORT
#include "DLLTutorial.h"
extern "C"
{
DECLDIR int Add( int a, int b )
{
return( a + b );
}
DECLDIR void Function( void )
{
std::cout << "DLL Called!" << std::endl;
}
}
C# code to use the DLL:
using System.Runtime.InteropServices;
[DllImport(#"C:\Users\kpenner\Desktop\DllTutorialProj.dll"]
public static extern int Add(int x, int y);
int x = 5;
int y = 10;
int z = Add(x, y);
You C++ code uses the cdecl calling convention and the C# code defaults to stdcall. This mismatch explains the message that you see.
Make the two sides of the interface match:
[DllImport(#"...", CallingConvention=CallingConvention.Cdecl]
public static extern int Add(int x, int y);
Alternatively you could use stdcall for your C++ exports:
DECLDIR __stdcall int Add( int a, int b );
It's up to you which of these two options you choose, but make sure that you only change one side of the interface and not both, for obvious reasons!

Categories

Resources