📄 tij0191.html
字号:
<font color="#990000"><PRE>#include <windows.h>
#include "ShowMsgBox.h"
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason, <font color="#0000ff">void</font>** lpReserved) {
<font color="#0000ff">return</font> TRUE;
}
JNIEXPORT <font color="#0000ff">void</font> JNICALL
Java_ShowMsgBox_ShowMessage(JNIEnv * jEnv,
jobject <font color="#0000ff">this</font>, jstring jMsg) {
<font color="#0000ff">const</font> <font color="#0000ff">char</font> * msg;
msg = (*jEnv)->GetStringUTFChars(jEnv, jMsg,0);
MessageBox(HWND_DESKTOP, msg,
"Thinking in Java: JNI",
MB_OK | MB_ICONEXCLAMATION);
(*jEnv)->ReleaseStringUTFChars(jEnv, jMsg,msg);
}</PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If
you have no interest in Win32, just skip the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>MessageBox( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
call; the interesting part is the surrounding code. The arguments that are
passed into the native method are the gateway back into Java. The first, of type
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">contains
all the hooks that allow you to call back into the JVM. (We’ll look at
this in the next section.) The second argument has a different meaning
depending on the type of method. For non-
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>static</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods like the example above (also called
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>instance
methods
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">),
the second argument is the equivalent of the “this” pointer in C++
and similar to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>this</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in Java: it’s a reference to the object that called the native method. For
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>static</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods, it’s a reference to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Class</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object where the method is implemented.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
remaining arguments represent the Java objects passed into the native method
call. Primitives are also passed in this way, but they come in by value.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
the following sections we’ll explain this code by looking at how to
access and control the JVM from inside a native method.
</FONT><a name="_Toc408018820"></a><P></DIV>
<A NAME="Heading590"></A><H3 ALIGN=LEFT>
Accessing
JNI functions:
<P>The
JNIEnv argument
<P><A NAME="Index3095"></A><A NAME="Index3096"></A></H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">JNI
functions are those that the programmer uses to interact with the JVM from
inside a native method. As you can see in the example above, every JNI native
method receives a special argument as its first parameter: the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
argument, which is a pointer to a special JNI data structure of type
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv_</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
One element of the JNI data structure is a pointer to an array generated by the
JVM; each element of this array is a pointer to a JNI function. The JNI
functions can be called from the native method by dereferencing these pointers
(it’s simpler than it sounds). Every JVM provides its own implementation
of the JNI functions, but their addresses will always be at predefined offsets.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Through
the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
argument, the programmer has access to a large set of functions. These
functions can be grouped into the following categories:
</FONT><P></DIV>
<UL>
<LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Obtaining
version information
</FONT><LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Performing
class and object operations
</FONT><LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Handling
global and local references to Java objects
</FONT><LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Accessing
instance fields and static fields
</FONT><LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Calling
instance methods and static methods
</FONT><LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Performing
string and array operations
</FONT><LI><FONT FACE="Symbol" SIZE=3 COLOR="Black"> </FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Generating
and handling Java exceptions
</FONT></UL><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
number of JNI functions is quite large and won’t be covered here.
Instead, I’ll show the rationale behind the use of these functions. For
more detailed information, consult your compiler’s JNI documentation.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If
you take a look at the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>jni.h</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
header file, you’ll see that inside the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>#ifdef
__cplusplus
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
preprocessor conditional, the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv_</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
structure is defined as a class when compiled by a C++ compiler. This class
contains a number of inline functions that let you access the JNI functions
with an easy and familiar syntax. For example, the line in the preceding example
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">(*jEnv)->ReleaseStringUTFChars(jEnv,
jMsg,msg);
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">can
be rewritten as follows in C++:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">jEnv->ReleaseStringUTFChars(jMsg,msg);</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You’ll
notice that you no longer need the double dereferencing of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>jEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
pointer, and that the same pointer is no longer passed as the first parameter
to the JNI function call. In the rest of these examples, I’ll use the C++
style.
</FONT><P></DIV>
<A NAME="Heading591"></A><H4 ALIGN=LEFT>
Accessing
Java Strings
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">As
an example of accessing a JNI function, consider the code shown above. Here, the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
argument
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>jEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is used to access a Java
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Java
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s
are in Unicode format, so if you receive one and want to pass it to a
non-Unicode function (
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>printf( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
for example), you must first convert it into ASCII characters with the JNI
function
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>GetStringUTFChars( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
This function takes a Java
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and converts it to UTF-8 characters. (These are 8 bits wide to hold ASCII
values or 16 bits wide to hold Unicode. If the content of the original string
was composed only of ASCII, the resulting string will be ASCII as well.)
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>GetStringUTFChars</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is the name of one of the fields in the structure that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>JNIEnv</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is indirectly pointing to, and this field in turn is a pointer to a function.
To access the JNI function, we use the traditional C syntax for calling a
function though a pointer. You use the form above to access all of the JNI
functions.
</FONT><a name="_Toc408018821"></a><P></DIV>
<A NAME="Heading592"></A><H3 ALIGN=LEFT>
Passing
and using Java objects
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
the previous example we passed a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to the native method. You can also pass Java objects of your own creation to a
native method. Inside your native method, you can access the fields and methods
of the object that was received.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
pass objects, use the ordinary Java syntax when declaring the native method. In
the example below,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>MyJavaClass</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
has one
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
field and one
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method. The class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>UseObjects
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">declares
a native method that takes an object of class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>MyJavaClass</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
To see if the native method manipulates its argument, the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
field of the argument is set, the native method is called, and then the value
of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
field is printed.
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#0000ff">class</font> MyJavaClass {
<font color="#0000ff">public</font> <font color="#0000ff">void</font> divByTwo() { aValue /= 2; }
<font color="#0000ff">public</font> <font color="#0000ff">int</font> aValue;
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> UseObjects {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -