首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

用基准C编写COM(七)COM in plain C,Part7

2012-11-26 
用标准C编写COM(七)COM in plain C,Part7原文:http://www.codeproject.com/Articles/15037/COM-in-plain-C

用标准C编写COM(七)COM in plain C,Part7

原文:http://www.codeproject.com/Articles/15037/COM-in-plain-C-Part-7

拥有自定义COM对象的ActiveX脚本宿主允许在你的应用程序中调用C函数。 

下载例程- 380 Kb

内容

    简介    声明自定义对象    我们的IDL文件和类型库    向引擎注册我们的COM对象    脚本如何调用我们COM对象的函数    我们的IProvideMultipleClassInfo对象    应用程序和文档对象    C++宿主例程

简介

 

在前一章中,我们学习了如何让我们应用程序运行一段脚本。但为了让脚本能调用我们应用程序中的C函数,最终与我们的应用程序交换数据,我们需要给我们的应用程序添加另一个自定义COM对象。我们的C函数(脚本调用的)会封装在这个COM对象中。你可以返回第二章,为了让脚本调用我们COM对象中的函数,我们需要给它添加一个IDispatch标准函数(也有IUnkown标准函数)。

 

一句话,我们要做的是创建一个就像我们在第二章中那样的我们自定义COM对象。我们定义它包含IUnkown函数,后面是IDipatch函数,接着是我们想让脚本调用的额外函数。为了创建一个类型库(让脚本可以看到我们额外函数名、传递的参数和返回值)我们还得写一个.IDL文件。我们做的是像我们在第二章中做的那样创建我们自定义、脚本可识别的对象。


声明我们的自定义COM对象

 

我们可以给我们自定义COM对象起我们喜欢的名字。我们随便叫它IApp。

 

我们给脚本提供三个可调用的函数,Output、SetTitle和GetTitle。Output函数在我们主窗口的EDIT空间中显示一行文本。我们使用另一个自定义窗口消息(WM_APP+1)通过PostMessage传递这行给我们主窗口进程来显示,就像我们在我们的IActiveScriptSite的OnHandleError函数那样。SetTitle函数会改变在我们主窗口的标题栏中的文本。而GetTitle函数是回去标题栏文本。我们把这三个函数放到我们的IApp对象中,在IUnknown和IDispatch函数之后。

 

在ScriptHost4目录中是我们添加了这个IApp对象的ScriptHost版本。AppObject.c源文件包含了大部分新代码。

 

我们需要给我们的IApp对象一个唯一的GUID,因此我运行GUIDGEN.EXE创建了一个,给它命名为CLSID_IApp。我们还需要给IApp的VTable一个GUID,所以我创建另一个GUID,命名为IDD_IApp。我把这两个GUID放在了Guids.c和Guids.h源文件中。

 

像第二章那样,我们用一个特殊的宏来申明我们的IApp对象的VTable(和对象本身)。这是定义:

   SET doc = application.GetDocument("test.txt")

在ScriptHost5目录中是一个不完善的文本阅读器。它只是一个可以打开几个文本文件阅读的MDI应用程序;每个文件在它的自己的窗口中。我们的IApp对象有一个叫CreateDocument的额外函数。它接受一个要加载的文本文件的BSTR文件名。它创建一个新的MDI子窗口,并且在窗口中加载、显示文本文件。(事实上,我们只创建一个空文档)。CreateDocument还为这个窗口创建一个新的IDocument对象,把它返回给脚本。

 

我们的IDocument对象包含一个叫WriteText的函数。它接受一个BSTR格式的文本,同时这个文本替换窗口中的其他文本。

 

在ScriptHost5目录中有一个名为test.vbs的VBScript。它只调用我们我们的IApp的CreateDocument两次来创建两个IDocument对象,他们叫“Document 1”和“Document 2”。它调用每个IDocument的WriteText函数。对于“Document 1”,它设置文本为“This is document 1.”。对于“Document 2”,它设置文本为“This is document 2.”。

 

注意为了简单,ScriptHost5强行加载和运行test.vbs。

 

对于这个例程,你会注意到我们的IApp对象如何控制我们的阅读器所有操作,而IDocument控制每个单独的文档。注意我们向ScriptHost.idl中添加两个自定义对象(同时注意两个都是双VTable,因此我们用标准COM函数来做IDispatch的大部分工作)。还的注意在我们的IDL中我们需要另一个GUID给IDocument的VTable。但我们没在IDL文件中定义IDocument对象本身。我们不需要因为脚本从不通过CoCreateInstance创建他们,但会间接获取我们应用程序自己创建的一个IDocument。


C++宿主例程

 

在ScriptHost6目录中是一个ScriptHost5的C++版本。你会注意到在AppObject.h中我们定义我们的MyRealIApp和MyRealIDocument类继承于我们IApp和IDocument。这些COM函数成为他们各自类的成员。注意,尽管在C例程中我们的MyRealApp的函数接受一个指向MyRealApp的指针作为第一个参数,但在C++版本中这被忽略。因为它变成了隐藏的“this”指针。同时我们不需要去声明和初始化任何VTable的指针。C++编译器为我们做这一切。

 

此外,无论我们什么时候调用COM函数,我们忽略->lpVtbl,同时不用传一个指向这个对象的指针作为第一个参数。

 

在IActiveScriptSite.h中,我们也要把MyRealIActiveScriptSite声明为继承于IActiveScriptSite和IActiveScriptSiteWindow的类。注意我们不再需要为每个子对象提供单独的QueryInterface、AddRef和Release。我们只要声明基对象的QueryInterface、AddRef和Release,然后C++编译器会自动为其他子对象生成这些函数的正确的委托(delegation)。

热点排行