Author: normalnotebook background
The last talks us introduced the basic concepts and basic usage of JNI. Now introduce a complicated example, call the DLL generated by other tools with JNI to implement a particular function. Here we will write a DLL with VC for Java calls.
VC writing simple DLL
This DLL implements a simple string pass, then pops up a message box, displays the passed string, turn the transmitted string into lowercase, returns to the Java program. That is, the Java program and the VC written DLL implementation string intermittence.
Open the VC integrated development environment, select File-> New-> Projects, select the MFC AppWizard (DLL), then enter the project name, here we entered the vjstring. Click Next, remove the default options.
Declaring two methods in vjstring.h header file, the code code is as follows:
........
#include "resource.h" // main symbol This is the code generated by VC
// --------- Add by Normalnotebook 8/9/2004 Start ---------- //
Void ShowMessage (Char * text, char * caption);
Void CTojavastr (Char * Context);
// --------- Add by NormalnoteBook 8/9/2004 end ---------- //
............ .....
Then add the implementation of these two methods in vjstring.cpp.
// --------- Add by Normalnotebook 8/9/2004 Start ---------- //
Void ShowMessage (Char * Text, Char * CAPTION)
{
CSTRING STRTEXT, STRCAPTION;
Strtext.Format (_T ("% s"), text);
STRCAPTION.FORMAT (_T ("% s"), caption);
MessageBox (NULL, TEXT, CAPTION, MB_OK);
}
Void CTojavastr (Char * Context)
{
CString strcontext;
StrContext.Format ("% s", context);
StrContext.maker ();
STRCPY (CONTEXT, (LPCTSTR) StrContext);
}
// --------- Add by NormalnoteBook 8/9/2004 end ---------- //
So far, the DLL part is basically almost. Everyone may be very strange. Why don't you use a CString to do parameters, why use the most original char *. The reason is this: When writing the C / C compilation environment, it is not aware of the MFC class at the C / C compilation environment.
You should also conduct a description of the function in the vjstring.def file, the quote code is as follows:
Exports
Explicit Exports Can Go Here
ShowMessage
CTojavastr
You can start compilation and link it. Then it generates a vjstring.dll this DLL file, and also generates a vjstring.lib file for use (the calling program is a static link DLL).
Copy the DLL and LIB files to a folder. We can also do a .h file, for use. Here we will export two methods, generate a header file of a vjstring.h under this folder. If the call program is a dynamic link, you can do not .lib and .h file. The content of the vjstring.h header is as follows: _Declspec (dllexport) void showMessage (char *, char *);
_Declspec (dllexport) void ctojavastr (char *);
So far, the DLL part of the VC is written. The next step is to complete the JNI section.
JNI section
One. Java section
Here we will give a case that contains the package because there is a package than no package. In the actual project, it may be a case where the package is included (for specific places where you need to pay attention, please see my previous article).
We create a new Java file, named vjstring.java; its contents are as follows:
Package com.convertstring;
Public class vjstring
{
Static
{
System.out.println (System.GetProperty ("java.library.path");
System.LoadLibrary ("jnidll");
}
Public Native Void Showmsg (String text, String Caption);
Public Native String ConvertString (String Context);
}
Then start compiling it, we write a batch file here. Taken to vj.bat, the content is as follows:
Javac -d. vjstring.java
Jar -cf vjstring.jar COM /
Javah com.convertstring.vjstring
PAUSE
Then save it. Double click on Vj.bat to run it. Is there three files in the current folder, one is a vjstring.jar file, com_convertstring_vjstring.h file and COM folder.
You can also write a batch file, directly in DOS, please refer to my previous article.
two. Corresponding C implementation
Here we choose a VC development tool to complete the C implementation section.
Open the VC integrated development environment, choose File-> New-> Projects, select Win32 Dynamic-Link Library, and we name the project to JNIDLL, and the rest will choose the default. At the same time, copy COM_CONVERTSTRING_VJSTRING.H and VJString.h to this project, and also copy the vjstring.lib file to this project. Jni.h's settings See my previous article.
Add com_convertstring_vjstring.h and vjstring.h two headers to the project. We modify the content inside COM_CONVERTSTRING_VJSTRING.H. We will add two functions inside, one to convert the ANSI encoding to Unicode encoding. One is used to convert Unicode encodes to ANSI encoding. Added before #ifdef __cplusplus, the added code is as follows:
// --------- Add by Normalnotebook 8/9/2004 Start ---------- //
Void Convertunitoansi (jnienv *, jstring, char *);
JString Convertansitouni (Jnienv *, Char *);
// --------- Add by NormalnoteBook 8/9/2004 end ---------- // then select New-> File-> C Source File, enter the file name, we take Named JNIDLL. Then there will be an empty jnidll.cpp file, and then the corresponding method of Java will begin, the quaternies are as follows:
#include "com_convertstring_vjstring.h"
#include "stdio.h"
#include "vjstring.h"
#include "windows.h"
/ *
* Class: com_convertstring_vjstring
* Method: Showmsg
* Signature: (Ljava / Lang / String; Ljava / Lang / String;) V
* /
JNIEXPORT VOID JNICALL JAVA_COM_CONVERTSTRING_VJSTRING_SHOWMSG
(JNIENV * ENV, Jobject Obj, JString text, jstring caption)
{
Char chtext [256 * 2];
Char chcaption [256 * 2];
Convertunitoansi (ENV, Text, Chtext);
Convertunitoansi (ENV, CAPTION, CHCAPTION);
ShowMessage (ChText, Chcaption);
}
/ *
* Class: com_convertstring_vjstring
* Method: ConvertString
* Signature: (Ljava / Lang / String;) V
* /
JNIEXPORT JSTRING JNICALL JAVA_COM_CONVERTSTSTRING_VJSTRING_CONVERTSTRING
(JNIENV * ENV, JOBJECT OBJ, JSTRING CONTEXT)
{
Char chcontext [256 * 2];
Convertunitoansi (ENV, Context, Chcontext);
CTOJavastr (chcontext);
Return Convertansitouni (ENV, ChCONTEXT);
}
/ *
* Class: NULL
* Method: ConvertUnitoansi
* Detail: Convert Unicode Encoding to ANSI Code
* /
Void Convertunitoansi (Jnienv * ENV, JString Oldstr, Char * Newstr)
{
INT DESC_LEN = 256 * 2;
Int Len;
IF (oldstr == null || newstr == null)
Return;
Wchar_t * w_buffer = new wchar_t [256];
WCSCPY (w_buffer, env-> getStringChars (OldStr, 0));
ENV-> ReleaseStringChars (Oldstr, W_Buffer);
Len = Widechartomultibyte (CP_ACP, 0, W_Buffer, 1024, NewStr, DESC_LEN, NULL, NULL);
IF (Len> 0 &&len { Newstr [len] = '/ 0'; } Delete [] w_buffer; } / * * Class: NULL * Method: Convertansitouni * Detail: Convert ANSI Coding into Unicode Codes * / JString Convertansitouni (Jnienv * ENV, Char * CSTR) { Int Slen = Strlen (CSTR); IF (! Env || Slen == 0) Return NULL; Jchar * buffer = new jchar [slen]; INT LEN = MultibytetowideChar (CP_ACP, 0, CSTR, STRLEN (CSTR), Buffer, SLEN) IF (Len> 0 &&len Buffer [len] = '/ 0'; JString JS = Env-> Newstring (Buffer, Len); DELETE [] BUFFER; Return JS; } Functions Convertansitouni () and ConvertUnitoansi () are two universal functions that can be copied directly to your code, just pass the string to pass. Before using these two functions, you must include the header file of #include "windows.h" because MultibyToWideChar () and widechartomultibyte () are declared in this. I must remember to add vjstring.lib to the ProjectàSettingàLinkàLibrary Module. Now start compiling it, generate a file of jnidll.dll. Test part Copy jnidll.dll and vjstring.dll to the correct path (the path settings are specifically see the previous article). Then start writing a test program. For a package, the package must be set correctly. If it is a jar file, you will lose it directly to the Lib folder under the JDK directory. Or set the path. The contents of Testjni.java are as follows: Import com.convertstring.vjstring; Public Class Testjni { Public static void main (string args []) { Vjstring str = new vjstring (); String text, caption, context; Text = "Success!"; CAPTION = "Haha ..."; Context = "Founder"; Str.Showmsg (Text, Caption); System.out.println (Str.ConvertString (Context)); } } Then compile, run. Oh, is it successful! But don't be happy too early. I can succeed in the Java console, but it fails to use the JSP page, saying that the function in the localization method is not found. postscript Let's open Jnidll.dll to see other tools. File name: ....../ jnidll / debug / jnidll.dll ------------------------------------------------ The section where the table is exported: .rdata ------------------------------------------------ Original file name jnidll.dll NBase 00000001 Numberoffunctions 00000002 NumberOfnames 00000002 Addressoffunctions 0002AED8ADDRESSOFNAMES 0002AEE0 AddressOfnameRD 0002AEE8 ------------------------------------------------ Export serial number virtual address export function name ------------------------------------------------ 00000001 0000101E _JAVA_COM_CONVERTSTRING_VJSTRING_CONVERTSTRING @ 12 00000002 0000100A _JAVA_COM_CONVERTSTRING_VJSTRING_SHOWMSG @ 16 It is found that the function we export has changed, and we call in the program, ConvertString () and showmsg (), how do you become this? In fact, this is a set of rules of Microsoft. The above reasons may be here wrong, because the function you export is inconsistent with the function you call. So you correct the name of the export function. The method is to add a DEF file. Add a jnidll.def in the C implementation section of Write the JNI. The content is as follows: Library "jnidll" Description 'ImageConvertdll Windows Dynamic Link Library' Exports Explicit Exports Can Go Here Java_com_convertstring_vjstring_showmsg Java_com_convertstring_vjstring_convertstring Then recompile it, then replace the old DLL with new Jnidll.dll, run the program, found in the JSP page. We use tools to analyze this DLL to see. File name: ....../ jnidll / debug / jnidll.dll ------------------------------------------------ The section where the table is exported: .rdata ------------------------------------------------ Original file name jnidll.dll NBase 00000001 Numberoffunctions 00000002 NumberOfnames 00000002 Addressoffunctions 0002AED8 AddressOfnames 0002aee0 AddressOfnameRD 0002AEE8 ------------------------------------------------ Export serial number virtual address export function name ------------------------------------------------ 00000001 0000101E java_com_convertstring_vjstring_convertstring 00000002 0000100A Java_com_convertstring_vjstring_showmsg The found function name is changed. But the name is not the name we call? I think that the situation should be like this: JNI is a localization method. It is necessary to establish a relationship in Java virtual machines and other platforms, inevitably have her own set of rules, which may be reflected here. When we call the function in JNI generated DLL in Java, it is directly called ConvertString () and showmsg (), and the compiler will add a java in front, then add the package name, plus local The class name of the method, finally add the function called, to the DLL to find the corresponding function, turn it into java_com_convertstring_vjstring_convertstring and java_COM_CONVERTSTRING_VJSTRING_SHOWMSG, is it consistent with the function exported in the DLL. If your package is changed, of course you have to rewrite a DLL. There is also an interesting phenomenon that compiles with DOS and written in Eclipse, and the Java.library.Path path sequence is different. In our actual project, write the procedure under DOS, not to put the DLL to the Windows / System32 / below of the system disk. Because there is a to take the current path in our COM component, then other operations. This is a special case. But also tell us a thing at the same time, under DOS, when calling the local approach, is the role of the windows / system32 / below. But in Eclipse, it can be placed casually. When I wrote this version, I put it in the same class directory with the Java file, running is successful. Welcome everyone to communicate with me Normalnotebook@126.com If you reprint, please indicate the source and the author.