Delphi COM编程技术四自动化技术

一、自动化技术的基础

1、 自动化名称介绍:

1>、自动化: 是一种从应用程序的内部自动控制另一个应用程序的方法。

2>、自动化对象: 指的是实现了IDispatch接口的COM对象,IDispatch接口是自动化对象的一个重要标志。因此,可以通过QuereyInterface()函数查询组件是否包含此接口,来确定该组件是否是自动化对象。自动化对象包括属性和方法,其属性只能被读取不能被写入。

3>、自动化组件:除了定义自动化对象外,还将内部可编程对象展现给自动化客户,而自动化客户则对这些暴露的自动化对象进行操作。

4>、早期连接/接口(early binding):早期连接是指对接口方法的所有调用在编译时检查参数是否正确;

5>、后期连接/Variants (late binding):后期连接指连接意味着方法调用直到运行时才被实现;Variant不是对象指针;对象的调用方法是后期连接;编写快速、简单的客户应用程序不用费力去输入一个类型库;

6>、派遣接口(DispInterface) :在接口和Variant中间的某个地方就是派遣接口;与接口有很多类似; 只是方便客户而设定的; 并没有在服务器上实现派遣接口;是服务器上实现了接口;假设服务器的COM对象也支持IDispatch接口,客户应用程序可以使用Variants或派遣接口;

7>、双重接口(Dual Interface):支持早期连接(接口)和后期连接(Variants);使用delphi创建的任何任何自动化服务器将自动支持双重接口;

 

2、使用自动化技术的目的:

1>、使用自动化技术的一个主要目的就是对COM的一些底层操作进行简化,包括自动化组件(用于定义自动化对象)和自动化客户(用于使用自动化对象)两方面的内容。

2>、通过自动化操作类型库。

3>、从应用程序的内部自动控制另一个应用程序的方法。

4>、客户通过使用接口、Variants派遣接口和双重接口创建并使用自动化服务器; 

二、IDispatch接口:自动化对象的标志

1、IDispatch接口的定义:

IDispatch接口直接从IUnknown接口派生,接口定义如下:

interface IDispatch : IUnknown
{
 virtual HRESULT GetTypeInfoCount(UINT* pctinfo) = 0;
 virtual HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) = 0;
 virtual HRESULT GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) = 0;
 virtual HRESULT Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr ) = 0;
}

 

2、IDispatch接口的中的函数:

1>、GetTypeInfoCount()成员函数:用于获取自动化组件支持的ITypeInfo接口的数目

2>、GetTypeInfo()成员函数:用于获取指针ITypeInfo接口的指针,通过该指针将能够判断自动化服务程序所提供的自动化支持。

3>、GetIDsOfNames()成员函数:将读取一个函数的名称并返回其调度ID(DISPID),DISPID只是一个long类型的数据,对于IDispatch的一个特定实现,此DISPID值应该是唯一的。
riid:为保留参数,必须设置为IID_NULL,
rgszNames:指定了成员的函数名及其参数,
cNames:标识了名字的个数,
lcid:参数用于指定本地化标识,如:GetUserDefaultLCID()
rgdispid:得到的DISPID 将保存到rgdispid中。

4>、Invoke()成员函数:提供了访问自动化对象暴露出来的方法和属性的方法。
dispidMember: 可以将DISPID作为函数指针数组的索引传入dispidMember参数,Invoke()将实现一组按此索引来访问的函数。
riid和lcid: 的含义与在GetIDsOfNames()中的定义相同,分别为保留参数和本地化标识。
WFlags: 指定了要访问的是接口的属性还是方法,
pdispparams: 包括了方法和属性调用的参数数组、DISPID数组以及数组中参数个数等信息。
pvarResult: 保存有返回值信息,可以使用NULL。
pexcepinfo: 指向一个有效的异常信息结构,可以使用NULL。
puArgErr: 参数包含了第一个产生错误的参数指针。可以使用NULL。

    通过GetIDsOfNames()和Invoke()的结合使用,将可以根据函数名称对方法和属性进行调用。这样,函数地址、AddRef()、Release()以及接口指针等细节问题将无需考虑。

 

3、IDispatch接口的使用实例(C++代码):

// 从ProgID得到CLSID
wchar_t progid[] = L"MSCAL.Calendar.7";
CLSID clsid;
if (FAILED(::CLSIDFromProgID(progid, &clsid)))// Calendar组件的ProgID转换为CLSID
 return;
// 得到IDispatch接口指针
IDispatch* pIDispatch = NULL;

//创建CLSID相应的组件并从输出IDispatch接口的指针
if (FAILED(::CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void**)&pIDispatch)))
 return;
// 得到DISPID
DISPID dispid;
OLECHAR* func = L"Today";
if (FAILED(pIDispatch->GetIDsOfNames(IID_NULL, &func, 1, GetUserDefaultLCID(), &dispid)))
 return;
// 通过DISPID使用Today方法
DISPPARAMS dispparams = {NULL};
if (FAILED(pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &dispparams, NULL, NULL, NULL)))
 return;
// 将日期移动到今天
AfxMessageBox("日期成功移动到今天");

    这段代码使用的是Calendar组件,并通过IDispatch接口完成对Today()方法的调用。CLSIDFromProgID()将Calendar组件的ProgID转换为CLSID,并以此CLSID和IID_IDispatch作为参数去调用CoCreateInstance()以得到IDispatch接口指针。通过其成员函数GetIDsOfNames()得到将要调用的Today方法的DISPID,最后使用Invoke()成员函数执行此方法。


三、获取自动化服务器COM对象的方法

1、自动化服务器

1>、在本身应作为独立服务器应用程序的情况下,使用进程外自动化服务器非常好;

2>、自动服务器中的所有方法必须返回一个HResult,暗示是成功还是失败; 
3>、所有其他参数必须在out参数中返回;

4>、访问自动化服务器的方法:通过接口、派遣接口、Variants(可使用的类名,CreateOleObject)、回调接口来控制此服务器;

l         派遣接口(DispInterface): 为事件提供了更好的支持;与VB兼容;实现事件是最兼容的方法、

l         接口(Interface): 不与VB兼容;但速度比派遣接口稍快;

l         回调接口(CallBack Interface):除非有极重要的原因否则不要使用;服务器做大量的工作,而刻户端不需要太多的工作;接口中定义回调方法,而不是使用派遣接口把事件送回到客户端; 回调接口在服务器中定义,但在客户中实现; 如果知道服务器和客户提供的接口,回调接口更有效;

2、 进程内自动化服务器

    进程中的服务器是作为动态连接库(DLL)实现的,这意味着该服务器在运行时被动态地放进你的进程中。COM服务器将成为你应用中的一部分,而COM操作在应用的线程中进行。事实上,许多的COM对象都是以这种方式实现的,因为性能很好。一个COM函数调用的系统开销很小,但你可以得到COM所有的设计和重用的好处。COM自动处理载入和卸下该DLL。
CreateOleObject函数:总是创建特定服务器的新实例; 
GetActiveOleObject函数: 用来获取正在内存中运行的服务器的引用; 
例如:创建并使用进程内自动化服务器; 
       Procedure StartOrLinkToWord; 
       var

         v: Variant; 
       begin  
         try 
           v := GetActiveOleObject('Word.Basic');  //判断是否Word已启动; 
         except 
           v := CreateOleObject('Word.Basic');   //否则启动Word; 通常自动化服务器启动是隐藏的; 
           v.AppShow;   //显示Word应用程序; 
         end; 
         V.FileNew;  //创建一个新的文档; 
         v.Insert('Automation is easy!');     
       end; 

3、 进程外自动化服务器

    一个进程外的服务器令客户和服务端的区分更明显。该类服务器作为一个独立的可执行(EXE)程序运行,因此处在一个私有的进程空间中。EXE服务器的启动和停止在Windows中服务管理器中进行(SCM)。COM接口的调用通过内部的进程通信技术来处理。服务器可以运行在本地的机器,或者在一个远程的计算机上。如果服务器在一个远程的计算机上,我们称它为“Distributed COM,分布式的COM”,或者DCOM。

四、 自动化ADO: Microsoft最新的数据库技术;

1、主要组件:Connection、RecordSet、Command; 
1>、Connection对象: 用于连接到一个本地或远处的数据库;连接数据库:Connection.Open();
2>、RecordSet对象: 提供了一个记录集的连接;打开记录集:RecordSet.Open() 
3>、Command对象: 向数据库发出命令,应使用Command对象(与Parameter一起工作); 
4>、访问字段值:访问Field对象的值: RecordSet.Fields.Item[FieldNo].Value; 
5>、访问字段名称:RecordSet.Fields.Item[FieldNo].Name; 
6>、数据库错误处理:Error对象,该对象提供任何错误的详细代码;

你可能感兴趣的:(Delphi COM编程技术四自动化技术)