COM笔记 (1)SAMPLE: MFCAxs.exe Implements an Active Script Host Using MFC 用MFC实现script引擎host

SAMPLE: MFCAxs.exe Implements an Active Script Host Using MFC

Retired KB ArticleRetired KB Content Disclaimer

View products that this article applies to.

This article was previously published under Q168214

On This Page

·         SUMMARY

·         MORE INFORMATION

o        Running the Sample

o        Exposing the Host: Dispatch Objects

o        Named Items

o        Getting to Other Apps: HostCreateObject

o        Class Wizard Support

o        Appendix A: Object Model

Expand all | Collapse all

SUMMARY

MFCAxs.exe is a sample that contains MfcAxscrVb. MfcAxscrVb is an instructional...

MFCAxs.exe is a sample that contains MfcAxscrVb. MfcAxscrVb is an instructional sample Active Scripting host written using MFC. It hosts the VBScript DLL; however, the Active Scripting mechanisms are generic to any Active Scripting engine. MfcAxscrVb shows just one possible way to provide dispatch objects from the host, to implement the host's Active Scripting interfaces, and to connect the messages of windows in the host with events fired to the scripting engine.

MfcAxscrVb
实现了vbscripthost功能,通过提供IDispatch接口的object实现script接口。使用events实现消息通信。

MfcAxscrVb includes a Visual C++ 5.0 workspace and project file. Although no VC++ 4.2 compatible makefile or mdpfile is provided, the source code for MfcAxscrVb is compatible with MFC 4.2b.

Prerequisites: COM, Automation

Back to the top

MORE INFORMATION

The following file is available for download from the Microsoft Download Center:...

The following file is available for download from the Microsoft

程序及源代码可以在这里下载:(注:用vc2005编译的话会有几个小错误,不过很好改)

Download Center:

