c++ - C++ Builder 中是否有 COM 事件处理的工作示例?

标签 c++ events com c++builder

我正在尝试将 C++ Builder 应用与 .NET 服务应用连接,并且希望 .NET 服务应用能够将事件发送回 C++ Builder 应用。

是否有可以处理 COM 事件的 C++ Builder 应用程序的工作示例?

最佳答案

DocWiki 中有关处理 COM 事件的错误。我从各地收集了一些例子,放在一起供引用。

.NET 应用程序具有以下内容:

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace IPractLib01
{
    // 
    // GUID's to use for the COM objects.
    [Guid("ACD03FE3-E506-4D87-BF8B-CC1F52E1FF0C")]
    public interface IManagedInterface
    {
        int SendMessage(
            string message
            );
    }


    // Source interface with "event handlers" for COM objects to implement
    [Guid("1ACAB463-55A3-4B3F-BE10-6252CDD93CE8")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] // use InterfaceIsDual to get callbacks by other than InvokeEvent()
    public interface IIntelliPractEvents
    {
        [DispId(1)] void MessageReceived();

        [DispId(2)] void MessageTextReceived(string message);
    }

    // Delegates for the events
    public delegate void MessageReceivedEventHandler();
    public delegate void MessageTextReceivedEventHandler(string message);

    [Guid("1F4A7EDA-EE2A-4EA3-B213-A1911C5F766E")]
    [ComSourceInterfaces(typeof(IIntelliPractEvents))]
    public class IPractLib01Class : IManagedInterface
    {
        public event MessageReceivedEventHandler MessageReceived;
        public event MessageTextReceivedEventHandler MessageTextReceived;

        public int SendMessage(string message)
        {
            if (MessageReceived != null)
            {
                MessageReceived();
            }
            if (MessageTextReceived != null)
            {
                int len = message.Length;
                string newMessage = "The message is '" + message + "', and the length of the message is " + len;
                MessageTextReceived(newMessage);
            }
            return 0;
        }    
    }
}

C++ Builder 应用程序包含:

#include "Unit1.h"
#include "IPractLib01_TLB.h" // created with Component/Import Component/Import a Type Library

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

// to register the assembly dll:
// regasm IPractLib01.dll /tlb /verbose
// Need to run regasm as administrator, due to need to modify registry.  If a regular user login was used to map drives, the mappings are not normally seen by the administrator login.  Use "net use" in the administrator login to map them for the administrator

static TCOM_IPractLib01Class iplClass;

// The DocWiki does not take the address of the DIID_, but that does not compile
class MyEventSinkClass : public TEventDispatcher<MyEventSinkClass, &DIID_IIntelliPractEvents>
{
public:
  MyEventSinkClass(IUnknown* sourceClass);
  ~MyEventSinkClass();
// declare the methods of DIID_IIntelliPractEvents here
  void __fastcall MessageReceived();
  void __fastcall MessageTextReceived(BSTR message/*[in]*/);
  virtual HRESULT InvokeEvent(DISPID id, TVariant* params = 0);

  IUnknown* theSource_;
};

static MyEventSinkClass* theEventSink = NULL;

static void ConnectNetHandler(void)
{
    if (!iplClass)
        iplClass = CoIPractLib01Class::Create();

    if (!theEventSink) {
        theEventSink = new MyEventSinkClass(iplClass);
    }

}

// All of the events come through InvokeEvent -- change the interface to InterfaceIsDual if you want events through the other routines
HRESULT MyEventSinkClass::InvokeEvent(DISPID id, TVariant* params)
{
    ShowMessage("got InvokeEvent with DISPID " + String(id));
    // params would need better handling in a real app
    if (params) {
        String st = params->operator WideString();
        ShowMessage("String is " + st);
    }
    return 0;
}

MyEventSinkClass::MyEventSinkClass(IUnknown* sourceClass)
{
    theSource_ = sourceClass;
    ConnectEvents(sourceClass);
}

MyEventSinkClass::~MyEventSinkClass()
{
    DisconnectEvents(theSource_);
}


// These two routines do not get called with InterfaceIsDispatch; change that to InterfaceIsDual for these routines to be called.
void __fastcall MyEventSinkClass::MessageReceived()
{
    ShowMessage("Message handler received");
}

void __fastcall MyEventSinkClass::MessageTextReceived(BSTR message/*[in]*/)
{
    ShowMessage(String("Message handler received with message: ") + message);
}    

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ConnectNetHandler();

    long result = -1;
    TCOMIManagedInterface mif = iplClass;
    if (!mif) {
        ShowMessage("Unable to connect to interface");
        return;
    }

    String theMessage = "the message";
    mif->SendMessage(WideString(theMessage).c_bstr(), &result);

    // check the IErrorInfo
    // (Microsoft: Making a COM call that goes through a proxy-stub will clear any existing error object for the calling thread)

    IErrorInfo *pperrinfo = NULL;
    HRESULT hr = GetErrorInfo(0, &pperrinfo);
    if (SUCCEEDED(hr) && pperrinfo) {

    WideString wideStringMessage, wideStringDescription; // WideString is a wrapper for BSTR
    pperrinfo->GetSource(&wideStringMessage);
    pperrinfo->GetDescription(&wideStringDescription);
    ShowMessage("Got error from " + String(wideStringMessage) + "; error description: " + String(wideStringDescription));
}

.NET 代码创建的 DLL 必须使用 regasm/tlb 注册才能生成类型库,以允许 C++ Builder 创建实现 COM 的单元。但是,一旦创建了应用程序,就不需要在部署该应用程序的系统上调用 regasm。

关于c++ - C++ Builder 中是否有 COM 事件处理的工作示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34563863/

相关文章:

c++ - 循环和if的优化

WPF Mousedown => 没有 MouseLeave 事件

c++ - 当我们迭代它时更改 HashMap 的行为是否已定义?

swift - 从 bash 脚本调用 swift 函数

vb.net - 确定是否已附加事件

c++ - COM IContextMenu::InvokeCommand - 匹配 LPCMINVOKECOMMANDINFO::lpVerb 到项目

c++ - VARIANT 结构 (COM) 似乎没有成员

c++ - 再生连接点法

c++ - 指向数组访问的指针出现段错误

c++ - 如何在 rtl 对齐中打开右侧的子菜单?