2016-01-02 9 views

回答

1

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。

相關問題