我要写一个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组件原则上是可以供多种语言调用的

解决方案 »

  1.   

    copy <<Delphi 5开发人员指南>>的建立客户端的最后一步是把事件接收器连接到服务器的源接口。这一步只要从主窗体的构造器中
    调用ComObj单元的InterfaceConnect()函数就可以轻松完成,如下所示:这个函数的第一个参数指定了一个源对象,第二个参数是输出接口的IID,第三个参数指定事件接
    收器的接口,第四个参数是一个cookie。
    当你对事件的处理结束后,应该在主窗体的析构器中调用InterfaceDisconnect()函数:
      

  2.   

    楼上记性真好,是引用了Delphi 5开发人员指南,不过现在却要用在项目上了。
    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,
    这种方法可行吗?
      

  3.   

    1、Fobject是否需要用一个真正的接口来声明而不是IUnKnown,还是有其它办法? 
    用IUnknown的QueryInterface,得到你所需要的接口或者通过IDispatch接口调用
      

  4.   

    这种方法只有在程序执行的过程中才会知道真正的接口及其方法吧
    但我在写代码的时候要事先知道这些方法
    Fobject.AddText(Edit1.Text);
    AddText这个方法编译器不会认的。
      

  5.   

    为什么你要用那个函数,就把接口定义成那个接口啊!
    为什么你要定义成IUnKonw?
      

  6.   

    那个接口是delphi定义的,但调用者是其它的开发语言,没办法直接引用delphi单元的那个接口。
      

  7.   

    你可以先查询到你定义的接口,由QueryInterface的参数返回你要查询的类型的句柄,如果查询到自然方法都可用.
      

  8.   

    就算是Delphi定义的,但你总得在idl文件中定义接口吧, 其他语言就需要这个idl中的定义.
      

  9.   

    你看下这篇文章
    http://blog.csdn.net/akirya/archive/2008/02/17/2100501.aspx
    能理解C版的如何调用的话知道你的代码该如何写了.
      

  10.   

    这是自动化服务器,只要提供接口任何语言都可调用的。就象word一样,也是一个自动化服务器。
      

  11.   

    这是自动化服务器,只要提供接口任何语言都可调用的。就象word一样,也是一个自动化服务器。
      

  12.   

    如果是脚本语言(当然不是脚本语言也可以),一般用IDispach自动化接口,也就是把你的Fobject声明成IDispach类型
    如果是编译型语言,一般用vTable调用,因此会使用导入类型库,这样调用者就会生成tlb对应的接口定义单元,所以不会存在你所谓的“那个接口是delphi定义的,但调用者是其它的开发语言,没办法直接引用delphi单元的那个接口”