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.
Related
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 ?
I’ve built a C# DLL (MyTestDll) using the NuGet package UnmanagedExports:
[DllExport("Test", CallingConvention = CallingConvention.Cdecl)]
public static string Test(string name)
{
return "hi " + name + "!";
}
I use it from Python via ctypes DLL import:
path = "C:\\Temp\\Test"
os.chdir(path)
dll = ctypes.WinDLL("MyTestDll.dll")
f = dll.Test
f.restype = ctypes.c_char_p
print f('qqq')
It’s just a fantasy, it works.
Then, I added one more DLL (NoSenseDll):
namespace NoSenseDll
{
public class NoSenseClass
{
public static int Sum(int a, int b)
{
return a + b;
}
}
}
I started to use this NoSenseDll to implement MyTestDll:
[DllExport("Test", CallingConvention = CallingConvention.Cdecl)]
public static string Test(string name)
{
return NoSenseDll.NoSenseClass.Sum(4, 5).ToString();
}
Unfortunately, it does not work. Python says:
WindowsError: [Error -532462766] Windows Error 0xE043435
I’ve tried to add C:\\Temp\\Test to path, but that did not help.
I’ve written a C++ test:
#include "stdafx.h"
#include "windows.h"
#include <iostream>
#include <string>
#include "WinBase.h"
typedef char*(__stdcall *f_funci)(const char*);
int _tmain(int argc, _TCHAR* argv[])
{
int t;
std::string s = "C:\\Temp\\Test\\MyTestDll.dll";
HINSTANCE hGetProcIDDLL = LoadLibrary(std::wstring(s.begin(), s.end()).c_str());
f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "Test");
std::cout << "funci() returned " << funci(std::string("qqq").c_str()) << std::endl;
std::cin >> t;
return EXIT_SUCCESS;
}
It works if the second DLL (NoSenseDll) is in the same folder as the C++ executable. It does not work if I just add NoSenseDll folder to PATH.
Draft solution:
Copy NoSenseDll to the folder of Python, in my case %HOMEPATH%\Anaconda.
Restart IPython/Spyder.
Final solution:
static MyTestDllClass() // static constructor
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
}
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
{
string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
if (File.Exists(assemblyPath) == false) return null;
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
Final note:
If you can’t use IronPython because of matplotlib or pandas,
if you can’t use python.net because of IPython or spyder,
if you don’t want to use COM Interop just because,
and you really want to get C# and Python to work together, use the solution above and C# reflection.
You can also check out Costura.Fody.
This is a build task that will add your dependencies as resources to your assembly and even hooks up a module initializer to load them at runtime.
you cant do it directly with managed code.
register COM object from you dll:
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\regasm.exe my.dll /tlb:my.tlb /codebase
and make com call from python.
see here examples: http://www.codeproject.com/Articles/73880/Using-COM-Objects-in-Scripting-Languages-Part-Py
I am in the need of using some functions in a C made program. To test I defined the following :
This is my .h file :
namespace amt
{
class AMT_EXPORT FaceRecognition
{
public:
std::string amt_test_string(std::string in);
};
};
This is my .cpp file :
#include <memory.h>
#include <string>
#include <iostream>
#include <fstream>
#include "api_shared.h"
#include <sys/stat.h>
using namespace std;
std::string amt::FaceRecognition::amt_test_string (std::string in)
{
std::string s="in: "+in;
std::cout<<s<<std::endl;
return s;
}
I am trying to invoke the method like this :
const string str = "C:\\minimal.dll";
[DllImport(str)]
public static extern string amt_test_string(string input);
static void Main(string[] args)
{
string myinput = "12";
string myoutput = "";
myoutput = amt_test_string(myinput);
Console.WriteLine(myoutput);
Console.Read();
}
But im getting an error saying that it cannot find the entry point named amt_test_string..why so? I am a newbie in C btw
That's not a C DLL, that's a C++ DLL. C and C++ are not the same language. In particular, C++ has name mangling, so the function name which gets exported to the DLL is decorated.
I'd strongly recommend that you avoid having C++ exports in your DLL for that reason. If you use only C exports, the symbol name will be predictable (i.e. will not depend on the specific details of how your C++ compiler decorates names), and you won't have to worry about runtime differences, like how your C++ standard library implements std::string.
I'd recommend your DLL export look like this:
extern "C" // This says that any functions within the block have C linkage
{
// Input is 'in', output gets stored in the 'out' buffer, which must be 'outSize'
// bytes long
void DLLEXPORT amt_FaceRecogniztion_amt_test_string(const char *in, char *out, size_t outSize)
{
...
}
}
This interface does not rely on any particular library's std::string implementation, and C# knows how to martial char* parameters as C strings. However, memory management is more complicated, as you need to figure out an upper bound on how big the output is going to be and pass in an appropriately sized bufer.
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 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.