<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>idv2 &#187; jni</title>
	<atom:link href="http://tech.idv2.com/tag/jni/feed/" rel="self" type="application/rss+xml" />
	<link>http://tech.idv2.com</link>
	<description>关注Web开发技术，关注Internet。</description>
	<lastBuildDate>Tue, 27 Jul 2010 12:54:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>在Java程序中使用JNI调用平台相关函数</title>
		<link>http://tech.idv2.com/2005/11/07/use-jni-in-java/</link>
		<comments>http://tech.idv2.com/2005/11/07/use-jni-in-java/#comments</comments>
		<pubDate>Mon, 07 Nov 2005 07:16:52 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
				<category><![CDATA[编程开发]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jni]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://charlee.itbdns.com/tech/archive/66.html</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>前一阵子遇到的一个问题是，如何在Java程序中调用Windows DLL的函数。查了查资料，得知使用名为JNI（Java Native Interface）的方式可以让Java调用DLL中的函数。JNI的使用方法如下：</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>在Java中定义JNI调用，并撰写使用该JNI调用的相关代码。</li>
<li>根据定义好的JNI调用生成相应的C语言头文件。</li>
<li>利用上一步生成的头文件，使用C书写Windows平台上的代码。</li>
<li>编译C代码生成DLL库文件。</li>
<li>执行Java程序中JNI调用的代码。</li></ol>
<!-- end Pukiwiki generated code--><span id="more-47"></span><!-- begin Pukiwiki generated code--><p>我们可以看到，第三步使用C语言书写代码时，须遵从JNI的规范，这就为我们带来了一个问题：如果我们想使用的DLL文件是已经编译好的，它未必遵从JNI规范，怎么办？另一个问题是，在Java程序中需要定义JNI调用，但是我们显然不希望在业务逻辑代码中定义JNI调用。于是产生了下面的结构：</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2006/09/jni.png" alt="JNI结构图" title="JNI结构图" width="386" height="339" /></div>

<p>最上方的Java Application是业务逻辑的实现部分，最下方的Windows DLL是我们拥有的DLL函数库，而中间虚线框的部分即为使用JNI进行开发的部分。</p>
<p>我们假设Java Application部分的代码如下。文件名为JavaApp.java。</p>
<pre>package jnisample;

public class JavaApp {
    public static final void main(String args[]) {
        JNIWrapper.Hello();
    }
}</pre>
<p>这里JNIWrapper类为我们即将进行开发的JNI Wrapper的类名。</p>
<p>我们先创建一个空的JNIWrapper.java以使得JavaApp.java能够正常编译。</p>
<pre>package jnisample;

class JNIWrapper {
    static void Hello() {}
}</pre>
<p>然后我们编译这两个文件：</p>
<pre>javac -d . JNIWrapper.java
javac -d . JavaApp.java</pre>
<p>编译完成之后我们将在jnisample目录下得到JNIWrapper.class和JavaApp.class两个文件。</p>
<p>我们再假设现有的DLL函数库的实现代码如下：（文件名HelloDll.c）</p>
<pre>#include &lt;windows.h&gt;

__declspec(dllexport) BOOL __stdcall Hello();

BOOL __stdcall Hello() {
    MessageBox(NULL, &quot;Helo, world!&quot;, &quot;Hello&quot;, MB_OK | MB_ICONINFORMATION);
    return TRUE;
}</pre>
<p>然后我们使用Microsoft Visual Studio 6.0自带的编译器 cl 进行编译：</p>
<pre>cl HelloDll.c -MD -LD User32.lib</pre>
<p>这样我们将得到HelloDll.dll文件。将该文件与jnisample目录放到同一层次上。</p>
<p>下面我们来看一下如何使用JNI在JavaApp.java中调用HelloDll.c中的Hello函数。首先我们将JNI Wrapper模块的JNIWrapper.java改成下面的样子：</p>
<pre>package jnisample;

class JNIWrapper {
    static native void _dll_Hello();

    static {
        try {
            System.loadLibrary(&quot;DllWrapper&quot;);
        } catch (Exception e) {
            System.out.println(&quot;DllWrapper.dll load errer&quot;);
        }
    }

