JNI class and interface naming - java-native-interface

inside my JNI test app, I use JNIViie as projet name. In this case I have
JNIViie.java
native lib: JNIViie.cpp / JNIViie.h finaly libJNIViie.so
Everything is woking fine.
static {
System.loadLibrary("JNIViie");
}
and calling JNI function:
JNIEXPORT jobject JNICALL Java_JNIViie_getMediumInformation
( JNIEnv *env, jobject jobj );
is working fine. But now I want to use the JNIViie native lib inside an app calling "MyApp" but leave the native lib with the naming JNIViie. My question is now, is this possible or need the native lib the same naming as the app?

Related

Using a c++ builder application with an external dll

I'm trying to use an external dll in my c++ builder application. The dll (let.s call it X.dll) was created with Qt Creator (using MingW 32 bit compiler, tried gcc as well )
and consists of a single functon to keep things simple (besides X.dll, an import library X.a is also created).
The dll header (Dll_lib.h) is basically just
__declspec(dllexport) Dll_method(float *p, int n);
If I create a simple Qt application, add the dll header to it and link it to the dll import library X.a, everythink works as expected.
However, when I try to use the dll in my c++ builder application, I get an "unresolved external _Dll_method referenced from ..." error.
The part of my c++ builder app that references the dll looks like
#include "lib\Dll_lib.h"
#pragma comment(lib, "X.lib")
__declspec(dllimport) Dll_method(float *p, int n);
.....
X.lib was created directly from the dll using the implib tool that comes bundled with c++ builder. I also tried to create X.lib from X.a using coff2omf tool but nothing worked and I always get the same error message.
C++ environments have a habit of name mangling to support overloads, different arguments with the same name, like:
int use(int x, char y); // mangles to something like use__Int__Chr.
int use(double x); // mangles to something like use__Dbl.
This allows the correct one to be linked depending on the arguments.
You may need to wrap it inside extern "C" to get it to not mangle the name, something like:
extern "C" {
__declspec(dllimport) Dll_method(float *p, int n);
}
That's assuming you're creating it without name mangling and using it from something that assumes it is mangled. If it's mangled on both sides, you'll probably have to create and use it with extern "C" since there's no guarantee different compilers will mangle with the same rules.
As an aside, you should be able to examine the object files or DLLs created by your toolchain, to ascertain what the function is called where it's defined and also what it's expected to be by the caller. Under Linux, I'd use something like nm, I'm not sure what the equivalent is for Windows.

Can I add C++ DLL in a ASP MVC application

I am trying to add a reference to a DLL built using C++ in ASP.Net MVC 5 application.
I want to call functions in DLL from the app.
Yes you can. The key here is "platform invoke".
You need to create a class holding the DLL methods (Win32 in the sample)
You need to define the prototypes/signatures of the DLL methods, using the DllImport annotation
Now you can call those methods
This sample is taken from the Microsoft documentation:
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr MessageBox(int hWnd, String text,
String caption, uint type);
}
public class HelloWorld {
public static void Main() {
Win32.MessageBox(0, "Hello World", "Platform Invoke Sample", 0);
}
}
Yes, any native or unmanaged DLL can be used with ASP MVC applications. The builds should be targeting the same Platform. If a C++ DLL has been built for x64 platform, then the application(web/console) importing it should also be built for the same configuration.
See the post from #bdongus for importing using DllImport. Also the servers should run on the same platform.

Getting my App with JNI custom native code to work on 32 bit Windows 10 environment but getting "unsatisfiedlinkerror can't find dependent libraries"

