⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 delphi-jni-2.html

📁 JNI(java本地接口)之delphi版
💻 HTML
📖 第 1 页 / 共 4 页
字号:
</div>
<BLOCKQUOTE>
This example shows how to detect a Java exception. The code purposely attempts to invoke a non-existent method on a 
Java object, called <tt>nonexistent</tt>. This causes a run-time exception that is detected within the Delphi code.
<pre class="sourcecode"><code><font color="#003399"><i>(****************************************************************************
 *  Java declaration:
 *     native public void handleException();
 *
 *  Causes an exception in the JVM, but detects it and supresses it
 *
 *  Class:     Native
 *  Method:    handleException
 *  Signature: ()V
 *)</i></font>
<b>procedure</b> Java_Native_handleException(PEnv: PJNIEnv; Obj: JObject); <b>stdcall</b>;
<b>var</b>
  Cls: JClass;
  AException: JThrowable;
  JVM: TJNIEnv;
<b>begin</b>
  JVM := TJNIEnv.Create(PEnv);

    <font color="#003399"><i>// Get the class to which this object belongs</i></font>
  Cls := JVM.GetObjectClass(Obj);

    <font color="#003399"><i>// Attempt to get the ID of the 'nonexistent' member, which, not by</i></font>
    <font color="#003399"><i>// chance, doesn't exist!</i></font>
  JVM.GetFieldID(Cls, <font color="#9933CC">'nonexistent'</font>, <font color="#9933CC">'Ljava/lang/String;'</font>);

    <font color="#003399"><i>// Check for exception</i></font>
  AException := JVM.ExceptionOccurred;

    <font color="#003399"><i>// exception is non-zero if an exception occurred</i></font>
  <b>if</b> (AException &lt;&gt; <b>nil</b>) <b>then</b> <b>begin</b>

    <font color="#003399"><i>//WriteLn('Exception occurred in Native code and was handled. This was the exception:');</i></font>
    Writeln(Format(<font color="#9933CC">'Exception handled in Main.cpp: %d'</font>, [DWORD(AException)]));

      <font color="#003399"><i>// This call will print out a description of the exception</i></font>
    <font color="#003399"><i>//JVM.ExceptionDescribe;</i></font>

      <font color="#003399"><i>// Clear the exception so the JVM doesn't react to it after we handled it</i></font>
    JVM.ExceptionClear;

  <b>end</b>;

  JVM.Free;
<b>end</b>;
</code></pre>
<hr width=30%>
<b>Notes:</b>
<ul>
<li>You can't use the traditional <tt><b>try..except</b></tt> syntax. You must explicitly check for any exceptions by
calling the <tt>ExceptionOccurred</tt> function of the JNI. In most places throughout this code, I have neglected to
do this. This was to prevent the code from being overwhelmed with exception checks, which would have detracted from
the main focus of each example. However, in <i>real</i> code, you should check for exceptions like the code above.
<li>If you want to print out the exception error message above, simply remove the comment from the line:
<pre>
    JVM.ExceptionDescribe;
</pre>
<li>Be sure to call <tt>ExceptionClear</tt> after handling an exception. This will prevent the exception from being
thrown again within the JVM upon returning from the function.
</ul>
<p>
<a href="#Top">Back to top</a>
</BLOCKQUOTE>





<div class="SectionHeader">
<A NAME="Concept10">Concept #10 - Causing Java Exceptions within Delphi</A>
</div>
<BLOCKQUOTE>
<pre class="sourcecode"><code><font color="#003399"><i>(****************************************************************************
 *  Java declaration:
 *     native public void causeException();
 *
 *  Causes an exception in the JVM, but fails to catch it. Thus, it is
 *  propagated back to the JVM.
 *
 *  Class:     Native
 *  Method:    causeException
 *  Signature: ()V
 *)</i></font>
<b>procedure</b> Java_Native_causeException(PEnv: PJNIEnv; Obj: JObject); <b>stdcall</b>;
<b>var</b>
  Cls: JClass;
  JVM: TJNIEnv;
