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
View products
that this article applies to.
This article was previously published under Q168214
·
SUMMARY
o
Exposing the Host: Dispatch Objects
o
Getting to Other Apps: HostCreateObject
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实现了vbscript的host功能,通过提供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
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.
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文件里有一些例子
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接口控制的属性,方法和事件。MFC的ColeControl支持输入和输出disptch接口,event sinks。但是对我们来说,这个类太大了。我们只需要events,和dispatch接口,和type信息。Vbscrip需要读入支持event的dispatch对象的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, event和clsid),需要在cpp和odl文件里分别实现。
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类,而该按钮对应的dispatch为CAButtonDispatch类。
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中必须显式的将这两个连在一起
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必须实现Idispatch和ItypeInfo。Script引擎通过IActiveScriptSite::GetItemInfo得到某一项named item的Iunknown和ITypeInfo指针。
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通过AddNamedItems(SCRIPTITEM_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只暴露了一个外部的对象给script的namespace,即WebBrowser。Host通过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接口。在vb中host提供的是createobject方法
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了
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看看如何实现Automation和Events
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.
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 item是Scripter。他只有一个方法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.
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