    static void Hello() {
        _dll_Hello();
    }
} </pre>
<p>然后再次进行编译：</p>
<pre>javac -d . JNIWrapper.java</pre>
<p>下一步利用J2SE提供的工具来生成必要的头文件。执行下列命令：</p>
<pre>javah -jni jnisample.JNIWrapper</pre>
<p>这样我们得到一个名为jnisample_JNIWrapper.h的文件。打开这个文件之后可以看到，里面定义了这样一个函数：</p>
<pre>JNIEXPORT void JNICALL Java_jnisample_JNIWrapper__1dll_1Hello(JNIEnv *, jclass); </pre>
<p>这就是我们应当在DLL Wrapper模块中实现的函数。</p>
<p>创建DllWrapper.c文件，内容如下：</p>
<pre>#include &quot;jnisample_JNIWrapper.h&quot;
#include &lt;windows.h&gt;

typedef BOOL (*FUNCHELLO)();

JNIEXPORT void JNICALL Java_jnisample_JNIWrapper__1dll_1Hello(JNIEnv * jenv, jclass jcls)
{
    HANDLE hDll;
    FUNCHELLO fnHello;

    hDll = LoadLibrary(&quot;HelloDll.dll&quot;);
    if (hDll) {
        fnHello = (FUNCHELLO)GetProcAddress(hDll, &quot;_Hello@0&quot;);
        if (fnHello) fnHello();
        FreeLibrary(hDll);
    }
}</pre>
<p>然后进行编译：</p>
<pre>cl DllWrapper.c -I&quot;C:\Program Files\java\jdk1.5.0_04\include&quot; -I&quot;C:\Program Files\Java\jdk1.5.0_04\include\win32&quot; -MD -LD</pre>
<p>生成DllWrapper.dll文件。到此为止我们的目录结构如下：</p>
<pre>DllWrapper.dll
HelloDll.dll
jnisample/JNIWrapper.class
jnisample/JavaApp.class</pre>
<p>执行以下命令即可看到执行结果了。</p>
<pre>java jnisample.JavaApp</pre>
<p>以上简单地阐述了如何利用JNI来调用平台相关的本地代码。在实际应用中还会出现很多问题，例如Java和C语言之间的数据类型转换等，这里就不一一详述了。</p>
<p>(示例程序下载)</p>
<div class="img_margin" style="text-align:left"><a href="http://tech.idv2.com/wp-content/uploads/2006/09/jnisample.zip" title="jnisample.zip(2006/12/29 18:57:28 1.1KB)"><img src="http://tech.idv2.com/wp-content/plugins/wp-pukiwiki/img/attach.gif" width="16" height="16" alt="attach" style="border-width:0px" />jnisample.zip</a></div>

<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>前一阵子遇到的一个问题是，如何在Java程序中调用Windows DLL的函数。查了查资料，得知使用名为JNI（Java Native Interface）的方式可以让Java调用DLL中的函数。JNI的使用方法如下：</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>在Java中定义JNI调用，并撰写使用该JNI调用的相关代码。</li>
<li>根据定义好的JNI调用生成相应的C语言头文件。</li>
<li>利用上一步生成的头文件，使用C书写Windows平台上的代码。</li>
<li>编译C代码生成DLL库文件。</li>
<li>执行Java程序中JNI调用的代码。</li></ol>
<!-- end Pukiwiki generated code--><span id="more-47"></span><!-- begin Pukiwiki generated code--><p>我们可以看到，第三步使用C语言书写代码时，须遵从JNI的规范，这就为我们带来了一个问题：如果我们想使用的DLL文件是已经编译好的，它未必遵从JNI规范，怎么办？另一个问题是，在Java程序中需要定义JNI调用，但是我们显然不希望在业务逻辑代码中定义JNI调用。于是产生了下面的结构：</p>
<div class="img_margin" style="text-align:left"><img src="http://tech.idv2.com/wp-content/uploads/2006/09/jni.png" alt="JNI结构图" title="JNI结构图" width="386" height="339" /></div>

<p>最上方的Java Application是业务逻辑的实现部分，最下方的Windows DLL是我们拥有的DLL函数库，而中间虚线框的部分即为使用JNI进行开发的部分。</p>
<p>我们假设Java Application部分的代码如下。文件名为JavaApp.java。</p>
<pre>package jnisample;

public class JavaApp {
    public static final void main(String args[]) {
        JNIWrapper.Hello();
    }
}</pre>
<p>这里JNIWrapper类为我们即将进行开发的JNI Wrapper的类名。</p>
<p>我们先创建一个空的JNIWrapper.java以使得JavaApp.java能够正常编译。</p>
<pre>package jnisample;

