1
我正嘗試使用.NET服務應用程序連接C++ Builder應用程序,並希望.NET服務應用程序能夠將事件發送回C++ Builder應用程序。在C++ Builder中是否有COM事件處理的工作示例?
是否有可以處理COM事件的C++ Builder應用程序的工作示例?
我正嘗試使用.NET服務應用程序連接C++ Builder應用程序,並希望.NET服務應用程序能夠將事件發送回C++ Builder應用程序。在C++ Builder中是否有COM事件處理的工作示例?
是否有可以處理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。