I currently come across with an issue getting my application, App, (written and built under Eclipse RCP), to work on 32bit Windows 10 environment.
Here’s the background, I recently implemented a Windows Shutdown Blocker capability using JNI by embedding that capability in a c++ native code. As a result I generated 2 versions of the dll (using Cygwin – mingw32 capabilities - https://www3.ntu.edu.sg/home/ehchua/programming/howto/Cygwin_HowTo.html) one for 64 bit (same as my dev pc) and one for 32 bit. Then bundle them up in OSGi Bundle native-code. Finally the application is then packaged up and built into a .exe that can be deployed to client machines. Some clients use 32bit Windows so I have to cater for it.
In order to test this, I setup a vm using my pc’s Hyper-V function with Windows 10 32bit OS installed (a Windows evaluation license). Deployed my app in there and tried initiate activities that kicks off the Windows Shutdown Blocker capabilities I’ve produced.
Then I get the following error in the logs (I don’t get this issue in my 64bit Windows host environment and it’s working perfectly):
!SESSION 2020-01-21 16:48:42.604 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.8.0_60
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en _AU
Framework arguments: --startup plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar
Command-line arguments: -os win32 -ws win32 -arch x86 --startup plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar -user #user.home -data #user.home/App/202001201633
!ENTRY org.eclipse.ui 2 0 2020-01-21 16:50:10.579
!MESSAGE Save All Failed
!STACK 0
java.lang.UnsatisfiedLinkError: C:\Users\Dale\App\202001201633\configuration\org.eclipse.osgi\11\0\.cp\lib\shutdown\windows-i686\ShutdownBlocker.dll: Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1938)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1834)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
…
The end-to-end process on how I generated the .dll file goes like this:
Download and install Cygwin including the g++ compilers (32bit and 64bit)
Open Windows command prompt
Generate .h file from JNI class:
javac -h . ShutdownBlocker.java
This is the Java file
public class ShutdownBlocker {
private static boolean nativeLibLoaded;
public static void loadLibrary() {
if(!nativeLibLoaded) {
System.loadLibrary("ShutdownBlocker");
nativeLibLoaded=true;
}
}
public static native void shutdownBlockReasonCreate(String title, String reasonText);
public static native void shutdownBlockReasonDestroy(String title);
}
This is the .h file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_app_service_util_shutdown_ShutdownBlocker */
#ifndef _Included_com_app_service_util_shutdown_ShutdownBlocker
#define _Included_com_app_service_util_shutdown_ShutdownBlocker
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_app_service_util_shutdown_ShutdownBlocker
* Method: shutdownBlockReasonCreate
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonCreate
(JNIEnv *, jclass, jstring, jstring);
/*
* Class: com_app_service_util_shutdown_ShutdownBlocker
* Method: shutdownBlockReasonDestroy
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonDestroy
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
Create a .cpp file, i.e. ShutdownBlocker.cpp
#include <jni.h>
#include <iostream>
#include "com_app_service_util_shutdown_ShutdownBlocker.h"
#include <windows.h>
#include <commctrl.h>
using namespace std;
namespace {
LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";
LRESULT CALLBACK AppWndProc(
_In_ HWND hWnd,
_In_ UINT message,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ UINT_PTR uIdSubclass,
_In_ DWORD_PTR dwRefData
) {
// Callback function required to process some of the key OS messages in order to stall shutdown
switch (message) {
case WM_QUERYENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_ENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
break;
}
return DefSubclassProc(hWnd, message, wParam, lParam);
}
}
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title, jstring reasonText) {
SHUTDOWN_REASON = (LPCWSTR) env->GetStringChars(reasonText, NULL);
// Parse reasonText string passed in from Java code and retrieve handle to the App window with it
const jchar *str = env->GetStringChars(title, NULL);
HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
env->ReleaseStringChars(title, str);
if (hWnd == NULL) {
return;
}
ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);
// Obtain control of the window by subclassing its procedure
SetWindowSubclass(hWnd, &AppWndProc, 1, 0);
return;
}
JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
// Parse reasonText string passed in from Java code and retrieve handle to the App window with it
const jchar *str = env->GetStringChars(title, NULL);
HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
env->ReleaseStringChars(title, str);
if (hWnd == NULL) {
return;
}
// Release control of the window procedure
RemoveWindowSubclass(hWnd, &AppWndProc, 1);
ShutdownBlockReasonDestroy(hWnd);
return;
}
Open Cygwin
Run following command to generate ShutdownBlocker.dll file for each Windows OS architecture
For 64bit windows
x86_64-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,"C:\Windows\System32\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
For 32bit windows
i686-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,--enable-stdcall-fixup "C:\Windows\SysWOW64\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
Copy the dll files to appropriate location in order for OSGi Bundle to reference
Update OSGi reference
Update build.properties
Update MANIFEST.MF. Pasting relevant section here:
Bundle-NativeCode: lib/shutdown/windows-amd64/ShutdownBlocker.dll;
processor=x86_64,
lib/shutdown/windows-i686/ShutdownBlocker.dll;
processor=x86, *
Save -> Refresh -> Clean -> commit change
Using build tools to generate the setup.exe executable one (which bundles with Java runtime) for each OS architecture
Deploy and run setup32bit.exe in my 32 bit Windows VM (as mentioned above)
Run the App to kick-off the Shutdown Blocker capability
Then I get the above error which prevents the initiation of Shutdown Blocker capability
My approach to fix it (in vain):
I tried to use a DLL Dependency Walker as recommended in this post JNI dependent libraries. Ran it and found it throwing a lot of error on dependencies (which I don’t find it very helpful, because I did the same on a random c:\windows\system32 dll file which gives me similar outcome)
Or maybe I’m not using this tool correctly, here’s how I run it:
C:\Users\Dale >depends.exe ShutdownBlocker.dll
Then I found another post that suggests using a Cygwin capability called “objdump” (https://linux-tips.com/t/how-can-i-find-library-dependencies-of-a-windows-dll/328) I ran it and I got this:
$ objdump -p ShutdownBlocker.dll | grep DLL
DLL
vma: Hint Time Forward DLL First
DLL Name: KERNEL32.dll
DLL Name: msvcrt.dll
DLL Name: USER32.dll
DLL Name: libstdc++-6.dll
DLL Name: COMCTL32.dll
Seems promising and I found “libstdc++-6.dll” is the only dll missing on the new 32bit vm. So I copied this .dll file into a directory and updated PATH variable.
Running the App again but the change made no difference (same error)
In which case, how do I know which library it has trouble finding? Or anything I did wrong here?
Thanks in advance for anyone who can shed some light on this issue. And really appreciated your time on this!
Updated DLL Dependency Walker Image
Updated DLL Dependency Walker Image
Think I found a resolution to the issue of finding dependency dll for my ShutdownBlocker.dll. As you can see in the above image all looks fine now. It turned out by moving all the dependent libraries such as libstdc++-6.dll, libgcc_s_sjlj-1.dll and libwinpthread-1.dll to the same directory as ShutdownBlocker.dll solve the problem. Adding these dlls into PATH seemed to fix the error I had. But now I'm getting a different error:
!ENTRY org.eclipse.ui 4 0 2020-01-22 16:57:22.218
!MESSAGE Unhandled event loop exception
!STACK 0
java.lang.UnsatisfiedLinkError: com.app.service.util.shutdown.ShutdownBlocker.shutdownBlockReasonCreate(Ljava/lang/String;Ljava/lang/String;)V
(not sure if I can still discuss this issue here or I need to create a new question?)

c++ dll function export naming conventions (mangling)

I am totally new in C++ and starting with creating a simple dll and console app that tests the dll. The dll plugin afterwards should work on x86 machines (diag tools, ECU or PLC). The samples given to me that I fallow the same structure exports dll function as __sdcall. so my helloWorld project looks like:
plugin.dll
-----------
plugin.h
#pragma once
#include "types.h"
#define EXPORT extern "C" __declspec (dllexport)
EXPORT S32 WINAPI Greetings(string *str);
plugin.cpp
#include "plugin.h"
#include "types.h"
S32 __stdcall Greetings(string *str){*str = "Hello From Plugin!"; return -1;}
and the console app looks like: (both are in same solution, project/properties/cc++/adnvances/callingConvention = __cdecl (/Gd))
VS settings - Solution configuration=debug, Solution Platforms=x86
main.cpp
HMODULE DllHandler = ::LoadLibrary(L"plugin.dll");
string greetingText;
typedef U32(*Type)(string*);
Type greetings = reinterpret_cast<Type>(GetProcAddress(DllHandler, "Greetings"));
greetings(&greetingText);
cout << greetingText << endl;
Now, without plugin.def the GetProcAddress(DllHandler, "Greetings") returns null (0x000000) with the plugin.def (alongside with EXPORT) I get the Greetings with decoration plugin.dll!Greetings#4 the call will succeed but get
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
also no casting with naming convention is allowed.
I red many posts about __cdecl __stdcall but mostly explaining the assembly level that who cleans the stack, or using either .def or extern "C" with export.
I totally got lost in naming convention and mangling in C++. is related to local project setting or the dll will run on all environments? specially in this sample project how should I handle it?

A simple DLL using VS2010 MFC + a test app

I am trying to build a very simple DLL file which supports MFC.
I use VS2010.
All the examples I found on the net shows how to export class function members.
But my client, at the end, should be a C program. Meaning, it doesn't know to use classes and objects.
I just need to export some simple functions for it.
What I did until now is to put the following on my dll cpp file:
extern "C" __declspec(dllexport) CString SayHello (CString strName){
return theApp.SayHello(strName);
}
and on the app class I wrote:
CString CMyDLLApp::SayHello(CString strName){
return (CString)"Hello " + strName;
}
I created a simple dialog based app, which was suppose to use this function like this
CString strResult = SayHello(m_edit);
After I included the DLL h file at the top of the file:
#include "..\MyDll\MyDll.h"
But the compiler says : error C3861: 'SayHello': identifier not found
Can you please guide me how to do it? Don't offer me to not to use MFC on my DLL because I want to use the DB classes of it.
Also, how to tests it? I don't care if the test program itself is MFC based as well.
Try this declaration in your app to get rid of the compiler error:
extern "C" __declspec(dllimport) CString SayHello (CString strName);
But you cannot get theApp directly from within the DLL. Add another DLL function to pass a pointer to theApp to the DLL.