MFCAxs.exe (http://download.microsoft.com/download/vc50pro/mfcaxs/1/win98/en-us/mfcaxs.exe)

For additional information about how to download Microsoft Support files, click the following article number to view the article in the Microsoft Knowledge Base:

119591  (http://support.microsoft.com/kb/119591/EN-US/ ) How to Obtain Microsoft Support Files from Online Services

Microsoft scanned this file for viruses. Microsoft used the most current virus-detection software that was available on the date that the file was posted. The file is stored on security-enhanced servers that help to prevent any unauthorized changes to the file.

Back to the top

Running the Sample

When you run the MfcAxscrVb sample you will notice a large edit control in the upper left-hand corner of the application. You can paste or type script into this window and select the "Run Script" button to invoke the script. Several test scripts are provided for you in the Script.txt and Testevents.txt files.

运行该程序,在左上角的文本框内可以输入vbscript语句,并按RunScript按钮执行。在Script.txt Testevents.txt文件里有一些例子

Back to the top

Exposing the Host: Dispatch Objects

The main focus for this sample is the implementation of dispatch objects using MFC. The reason for this is simple. A scripting language isn't much use if there isn't anything to script.

本文的目的是介绍用MFC实现dispatch对象方法。


The core technology upon which all Active Scripting depends is most certainly that of Automation. A solid working knowledge of Automation is absolutely necessary before attempting to code any Active Scripting host. There are several good references for Automation: chapters 14 and 15 of Brockshmidt's "Inside OLE," chapter 11 of Dale Rogerson's "Inside COM," and the "OLE Automation Programmer's Reference."

实现的主要技术是automation。可以参考这些书:。。


CCmdTargetPlus:

What you need are some objects that allow for scriptable properties and methods through IDispatch but also generate scriptable events. MFC definitely does most of the grunt work for you when implementing dispatch interfaces for a COM object. However, the only MFC class that supports both incoming dispatch interfaces and outgoing dispatch interfaces, or event sinks, is COleControl. COleControl is much too bulky for what you want. You just want events, a dispatch interface, and type information. VBScript needs to read type information for dispatch objects that support events. You could either create this on the fly, or create a static type library for your host's dispatch objects and obtain the ITypeInfo for each individual object.

我们需要实现的是script语言可以用dispatch接口控制的属性,方法和事件。MFCColeControl支持输入和输出disptch接口,event sinks。但是对我们来说,这个类太大了。我们只需要events,dispatch接口,type信息。Vbscrip需要读入支持eventdispatch对象的type信息。


While probably not necessary, MfcAxscrVb has a base class called CCmdTargetPlus that supports these three pieces: dispatch interface, connection points with a control-style event map, and easily accessible type information through IProvideClassInfo. Most of the code in CmdTargetPlus was added to allow for event maps, which makes adding events to derived classes much easier.

这里有一个基类CcmdTargetPlus实现了三个功能:dispatch 接口, 连接点和事件map, 和通过IProvideClassInfo 实现的type 信息


Dispatch Objects:

All host-provided dispatch objects are implemented using CCmdTargetPlus. There are a few things they need to do to work well. Refer to any of the dispatch objects (CAButtonDispatch, CBButtonDispatch, and so forth) for a boilerplate on what is necessary. A brief rundown on MfcAxscrvb's object model is listed at the end of this document.

程序里提供的dispatch objects都是用CcmdTargetPlus实现的。需要注意(可以参考CAButtonDispatch, CBButtonDispatch..,本文末尾介绍了该程序实现的object


If you add your own objects, be sure to double-check for three unique GUIDs for the primary dispatch and primary events interfaces, and for the clsid for the object in sum. This needs to be done in the implementation file and in the .odl file. (Cut and Paste helps here.) Cut and paste all of the class wizard macros, and then change them to the new class name. Class Wizard is very particular, but if you follow everything just right in the .odl, .h, and .cpp files, you can use it to add new events, properties, and methods to your dispatch object as if it were an MFC OLE Control. This is sort of handy.

如果你想自己用CcmdTargetPlus添加object,需要注意:有三个唯一的GUID(dispatch, eventclsid),需要在cppodl文件里分别实现。


MfcAxscrVb keeps the object implementing the dispatch mechanisms separate from the MFC object, which it is actually referring to. For example, the dialog box has a button called the "AButton," which is scriptable. The MFC button object is CButton. The CCmdTargetPlus-derived class, CAButtonDispatch, is separate and distinct. This is a key point. Only what the host programmer explicitly chooses to expose for basic MFC objects and Windows controls will be scriptable.

本程序将dispatch机构的实现和mfc对象的实现分开为不同的类。比如有一个按钮对应Cbutton类,而该按钮对应的dispatchCAButtonDispatch类。

 

CEventsButton, CEventsEdit, CeventsListBox:

For events, there needs to be some code that responds to a Windows event-- say, a button click--and generates an event for the script engine. (Remember an event is a dispatch Invoke on an interface handled by connection points in the host object.) This sample accomplishes this by adding standard MFC message handlers into objects derived from the various classes. Each of these handlers merely has to call FireEvent (courtesy of the code added to CCmdTargetPlus) on the dispatch object. Everything else happens automatically.

对于event,需要用连接点实现。本文通过添加MFC消息的handler到类中实现此。每一个handler必须对dispatch的对象调用FireEvent。其他的都自动发生。


Because the dispatch object and the actual MFC window object are separate in this sample, the dialog parent needs to explicitly hook the two together. This is done in the Mfcaxscrvbdlg constructor.

 

由于dispatch对象和MFC对象的实现分开来了,dialog类的constructor中必须显式的将这两个连在一起

 

Back to the top

Named Items

Once you have dispatch objects, you have to set them up so that the script engine knows about them. The collection of all the named dispatch objects that the script engine knows about is called the "Script Namespace." Items are added to the script namespace through the IActiveScript::AddNamedItem method. As I mentioned previously, it is the host's duty to implement an IDispatch for the object and support type-information through ITypeInfo for the object. When the script engine needs to resolve a reference to a named item, it uses the IActiveScriptSite::GetItemInfo method to request an IUnknown pointer (which it queries mainly for IDispatch) and an ITypeInfo pointer.

你必须让script引擎知道你拥有的dispatch对象。你必须实现script名称空间,这通过IActiveScript::AddNamedItem实现。Host必须实现IdispatchItypeInfoScript引擎通过IActiveScriptSite::GetItemInfo得到某一项named itemIunknownITypeInfo指针。


Not everything that a host wants to be scriptable needs to be a named item. Usually the host will have a hierarchy of objects, where sub-objects are accessible through a higher-level object. A common metaphor is the Application->Document->Item hierarchy, where the Document object is accessible from the top-level Application object as an IDispatch property of the Application object itself. In the same manner, the Document object itself exposes several sub-objects and each is an Item that you can obtain through an Item array or other contrivance.

Using this scheme, the scripting engine is smart enough to navigate to a sub-item when the script code says the following without needing Document or Item to be added to the script namespace:

Set Obj = Application.Document.Item(1)

也可以不用named item实现,host可以有一系列树状的对象,底层的可以通过高层对象得到。比如Application->Document->Item。其中Document可以通过获取application对象的Application得到。用这种方法,script引擎可以遍历所有的item,比如Set Obj = Application.Document.Item(1)

 

As long as the sub-objects are exposed as get-properties of their parent object, the script engine finds them successfully. Interestingly enough, the script engine is able to "assume" the top-level item in the hierarchy. What this means is that if Application is declared as the top-level item, then it is sufficient to say the following for the prior script code:

Set Obj = Document.Item(1)
                              

 

This is exactly how Internet Explorer 3.0 allows you to script code in the context of the Window object without always prefixing all references to objects with "Window." A script host needs to identify the top-level script item in the call to AddNamedItems by using the SCRIPTITEM_GLOBALMEMBERS flag. What usually isn't made clear by Active Scripting documentation, however, is that only named items can support events. Using the above example, there is no syntax to say the following to handle an event in a particular item:

   Sub Application.Document.Item(1)_OnEvent ' this doesn't work!

这就是IE实现的功能。他的最顶层是Window,script host通过AddNamedItemsSCRIPTITEM_GLOBALMEMBERS)实现顶层的script item.但是只有named item支持event。这点需要注意。

       

So, for MfcAxscrvbdlg, because we want to be able to handle the events of every object in the hierarchy, every object is added as a Named Item. Each object is also accessible through the top-level Scripter object (the dialog itself), which does not support events currently.

对我们来说,想handle所有对象的event,因此必须都作为named item实现。并且都可以通过顶层对象(dialog本身,尚不支持event)得到。


WebBrowser Control:

In this sample, the script host exposes only one external object to the script namespace. This is the WebBrowser control hosted on the dialog by MFC's default control containment support. All you need is an AddRef'd dispatch pointer to the control, and you're set. For events, the external object needs to expose an ITypeInfo pointer somehow. MfcAxscrVb gets this through IProvideClassInfo::GetClassInfo. As a last resort, a host could read the object's type-information itself to expose an ITypeInfo. Fortunately, the WebBrowser control supports GetClassInfo, so MfcAxscrVb doesn't do this.

本例中,host只暴露了一个外部的对象给scriptnamespace,即WebBrowserHost通过AddRef'd得到dispatch接口,通过IprovideClassInfo ::

GetClassInfo得到ITypeInfo


If you wanted to add other external automation objects to the namespace, all that usually is necessary is to obtain an IUnknown interface using CoCreateInstance. Alternatively, the host can support a generic means for obtaining external objects, albeit ones that don't need to have events handled. In Visual Basic, the function to do this is called CreateObject.

 

如果你想加入新的外部对象,只需使用CoCreateInstance获得Iunknown接口。在vbhost提供的是createobject方法

 

Back to the top

Getting to Other Apps: HostCreateObject

Other than the set of properties used to expose all of the child objects, the main Scripter object (the dialog class itself) exposes only one special method. This method demonstrates a simple means for simulating VB's CreateObject function. Note that the method is named HostCreateObject to emphasize that this method is not provided for free by the script engine, but the host must implement it itself. Some hosts clearly would not want to provide this ability for security reasons, IE3 is a prime example. The primary goal of HostCreateObject is to return the dispatch pointer of the requested object. Once the scripting engine has the dispatch pointer, it knows what to do from there.

HostCreateObject的目的是返回要求的对象的dispatch指针


NOTE: As of version 2.0, the VBScript and JScript engines now support CreateObject as a built-in function. The host does not need to implement this function. This function will, however, test an object to make sure it is safe for scripting before allowing the object to be used. Objects deem themselves safe for scripting by either supporting the IObjectSafety interface or marking the appropriate Component Category registry entries for Safe-For-Scripting. Refer to the Microsoft Knowledge Base for more information.

 

注:vbscript本身已经支持CreateObject

Back to the top

Class Wizard Support

The last little bit of trickery in MfcAxscrVb is the manipulations made to support ClassWizard. Class Wizard, technically isn't "dumb." It is just mentally challenged. It is pretty convenient for what it does, but remember that it just blindly searches files looking for those special ClassWizard comments. If you follow the format for COleControl, you can just about get away with using ClassWizard's Automation and Events tabs.

介绍一下怎么实现对ClassWizard的支持。ClassWizard只是通过在文件中查找特别的comments实现。可以参考ColeControl看看如何实现AutomationEvents


One complication is that MfcAxscrVb uses derivation in some of its object hierarchy. All of the button objects are derived from a common CButtonDispatch object that exposes properties and methods, all of which it would individually support. However, when it comes time to fill out the .odl file, each individual object needs to contain all of the properties and methods of the parent class. Needless to say, this is going to confuse Class Wizard when it comes time to number the DISPIDs. If you use Class Wizard, make sure you double-check the generated DISPIDs in two places: the .odl file for the automation class and the enumeration inside the class definition. When working with the derived button classes, it is easy to see the same DISPID assigned to multiple properties and methods. It is much easier to correct the DISPIDs, though, than to add everything by scratch, so the functionality has been left in MfcAxscrVb.

 


With Visual C++ 5.0's improved support of IDL methods and properties through ClassView, it's a toss up whether ClassWizard is needed or not. But MfcAxscrVb supports it for now. Enjoy.

Back to the top

Appendix A: Object Model

Scripter:

This is the master object from which all other objects are derived. It is "IMfcaxscrvbDlg" in the .odl file but is added as the Named Item "Scripter." It has one method, HostCreateObject, which is described above.

这是master对象,在odl中为ImfcaxscrvbDlg,而named itemScripter。他只有一个方法HostCreateObject


Button Objects:

AButton BButton, CancelButton, OKButton, RunScript

Properties
属性

·         Caption: Text of button face.

Methods 方法Press: Acts as if the button were pushed.

·         Press: Acts as if the button were pushed.

Events事件

·         OnClick: Fired when button is pushed.

·         OnMouseOver: Fired when mouse rolls over button.

·         OnFocus(bSet): Fired when focus is given or taken from button.

BroCon:

BroCon is the name of the WebBrowser control on the dialog box. It supports all properties and methods as documented in the Internet Client SDK/ActiveX SDK for the WebBrowser control.

EditCon:

Methods

·         AppendLine(strToAdd): Adds strToAdd to end of edit text window.

·         InsertLine(strToAdd, nWhere): Adds strToAdd at line #nWhere.

·         RemoveLine(nWhere): Removes line # nWhere from edit window.

Events

·         OnMouseOver: Fired when mouse rolls over window.

·         OnChar(strChar): Fired when character strChar is entered into window.

·         OnFocus(bSet): Fired when focus is given or taken from button.

Lbox:

Methods

·         AddString(strIn): Adds StrIn into list box.

·         ClearList: Clears all strings from list box.

·         RemoveString(strRemove): Removes first instance of StrRemove and removes it from list box.

·         SelectString(strSelect): Selects string specified by strSelect.

Events

·         OnMouseOver: Fired when mouse rolls over window.

·         OnFocus(bSet): Fired when focus is given or taken from button.

·         OnSelCancel(strCancelled): When selection is cancelled in a list box element strCancelled.

·         OnSelChange(strChange): When a list box element strChange is selected by the user.

Back to the top


APPLIES TO

  • Microsoft Internet Explorer 3.01
  • Microsoft Internet Explorer 3.02
  • Microsoft Internet Explorer 4.0 128-Bit Edition
  • Microsoft Internet Explorer 4.01 Service Pack 2
  • Microsoft Visual Basic, Scripting Edition 1.0
  • Microsoft Visual Basic, Scripting Edition 1.1
  • Microsoft Visual Basic, Scripting Edition 2.0
  • Microsoft Foundation Class Library 4.2, when used with:
    • Microsoft Visual C++ 5.0 Enterprise Edition
    • Microsoft Visual C++ 5.0 Professional Edition

Back to the top

 

posted on 2009-03-07 16:13  cutepig  阅读(832)  评论(0编辑  收藏  举报

导航