请问COM组件的回调有哪些方式?怎样实现?

解决方案 »

  1.   

    1.可以定义一个interface实现回调:
      在COM外部实现这个接口,将这个接口做为一个参数传给COM内部,COM内部就可以调用这个接口的方法(其实是做为回调来用的),你在接口的方法里处理你的回调.
    2.传来个LONG参数给COM,在COM里强行转化成回调函数指针,这个方法比较不可靠,如果COM给其它语言用的时候不能保证对于RPC的回调我还不会!
      

  2.   

    COM中的回调有两种,一种是接口回调,例子代码如下:
    a) 新建一个新的ATL工程Com06
    b) 插入一个ATL对象(Math)其它全部采用缺省值
    c) 在IMath接口中增加方法(Add([in]long var1,[in]long var2,[out,retval])long* pVal)并实现之。(*pVal=var1+var2;)
    d) 在CMath类下创建一个成员变量ICallBack* m_pCallBack;并在构造函数中初始化为0;
    e) 增加另外一个方法Advise([in]ICallBack* pCallBack )
    STDMETHODIMP CMath::Advise(ICallBack *pCallBack)
    {
    m_pCallBack=pCallBack;
    m_pCallBack->AddRef();
    return S_OK;
    }
    f) 增加一个方法Unadvise()
    STDMETHODIMP CMath::Unadvise()
    {
    m_pCallBack->Release();
    m_pCallBack=0;
    return S_OK;
    }
    g) 定义引出接口,在接口定义文件中增加如下内容
    [
    object,
    uuid(2EA18575-2C16-424B-9DA7-D2A6B1BDB4A3),
    helpstring("ICallBack Interface")
    ]
    interface ICallBack : IUnknown
    {
    [helpstring("method Complete")] HRESULT Complete([in]long lResult);
    };
    h) 重新写Add()方法如下:
    STDMETHODIMP CMath::Add(long var1, long var2, long *pVal)
    {
    *pVal=var1+var2;
    m_pCallBack->Complete(*pVal);
    return S_OK;
    }
    到此为止,服务端写完
    4、 用VC写一个客户端程序
    a) 首先新建一个类,存放在文件a.h中,如下内容如下所示:
    #include "..\Com06\Com06.h"
    class CCallBack:ICallBack
    {
    public:
    long nCount;
    CCallBack()
    {
    nCount=0;
    }
    HRESULT _stdcall QueryInterface(REFIID riid,void** ppvObject)
    {
    if(riid==IID_ICallBack)
    *ppvObject=(ICallBack*)this;
    else 
    *ppvObject=(IUnknown*)(ICallBack*)this;
    return S_OK;
    }
    ULONG _stdcall AddRef()
    {
    return ++nCount;
    }
    ULONG _stdcall Release()
    {
    --nCount;
    if(nCount==0)
    {
    delete this;
    return 0;
    }
    return nCount;
    }
    HRESULT _stdcall Complete(long lResult)
    {
    CString str;
    str.Format("%d",lResult);
    MessageBox(0,str,"Msg",MB_OK);
    return S_OK;
    }
    };
    b) 在对话框类中增加一个新的成员变量如下:IMath* pIMath;,在头文件中增加相应的头文件a.h
    c) 在话框的初始化函数中增加如下代码,实现接口的登记
    ICallBack* pICallBack;
    CCallBack* pCallBack=new CCallBack;
    pCallBack->QueryInterface(IID_ICallBack,(void**)&pICallBack);
    ::CoInitialize(NULL);
    ::CoCreateInstance(CLSID_Math,NULL,1,IID_IMath,(void**)&pIMath);
    pIMath->Advise(pICallBack);
    d) 在Button1的事件处理代码中增加如下代码,调用COM组件中的方法
    long value;
    pIMath->Add(12,34,&value);
    e) 在对话框的关闭函数中增加如下代码,取消登记及相应接口指针的释放。
    void CCom06CliDlg::OnClose() 
    {
    pIMath->Unadvise();
    pIMath->Release();
    CDialog::OnClose();
    }
    到此为止整个VC下的回调过程实现另外一种就是连接点了,其实这两种差不太多,
      

  3.   

    还是连接点,应该必须是连接点,楼上所说的方法适用与同一进程的com组件
    如果,是其他的现成模式,这么做会会产生不可预料的后果,(比如是内存违规访问)
      

  4.   

    不一定要连接点,如果你的组件并不打算给别人在诸如VB的编程环境中使用, 你可以简单地接收一个接口,并调用这个接口的方法.COM规范没有阻止你这么使用.我曾经做过这样的例子.不过这么用如果客户端阻塞, 会造成服务器也阻塞.如果需要异步调用,可以用COM+的事件代替.
    不要使用自由线程模型.
      

  5.   

    补充: 强制转换函数指针是不对的. 即时是在同一个进程内,也不应该使用. 还会有线程等很多问题,一个C语言的函数指针对VB是没有意义的
      

  6.   

    不考虑其他的语言调用,进程服务器版本,使用从C++调用,的话可以使用
    Up的方法,不过那个时候需要使用com吗?