用标准C编写COM(二)COM in plain C,Part2
原文:http://www.codeproject.com/Articles/13862/COM-in-plain-C-Part-2
如何用C编写可以被Vbscript、VB和jscipt等脚本语言调用的COM组件
下载例程-93.5kb
内容:
简介 为何脚本语言不能使用我们的DLL? 自动化数据类型(也就是BSTR、VARIANT) IDispatch接口函数 类型库 注册类型库 VBScript例程 属性 更新后的C例程 包含在EXE中的COM组件简介
在本系列的第一部分中,我们用标准C创建了一个COM组件,把它封装在一个动态库中,同时学习了怎样去注册和用C或者C++调用它。我们还创建了一个包含我们的GUID和对象VTable(函数)定义的头文件(IExample.h)。通过包含这个.H文件, C/C++应用程序可以知道我们对象VTable的成员(调用我们函数)、参数和返回值及对象的GUID和VTable。
尽管这些对一个C/C++程序的支持已经足够了,我们必须(给我们的IExample DLL)增加功能以支持解释性“脚本”语言,比如说Visual Basic、VBScript、Jscript和Python等。这篇文章的焦点就是如何添加这方面的支持。在我们增加了这个支持后,我们将写一个VBScript例子来使用更新后的IExample组件。
不是所有的语言都能识别我们的C/C++包含文件和获取其中的信息,例如Visual Basic、Python等。这些应用程序不知道我们对象中的函数、函数传递参数和返回值及我们的GUID。大多数的语言不支持从C/C++包含文件中获取信息。我们需要一种方法,用一个中立的语言格式来指定IExample.h中的所有信息,比较合适的约定好的“二进制”格式,而不像IExample.h。就像我们要看到的一样,我们通过创建一种叫类型库的来实现这一点。
为了使脚本引擎读取我们类型库更容易和标准化,我们将添加一些被命名为IDispatch接口的函数给我们的对象。脚本引擎只通过这些IDispatch函数来获得类型库。由于脚本引擎不直接存取我们的类型库,这意味着如果微软开发一个后期版本的类型库,这些杂乱的版本细节对于脚本引擎是隐藏的。
另一个麻烦事就是数据类型。考虑到一个ANSI C的字符串。一个C字符串是一个以0结尾的八位的字节串。但是在Pascal中字符串不是这样存储的。一个Pascal字符串是以一个表明后面有多少字节数的字开始。换句话说,一个Pascal字符串以一个长度字节开始,接下来是这个字符串内容,没有0这个结束符。还有UNICODE和ANSI之分,对于UNICODE,字符串中的每个字符占两个字节(也就是说是一个short类型)。Visual Basic字符串使用UNICODE而不是ANSI C。
我们需要处理如何解析这些数据类型的问题。我们需要找出一套可以工作在使用我们对象的所有语言上的“通用数据类型”,同时只能使用这些数据类型作为我们对象函数的参数(包括我们函数的返回值)。
自动化数据类型
为了支持多种语言(以及每种语言扩展,比如UNICODE),微软已经定义了一种通用的数据类型给COM对象使用。微软叫他们“自动化数据类型”。(以后,我们将看到自动化这个名字是从哪而来。)其中的一个自动化数据类型是BSTR。BSTR是什么?它是一个特殊格式的字符串指针。每个字符占两个字节(也就是说是一个short类型),并且它以一个表明接着有多少short类型数据的unsiged long作为前缀,它以一个short类型的0结束。它几乎可以适应每种语言中的字符串数据类型。但是它也意味着,一个C/C++应用程序或者我们的C对象本身有时也需要转换一个C字符串为一个以NULL结束的带长度前缀的UNICODE字符串。
为了说明,让我们看一下下面的ANSI C 字符串:
#include "../IExampleExe/IExampleExe.h"
记住你必须安装、注册我们COM组件一次,然后在你运行修改后的IExample2App.exe测试程序前运行我们组件(IExample.exe)来把它加入COM任务列表中。
接下来是什么?
在下一个章节中,我们要从一个脚本引擎的观点来看IDispatch函数。脚本引擎是如何把代码翻译成它自己的语言,如何调用我们对象的IDisaptch函数?