<b>begin</b>
  JVM := TJNIEnv.Create(PEnv);

    <font color="#003399"><i>// Get the class to which this object belongs</i></font>
  Cls := JVM.GetObjectClass(Obj);

    <font color="#003399"><i>// Attempt to get the ID of the 'nonexistent' member, which, not by</i></font>
    <font color="#003399"><i>// chance, doesn't exist!</i></font>
  JVM.GetFieldID(Cls, <font color="#9933CC">'nonexistent'</font>, <font color="#9933CC">'Ljava/lang/String;'</font>);

    <font color="#003399"><i>// An exception has occurred, but it has not been suppressed.</i></font>
    <font color="#003399"><i>// The JVM will detect it and catch it.</i></font>
    <font color="#003399"><i>// Because we don't call this: JVM.ExceptionClear,</i></font>
    <font color="#003399"><i>// the JVM will react.</i></font>

  JVM.Free;
<b>end</b>;
</code></pre>
<p>
<a href="#Top">Back to top</a>
</BLOCKQUOTE>




<div class="SectionHeader">
<A NAME="TJNIEnv">TJNIEnv: The Wrapper Class</A>
</div>
<BLOCKQUOTE>
<tt><b>TJNIEnv</b></tt> is a <i>thin</i> wrapper around the JNI API, allowing it to look and feel a little object
oriented. It's called a <i>thin</i> wrapper because it doesn't really hide a lot of the underlying data and functions.
It's only a slight convenience. More importantly, however, is that it is more consistent with the way OO languages,
such as Delphi, are coded. Many APIs are simply sets of global functions that operate on the data you provide. The same
is true for the Java Native Interface API.
<p>
To get an idea of what the Delphi code would look like without using <tt>TJNIEnv</tt>, look at the <tt>printWXYZ</tt> 
method below. This is a modified version of the method used to describe <a href="#Concept8">Concept #8</a> above.
<pre class="sourcecode"><code><b>procedure</b> Java_Native_printWXYZ(PEnv: PJNIEnv; Obj: JObject); <b>stdcall</b>;
<b>var</b>
  X, Y, Z: JInt;
  W: JString;
  FID: JFieldID;
  Cls: JClass;
  Str: <b>string</b>;
  IsCopy: JBoolean;  <font color="#003399"><i>// added for GetStringChars</i></font>
  Chars: PJChar;     <font color="#003399"><i>// added for GetStringChars</i></font>
<b>begin</b>
    <font color="#003399"><i>// Get the class associated with this object</i></font>
  Cls := PEnv^.GetObjectClass(PEnv, Obj);

    <font color="#003399"><i>// w is a String</i></font>
  FID := PEnv^.GetFieldID(PEnv, Cls, <font color="#9933CC">'w'</font>, <font color="#9933CC">'Ljava/lang/String;'</font>);

    <font color="#003399"><i>// Get the Object (String) w.</i></font>
  W := PEnv^.GetObjectField(PEnv, Obj, FID);

    <font color="#003399"><i>// x is a non-static public field</i></font>
  FID := PEnv^.GetFieldID(PEnv, Cls, <font color="#9933CC">'x'</font>, <font color="#9933CC">'I'</font>);

    <font color="#003399"><i>// Get the int</i></font>
  X := PEnv^.GetIntField(PEnv, Obj, FID);

    <font color="#003399"><i>// y is a non-static private field, same as public here</i></font>
  FID := PEnv^.GetFieldID(PEnv, Cls, <font color="#9933CC">'y'</font>, <font color="#9933CC">'I'</font>);

    <font color="#003399"><i>// Get the int</i></font>
  Y := PEnv^.GetIntField(PEnv, Obj, FID);

    <font color="#003399"><i>// z is a _static_ public field, so call different method</i></font>
  FID := PEnv^.GetStaticFieldID(PEnv, Cls, <font color="#9933CC">'z'</font>, <font color="#9933CC">'I'</font>);

    <font color="#003399"><i>// Get static int</i></font>
  Z := PEnv^.GetStaticIntField(PEnv, Cls, FID);

    <font color="#003399"><i>// Convert Java string into Delphi string</i></font>
  Chars := PEnv^.GetStringChars(PEnv, W, IsCopy);
  Str := <b>string</b>(Chars);
  PEnv^.ReleaseStringChars(PEnv, W, Chars);

    <font color="#003399"><i>// Sort of like the traditional 'toString' output</i></font>
  WriteLn(Format(<font color="#9933CC">'[w = %s, x = %d, y = %d, z = %d]'</font>, [Str, X, Y, Z]));