class JNIWrapper {
    static void Hello() {}
}</pre>
<p>然后我们编译这两个文件：</p>
<pre>javac -d . JNIWrapper.java
javac -d . JavaApp.java</pre>
<p>编译完成之后我们将在jnisample目录下得到JNIWrapper.class和JavaApp.class两个文件。</p>
<p>我们再假设现有的DLL函数库的实现代码如下：（文件名HelloDll.c）</p>
<pre>#include &lt;windows.h&gt;

__declspec(dllexport) BOOL __stdcall Hello();

BOOL __stdcall Hello() {
    MessageBox(NULL, &quot;Helo, world!&quot;, &quot;Hello&quot;, MB_OK | MB_ICONINFORMATION);
    return TRUE;
}</pre>
<p>然后我们使用Microsoft Visual Studio 6.0自带的编译器 cl 进行编译：</p>
<pre>cl HelloDll.c -MD -LD User32.lib</pre>
<p>这样我们将得到HelloDll.dll文件。将该文件与jnisample目录放到同一层次上。</p>
<p>下面我们来看一下如何使用JNI在JavaApp.java中调用HelloDll.c中的Hello函数。首先我们将JNI Wrapper模块的JNIWrapper.java改成下面的样子：</p>
<pre>package jnisample;

class JNIWrapper {
    static native void _dll_Hello();

    static {
        try {
            System.loadLibrary(&quot;DllWrapper&quot;);
        } catch (Exception e) {
            System.out.println(&quot;DllWrapper.dll load errer&quot;);
        }
    }

    static void Hello() {
        _dll_Hello();
    }
} </pre>
<p>然后再次进行编译：</p>
<pre>javac -d . JNIWrapper.java</pre>
<p>下一步利用J2SE提供的工具来生成必要的头文件。执行下列命令：</p>
<pre>javah -jni jnisample.JNIWrapper</pre>
<p>这样我们得到一个名为jnisample_JNIWrapper.h的文件。打开这个文件之后可以看到，里面定义了这样一个函数：</p>
<pre>JNIEXPORT void JNICALL Java_jnisample_JNIWrapper__1dll_1Hello(JNIEnv *, jclass); </pre>
<p>这就是我们应当在DLL Wrapper模块中实现的函数。</p>
<p>创建DllWrapper.c文件，内容如下：</p>
<pre>#include &quot;jnisample_JNIWrapper.h&quot;
#include &lt;windows.h&gt;

typedef BOOL (*FUNCHELLO)();

JNIEXPORT void JNICALL Java_jnisample_JNIWrapper__1dll_1Hello(JNIEnv * jenv, jclass jcls)
{
    HANDLE hDll;
    FUNCHELLO fnHello;

    hDll = LoadLibrary(&quot;HelloDll.dll&quot;);
    if (hDll) {
        fnHello = (FUNCHELLO)GetProcAddress(hDll, &quot;_Hello@0&quot;);
        if (fnHello) fnHello();
        FreeLibrary(hDll);
    }
}</pre>
<p>然后进行编译：</p>
<pre>cl DllWrapper.c -I&quot;C:\Program Files\java\jdk1.5.0_04\include&quot; -I&quot;C:\Program Files\Java\jdk1.5.0_04\include\win32&quot; -MD -LD</pre>
<p>生成DllWrapper.dll文件。到此为止我们的目录结构如下：</p>
<pre>DllWrapper.dll
HelloDll.dll
jnisample/JNIWrapper.class
jnisample/JavaApp.class</pre>
<p>执行以下命令即可看到执行结果了。</p>
<pre>java jnisample.JavaApp</pre>
<p>以上简单地阐述了如何利用JNI来调用平台相关的本地代码。在实际应用中还会出现很多问题，例如Java和C语言之间的数据类型转换等，这里就不一一详述了。</p>
<p>(示例程序下载)</p>
<div class="img_margin" style="text-align:left"><a href="http://tech.idv2.com/wp-content/uploads/2006/09/jnisample.zip" title="jnisample.zip(2006/12/29 18:57:28 1.1KB)"><img src="http://tech.idv2.com/wp-content/plugins/wp-pukiwiki/img/attach.gif" width="16" height="16" alt="attach" style="border-width:0px" />jnisample.zip</a></div>

<!-- end Pukiwiki generated code-->
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2005/11/07/use-jni-in-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
