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

📄 appa.htm

📁 一本Java由初级到高级的编程书籍
💻 HTM
📖 第 1 页 / 共 5 页
字号:
API(函数、常数和数据类型)都映射成Java类。但幸运的是,根本不必这样做。<br>
<br>
A.3.2 com.ms.win32包<br>
Win32 API的体积相当庞大——包含了数以千计的函数、常数以及数据类型。当然,我们并不想将每个Win32 
API函数都写成对应Java形式。微软考虑到了这个问题,发行了一个Java包,可通过J/Direct将Win32 
API映射成Java类。这个包的名字叫作com.ms.win32。安装Java SDK 2.0时,若在安装选项中进行了相应的设置,这个包就会安装到我们的类路径中。这个包由大量Java类构成,它们完整再现了Win32 
API的常数、数据类型以及函数。包容能力最大的三个类是User32.class,Kernel.class以及Gdi32.class。它们包含的是Win32 
API的核心内容。为使用它们,只需在自己的Java代码里导入即可。前面的ShowMsgBox示例可用com.ms.win32改写成下面这个样子(这里也考虑到了用更恰当的方式使用UnsatisfiedLinkError):<br>
<br>
1012页程序<br>
<br>
Java包是在第一行导入的。现在,可在不进行其他声明的前提下调用MessageBeep()和MessageBox()函数。在MessageBeep()里,我们可看到包导入时也声明了Win32常数。这些常数是在大量Java接口里定义的,全部命名为winx(x代表欲使用之常数的首字母)。<br>
写作本书时,com.ms.win32包的开发仍未正式完成,但已可堪使用。<br>
<br>
A.3.3 汇集<br>
“汇集”(Marshaling)是指将一个函数自变量从它原始的二进制形式转换成与语言无关的某种形式,再将这种通用形式转换成适合调用函数采用的二进制格式。在前面的例子中,我们调用了MessageBox()函数,并向它传递了两个字串。MessageBox()是个C函数,而且Java字串的二进制布局与C字串并不相同。但尽管如此,自变量仍获得了正确的传递。这是由于在调用C代码前,J/Direct已帮我们考虑到了将Java字串转换成C字串的问题。这种情况适合所有标准的Java类型。下面这张表格总结了简单数据类型的默认对应关系:<br>
<br>
Java C<br>
<br>
byte BYTE或CHAR<br>
short SHORT或WORD<br>
int INT,UINT,LONG,ULONG或DWORD<br>
char TCHAR<br>
long __int64<br>
float Float<br>
double Double<br>
boolean BOOL<br>
String LPCTSTR(只允许在OLE模式中作为返回值)<br>
byte[] BYTE *<br>
short[] WORD *<br>
char[] TCHAR *<br>
int[] DWORD *<br>
<br>
这个列表还可继续下去,但已很能说明问题了。大多数情况下,我们不必关心与简单数据类型之间的转换问题。但一旦必须传递用户自定义类型的自变量,情况就立即变得不同了。例如,可能需要传递一个结构化的、用户自定义的数据类型,或者需要把一个指针传给原始内存区域。在这些情况下,有一些特殊的编译引导命令标记一个Java类,使其能作为一个指针传给结构(@dll.struct引导命令)。欲知使用这些关键字的细节,请参考产品文档。<br>
<br>
A.3.4 编写回调函数<br>
有些Win32 API函数要求将一个函数指针作为自己的参数使用。Windows API函数随后就可以调用自变量函数(通常是在以后发生特定的事件时)。这一技术就叫作“回调函数”。回调函数的例子包括窗口进程以及我们在打印过程中设置的回调(为后台打印程序提供回调函数的地址,使其能更新状态,并在必要的时候中止打印)。<br>
另一个例子是API函数EnumWindows(),它能枚举目前系统内所有顶级窗口。EnumWindows()要求获取一个函数指针作为自己的参数,然后搜索由Windows内部维护的一个列表。对于列表内的每个窗口,它都会调用回调函数,将窗口句柄作为一个自变量传给回调。<br>
为了在Java里达到同样的目的,必须使用com.ms.dll包里的Callback类。我们从Callback里继承,并取消callback()。这个方法只能接近int参数,并会返回int或void。方法签名和具体的实施取决于使用这个回调的Windows 
API函数。<br>
现在,我们要进行的全部工作就是创建这个Callback衍生类的一个实例,并将其作为函数指针传递给API函数。随后,J/Direct会帮助我们自动完成剩余的工作。<br>
下面这个例子调用了Win32 API函数EnumWindows();EnumWindowsProc类里的callback()方法会获取每个顶级窗口的句柄,获取标题文字,并将其打印到控制台窗口。<br>
<br>
1014页程序<br>
<br>
对sleep()的调用允许窗口进程在main()退出前完成。<br>
<br>
A.3.5 其他J/Direct特性<br>
通过@dll.import引导命令内的修改符(标记),还可用到J/Direct的另两项特性。第一项是对OLE函数的简化访问,第二项是选择API函数的ANSI及Unicode版本。<br>
根据约定,所有OLE函数都会返回类型为HRESULT的一个值,它是由COM定义的一个结构化整数值。若在COM那一级编写程序,并希望从一个OLE函数里返回某些不同的东西,就必须将一个特殊的指针传递给它——该指针指向函数即将在其中填充数据的那个内存区域。但在Java中,我们没有指针可用;此外,这种方法并不简练。利用J/Direct,我们可在@dll.import引导命令里使用ole修改符,从而方便地调用OLE函数。标记为ole函数的一个固有方法会从Java形式的方法签名(通过它决定返回类型)自动转换成COM形式的函数。<br>
第二项特性是选择ANSI或者Unicode字串控制方法。对字串进行控制的大多数Win32 
API函数都提供了两个版本。例如,假设我们观察由USER32.DLL导出的符号,那么不会找到一个MessageBox()函数,相反会看到MessageBoxA()和MessageBoxW()函数——分别是该函数的ANSI和Unicode版本。如果在@dll.import引导命令里不规定想调用哪个版本,JVM就会试着自行判断。但这一操作会在程序执行时花费较长的时间。所以,我们一般可用ansi,unicode或auto修改符硬性规定。<br>
欲了解这些特性更详细的情况,请参考微软公司提供的技术文档。<br>
<br>
A.4 本原接口(RNI)<br>
同J/Direct相比,RNI是一种比非Java代码复杂得多的接口;但它的功能也十分强大。RNI比J/Direct更接近于JVM,这也使我们能写出更有效的代码,能处理固有方法中的Java对象,而且能实现与JVM内部运行机制更紧密的集成。<br>
RNI在概念上类似Sun公司的JNI。考虑到这个原因,而且由于该产品尚未正式完工,所以我只在这里指出它们之间的主要差异。欲了解更详细的情况,请参考微软公司的文档。<br>
JNI和RNI之间存在几方面引人注目的差异。下面列出的是由msjavah生成的C头文件(微软提供的msjavah在功能上相当于Sun的javah),应用于前面在JNI例子里使用的Java类文件ShowMsgBox。<br>
<br>
1016页程序<br>
<br>
除可读性较差外,代码里还隐藏着一些技术性问题,待我一一道来。<br>
在RNI中,固有方法的程序员知道对象的二进制布局。这样便允许我们直接访问自己希望的信息;我们不必象在JNI里那样获得一个字段或方法标识符。但由于并非所有虚拟机都需要将相同的二进制布局应用于自己的对象,所以上面的固有方法只能在Microsoft 
JVM下运行。<br>
在JNI中,通过JNIEnv自变量可访问大量函数,以便同JVM打交道。在RNI中,用于控制JVM运作的函数变成了可直接调用。它们中的某一些(如控制异常的那一个)类似于它们的JNI“兄弟”。但大多数RNI函数都有与JNI中不同的名字和用途。<br>
JNI和RNI最重大的一个区别是“垃圾收集”的模型。在JNI中,垃圾收集在固有方法执行期间遵守与Java代码执行时相同的规则。而在RNI中,要由程序员在固有方法活动期间自行负责“垃圾收集器”器的启动与中止。默认情况下,垃圾收集器在进入固有方法前处于不活动状态;这样一来,程序员就可假定准备使用的对象用不着在那个时间段内进行垃圾收集。然而一旦固有方法准备长时间执行,程序员就应考虑激活垃圾收集器——通过调用GCEnable()这个RNI函数(GC是“Garbage 
Collector”的缩写,即“垃圾收集”)。<br>
也存在与全局句柄特性类似的机制——程序员可利用可保证特定的对象在GC活动期间不至于被当作“垃圾”收掉。概念是类似的,但名称有所差异——在RNI中,人们把它叫作GCFrames。<br>
<br>
A.4.1 RNI总结<br>
RNI与Microsoft JVM紧密集成这一事实既是它的优点,也是它的缺点。RNI比JNI复杂得多,但它也为我们提供了对JVM内部活动的高度控制;其中包括垃圾收集。此外,它显然针对速度进行了优化,采纳了C程序员熟悉的一些折衷方案和技术。但除了微软的JVM之外,它并不适于其他JVM。<br>
<br>
A.5 Java/COM集成<br>
COM(以前称为OLE)代表微软公司的“组件对象模型”(Component Object 
Model),它是所有ActiveX技术(包括ActiveX控件、Automation以及ActiveX文档)的基础。但COM还包含了更多的东西。它是一种特殊的规范,按照它开发出来的组件对象可通过操作系统的专门特性实现“相互操作”。在实际应用中,为Win32系统开发的所有新软件都与COM有着一定的关系——操作系统通过COM对象揭示出自己的一些特性。由其他厂商开发的组件也可以建立在COM的基础上,我们能创建和注册自己的COM组件。通过这样或那样的形式,如果我们想编写Win32代码,那么必须和COM打交道。在这里,我们将仅仅重述COM编程的基本概念,而且假定读者已掌握了COM服务器(能为COM客户提供服务的任何COM对象)以及COM客户(能从COM服务器那里申请服务的一个COM对象)的概念。本节将尽可能地使叙述变得简单。工具实际的功能要强大得多,而且我们可通过更高级的途径来使用它们。但这也要求对COM有着更深刻的认识,那已经超出了本附录的范围。如果您对这个功能强大、但与不同平台有关的特性感兴趣,应该研究COM和微软公司的文档资料,仔细阅读有关Java/COM集成的那部分内容。如果想获得更多的资料,向您推荐Dale 
Rogerson编著的《Inside COM》,该书由Microsoft Press于1997年出版。<br>
由于COM是所有新型Win32应用程序的结构核心,所以通过Java代码使用(或揭示)COM服务的能力就显得尤为重要。Java/COM集成无疑是Microsoft 
Java编译器以及虚拟机最有趣的特性。Java和COM在它们的模型上是如此相似,所以这个集成在概念上是相当直观的,而且在技术上也能轻松实现无缝结合——为访问COM,几乎不需要编写任何特殊的代码。大多数技术细节都是由编译器和/或虚拟机控制的。最终的结果便是Java程序员可象对待原始Java对象那样对待COM对象。而且COM客户可象使用其他COM服务器那样使用由Java实现的COM服务器。在这里提醒大家,尽管我使用的是通用术语“COM”,但根据扩展,完全可用Java实现一个ActiveX 
Automation服务器,亦可在Java程序中使用一个ActiveX控件。<br>
Java和COM最引人注目的相似之处就是COM接口与Java的“interface”关键字的关系。这是接近完美的一种相符,因为:<br>
■COM对象揭示出了接口(也只有接口)<br>
■COM接口本身并不具备实施方案;要由揭示出接口的那个COM对象负责它的实施<br>
■COM接口是对语义上相关的一组函数的说明;不会揭示出任何数据<br>
■COM类将COM接口组合到了一起。Java类可实现任意数量的Java接口。<br>

⌨️ 快捷键说明

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