<b>end</b>;
</code></pre>
There are a few changes that stand out:
<ul>
<li>There is no <tt>TJNIEnv</tt> object (called <tt>JVM</tt> in all of the examples.) This is simply because we aren't 
using the wrapped version. Instead, we call each API function through the <tt>PJNIEnv</tt> parameter that 
was passed into our method, for example:
<pre>
  Cls := JVM.GetObjectClass(Obj);
</pre>
becomes:
<pre>
  Cls := PEnv^.GetObjectClass(PEnv, Obj);
</pre>
<li>The PJNIEnv parameter that was passed into the method is passed as the first parameter to every API function. When we
instantiated a <tt>TJNIEnv</tt> object, we passed a <tt>JNIEnv</tt> pointer (<tt>PJNIENV</tt>) to the constructor:
<pre>
  JVM := TJNIEnv.Create(PEnv);
</pre>
This pointer is stored in the class and is passed to each API method on behalf of the client. So, this call by the client
<pre>
  Cls := JVM.GetObjectClass(Obj);
</pre>
calls this function in the <tt>TJNIEnv</tt> class:
<pre>
  <b>function</b> TJNIEnv.GetObjectClass(Obj: JObject): JClass;
  <b>begin</b>
    Result := Env^.GetObjectClass(Env, Obj);
  <b>end</b>;
</pre>
<tt>Env</tt> is the <tt>TJNIEnv</tt> pointer that was passed into the <tt>TJNIEnv</tt> constructor above.
<p>
<li>Converting the Java string to a Delphi string requires the user to call JNI API functions. The <tt>TJNIEnv</tt> class
hides this from the user by providing a <tt>JStringToString</tt> function so this (<tt>W</tt> is the Java string):
<pre>
  Chars := PEnv^.GetStringChars(PEnv, W, IsCopy);
  Str := <b>string</b>(Chars);
  PEnv^.ReleaseStringChars(PEnv, W, Chars);
</pre>
becomes this:
<pre>
  Str := JVM.JStringToString(W);
</pre>
</ul>
<p>
One thing you may be saying to yourself is <i>"I don't see the great benefit of using wrappers around the API"</i> For the 
<tt>TJNIEnv</tt> class, I would partially agree. There seems to be almost a one-to-one correspondence between the code you
write <i>with</i> the wrapper class compared to the code you write <i>without</i> it. But don't forget that a major factor in
using classes is to be consistent with Delphi's programming style. Also, this allows the TJNIEnv class to be extended 
at a later time to provide more functionality than it does now. 
<p>
In <a href="delphi-jni-3.html">Part Three</a> of 
<i>Using the Java Native Interface with Delphi</i> you will see another wrapper class called <tt>TJavaVM</tt> which is
not merely a thin layer, but a full-blown OO interface to the Invocation API of the JNI. Among other things, this class handles
loading and unloading of DLLs at the appropriate times, relieving the programmer of this burden.
<p>
<a href="#Top">Back to top</a>
</BLOCKQUOTE>






<div class="SectionHeader">
<A NAME="Summary">Summary</A>
</div>
<BLOCKQUOTE>
Part Two of <i>Using the Java Native Interface with Delphi</i> shows by example how to perform many of the common tasks necessary
when using the JNI. These tasks are not specific to Delphi, but are required by any language that desires to
interface with Java using the JNI. These examples show, from a Delphi perspective using Delphi code, how to interact
with Java at runtime. After reading this document, you should have a good foundation to further explore Delphi and the Java
Native Interface.
<p>
<a href="delphi-jni-3.html">Part Three</a> introduces you to the Invocation API, which is the term given to a subset of
the JNI that deals with embedding the Java Virtual Machine into another program. In our case, this other program will
be a Delphi program.
<p>
<a href="zips/native.zip">Download</a> the files used in this document.
<br>
<a href="delphi-jni-1.html">Using the Java Native Interface with Delphi (Part One)</a>
<br>
<a href="delphi-jni-3.html">Using the Java Native Interface with Delphi (Part Three)</a>
<br>
<a href="delphi-jni-1.html#Resources">Helpful resources</a> (from Part One.)
<p>
<a href="#Top">Back to top</a>
</BLOCKQUOTE>

<hr>
<center>Copyright &copy 2001 <a href="mailto:jni@matthewmead.com">Matthew Mead</a> All Rights Reserved.</center>
<a href="http://www.delphi-jedi.org"><img src="gifs/btn_jedinow.gif" width="116" height="31"></a>
<br><br>

</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -