我要写一个COM组件供其它的开发语言调用,这个组件需要产生一些事件通知调用者。
但不知道如何把该COM组件的事件,与调用者关联起来,请大家指教。
示例代码如下:
这个是COM组件单元文件unit RealOAMessengerAutoServer;{$WARN SYMBOL_PLATFORM OFF}interfaceuses
ComObj, ActiveX, AxCtrls, Classes, RealICQCOM_TLB, StdVcl,Dialogs;type
TRealOAMessengerAutoServer = class(TAutoObject, IConnectionPointContainer, IRealOAMessengerAutoServer)
private
{ Private declarations }
FConnectionPoints: TConnectionPoints;
FConnectionPoint: TConnectionPoint;
FEvents: IRealOAMessengerAutoServerEvents;
{ note: FEvents maintains a *single* event sink. For access to more
than one event sink, use FConnectionPoint.SinkList, and iterate
through the list of sinks. }
public
procedure Initialize; override;
protected
procedure AddText(const NewText: WideString); safecall;
procedure clear; safecall;
{ Protected declarations }
property ConnectionPoints: TConnectionPoints read FConnectionPoints
implements IConnectionPointContainer;
procedure EventSinkChanged(const EventSink: IUnknown); override;
end;implementationuses ComServ;procedure TRealOAMessengerAutoServer.EventSinkChanged(const EventSink: IUnknown);
begin
FEvents := EventSink as IRealOAMessengerAutoServerEvents;
end;procedure TRealOAMessengerAutoServer.Initialize;
begin
inherited Initialize;
FConnectionPoints := TConnectionPoints.Create(Self);
if AutoFactory.EventTypeInfo <> nil then
FConnectionPoint := FConnectionPoints.CreateConnectionPoint(
AutoFactory.EventIID, ckSingle, EventConnect)
else FConnectionPoint := nil;
end;
procedure TRealOAMessengerAutoServer.AddText(const NewText: WideString);
begin
if FEvents <> nil then FEvents.OnTextChanged('我成功了');
// showmessage('dsf');
end;procedure TRealOAMessengerAutoServer.clear;
beginend;initialization
TAutoObjectFactory.Create(ComServer, TRealOAMessengerAutoServer, Class_RealOAMessengerAutoServer,
ciMultiInstance, tmApartment);
end.
其中OnTextChanged相关的方法及事件接口定义是这样的 IRealOAMessengerAutoServerDisp = dispinterface
['{5C187B3A-8691-4561-AA31-FAEDEBA42A10}']
procedure clear; dispid 201;
procedure AddText(const NewText: WideString); dispid 202;
end; IRealOAMessengerAutoServerEvents = dispinterface
['{00BC3F20-3265-403C-B0E3-69DF1C6EF89D}']
procedure OnTextChanged(const NewText: WideString); dispid 203;
procedure OnClear; dispid 204;
end;
调用者的代码如下:unit main;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
CLASS_AutoTest: TGUID = '{64C576F0-C9A7-420A-9EAB-0BE98264BC9D}';type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
FVar: OleVariant;
procedure OnEditChange(const NewText: WideString);
procedure OnClear;
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}uses ComObj;
procedure TForm1.Button1Click(Sender: TObject);
begin
FVar := CreateOleObject('RealICQCOM.RealOAMessengerAutoServer');//Srv.AutoTest');
// FVar.OnTextChanged:=OnEditChange('d');
end;procedure TForm1.Button2Click(Sender: TObject);
begin
FVar.AddText(Edit1.Text);
end;procedure TForm1.OnClear;
begin
self.Edit1.Clear;
end;procedure TForm1.OnEditChange(const NewText: WideString);
begin
showmessage(NewText);
end;end.注意:不要告诉我要引用COM组件的任何一个单元,因为被调用者很可能不是DELPHI语言,因为这个COM组件原则上是可以供多种语言调用的
但不知道如何把该COM组件的事件,与调用者关联起来,请大家指教。
示例代码如下:
这个是COM组件单元文件unit RealOAMessengerAutoServer;{$WARN SYMBOL_PLATFORM OFF}interfaceuses
ComObj, ActiveX, AxCtrls, Classes, RealICQCOM_TLB, StdVcl,Dialogs;type
TRealOAMessengerAutoServer = class(TAutoObject, IConnectionPointContainer, IRealOAMessengerAutoServer)
private
{ Private declarations }
FConnectionPoints: TConnectionPoints;
FConnectionPoint: TConnectionPoint;
FEvents: IRealOAMessengerAutoServerEvents;
{ note: FEvents maintains a *single* event sink. For access to more
than one event sink, use FConnectionPoint.SinkList, and iterate
through the list of sinks. }
public
procedure Initialize; override;
protected
procedure AddText(const NewText: WideString); safecall;
procedure clear; safecall;
{ Protected declarations }
property ConnectionPoints: TConnectionPoints read FConnectionPoints
implements IConnectionPointContainer;
procedure EventSinkChanged(const EventSink: IUnknown); override;
end;implementationuses ComServ;procedure TRealOAMessengerAutoServer.EventSinkChanged(const EventSink: IUnknown);
begin
FEvents := EventSink as IRealOAMessengerAutoServerEvents;
end;procedure TRealOAMessengerAutoServer.Initialize;
begin
inherited Initialize;
FConnectionPoints := TConnectionPoints.Create(Self);
if AutoFactory.EventTypeInfo <> nil then
FConnectionPoint := FConnectionPoints.CreateConnectionPoint(
AutoFactory.EventIID, ckSingle, EventConnect)
else FConnectionPoint := nil;
end;
procedure TRealOAMessengerAutoServer.AddText(const NewText: WideString);
begin
if FEvents <> nil then FEvents.OnTextChanged('我成功了');
// showmessage('dsf');
end;procedure TRealOAMessengerAutoServer.clear;
beginend;initialization
TAutoObjectFactory.Create(ComServer, TRealOAMessengerAutoServer, Class_RealOAMessengerAutoServer,
ciMultiInstance, tmApartment);
end.
其中OnTextChanged相关的方法及事件接口定义是这样的 IRealOAMessengerAutoServerDisp = dispinterface
['{5C187B3A-8691-4561-AA31-FAEDEBA42A10}']
procedure clear; dispid 201;
procedure AddText(const NewText: WideString); dispid 202;
end; IRealOAMessengerAutoServerEvents = dispinterface
['{00BC3F20-3265-403C-B0E3-69DF1C6EF89D}']
procedure OnTextChanged(const NewText: WideString); dispid 203;
procedure OnClear; dispid 204;
end;
调用者的代码如下:unit main;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
const
CLASS_AutoTest: TGUID = '{64C576F0-C9A7-420A-9EAB-0BE98264BC9D}';type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
FVar: OleVariant;
procedure OnEditChange(const NewText: WideString);
procedure OnClear;
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}uses ComObj;
procedure TForm1.Button1Click(Sender: TObject);
begin
FVar := CreateOleObject('RealICQCOM.RealOAMessengerAutoServer');//Srv.AutoTest');
// FVar.OnTextChanged:=OnEditChange('d');
end;procedure TForm1.Button2Click(Sender: TObject);
begin
FVar.AddText(Edit1.Text);
end;procedure TForm1.OnClear;
begin
self.Edit1.Clear;
end;procedure TForm1.OnEditChange(const NewText: WideString);
begin
showmessage(NewText);
end;end.注意:不要告诉我要引用COM组件的任何一个单元,因为被调用者很可能不是DELPHI语言,因为这个COM组件原则上是可以供多种语言调用的
调用ComObj单元的InterfaceConnect()函数就可以轻松完成,如下所示:这个函数的第一个参数指定了一个源对象,第二个参数是输出接口的IID,第三个参数指定事件接
收器的接口,第四个参数是一个cookie。
当你对事件的处理结束后,应该在主窗体的析构器中调用InterfaceDisconnect()函数:
InterfaceConnect方法已经会用了,还有一点小问题不太明白。
就是你说的"第一个参数指定了一个源对象",这个源对像指的就是我前面代码中的
FVar := CreateOleObject('RealICQCOM.RealOAMessengerAutoServer');//Srv.AutoTest');
当然这种创建方式是可以,但我更想用CreateComObject的方式,我是这样写的。Fobject:IUnKnown;//声明
Fobject:= CreateComObject(Class_AutoTest) as IUnKnown;//创建实例
InterfaceConnect(Fobject, IRealOAMessengerAutoServerEvents, FEventSink, FCookie);//连接,其中FEventSink是接收器。但问题出来了,当我要执行接口IRealOAMessengerAutoServerDisp 的AddText方法时,因为Fobject是声明的IUnKnown接口,
编译器是不允许通过的。我想问的是:
1、Fobject是否需要用一个真正的接口来声明而不是IUnKnown,还是有其它办法?
2、如果开发语言是C#(比如),那么是不是用C#重新写一个接口,该接口与delphi的IRealOAMessengerAutoServerDisp接口用同一个GUID,
这种方法可行吗?
用IUnknown的QueryInterface,得到你所需要的接口或者通过IDispatch接口调用
但我在写代码的时候要事先知道这些方法
Fobject.AddText(Edit1.Text);
AddText这个方法编译器不会认的。
为什么你要定义成IUnKonw?
http://blog.csdn.net/akirya/archive/2008/02/17/2100501.aspx
能理解C版的如何调用的话知道你的代码该如何写了.
如果是编译型语言,一般用vTable调用,因此会使用导入类型库,这样调用者就会生成tlb对应的接口定义单元,所以不会存在你所谓的“那个接口是delphi定义的,但调用者是其它的开发语言,没办法直接引用delphi单元的那个接口”