Hi, We are trying to implement COM inside our .NET c# application, that needs to be called from a C++ app. While we can get the properties and methods to work just fine, the C++ client has an issue with the events. The C++ client can see and register interest in the c# event just fine, I can debug the .net code and see that the C++ has registered interest, but as soon as the .net app fires the event, the C++ app dies with a Buffer Overrun exception. The event has no parameters, I've worked based on the information available from Microsoft, but I cannot fathom out why this is happening. Unfortunately I am not a C++ programmer, but a C# programmer, so the C++ code makes little sense! Does any one have any thoughts on why this might be happening? The relevant code is shown below: Interface in .NET DLL: namespace ClientControl { [Guid("04F3C372-9E85-442d-B7E4-D6966E14BD0E")] [ComVisible(true)] public interface IClientControl { void Login(string serverAddress, int serverPort, string username, string password); void Logout(); void Dispose(); void ChangeStatus(string status); string CurrentStatus { get; } string Version { get; } } [Guid("548B0682-AA8E-437c-839C-877BF9CADE3B")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)] [ComVisible(true)] public interface IClientControl_Events { [DispId(1)] void StatusChanged(); [DispId(2)] void Notification(); } } Main Class File: public delegate void StatusChangedEventHandler(); public delegate void NotificationEventHandler(); [ClassInterface(ClassInterfaceType.None),ComSourceInterfaces(typeof(IClientControl_Events))] [Guid("6612B82C-3C47-4c99-AE5E-FC83C397AF2C")] [ComVisible(true)] public partial class ClientControl : UserControl, IClientControl, IDisposable public event NotificationEventHandler Notification; public event StatusChangedEventHandler StatusChanged; Code to fire event: if (StatusChanged != null) { StatusChanged(); } If anyone has any pointers, I'd love to hear them! Best Regards
In Addition to the last post: I get the following when debugging the .net code (using the C++ exe as the test container for debug) ----------- ERROR : Unable to load Typelibrary. (HRESULT = 0x8002801d) Verify TypelibID and major version specified with IDispatchImpl, CStockPropImpl, IProvideClassInfoImpl or IProvideCLassInfo2Impl A first chance exception of type 'System.Runtime.InteropServices.COMException' occurred in ClientControl.dll An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in ClientControl.dll Additional information: Library not registered. (Exception from HRESULT: 0x8002801D (TYPE_E_LIBNOTREGISTERED)) ------------ This occurs as soon as the .net code tries to raise the event. Regards
You might look at your C++ event sink class. I suspect your error is probably in there. Maybe you could show your event sink implementation from your C++ code here. The C# code looks fine to me. [quoted text, click to view] "Chris Priest" <cpriest@gresham-computing.com> wrote in message news:%23Skthr4bHHA.4176@TK2MSFTNGP02.phx.gbl... > Hi, > > We are trying to implement COM inside our .NET c# application, that needs > to be called from a C++ app. > > While we can get the properties and methods to work just fine, the C++ > client has an issue with the events. > > The C++ client can see and register interest in the c# event just fine, I > can debug the .net code and see that the C++ has registered interest, but > as soon as the .net app fires the event, the C++ app dies with a Buffer > Overrun exception. > > The event has no parameters, I've worked based on the information > available from Microsoft, but I cannot fathom out why this is happening. > > Unfortunately I am not a C++ programmer, but a C# programmer, so the C++ > code makes little sense! > > Does any one have any thoughts on why this might be happening? > > The relevant code is shown below: > > Interface in .NET DLL: > > namespace ClientControl > { > [Guid("04F3C372-9E85-442d-B7E4-D6966E14BD0E")] > [ComVisible(true)] > public interface IClientControl > { > void Login(string serverAddress, int serverPort, string username, string > password); > void Logout(); > void Dispose(); > void ChangeStatus(string status); > string CurrentStatus { get; } > string Version { get; } > } > > [Guid("548B0682-AA8E-437c-839C-877BF9CADE3B")] > [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)] > [ComVisible(true)] > > public interface IClientControl_Events > { > [DispId(1)] > void StatusChanged(); > [DispId(2)] > void Notification(); > } > > } > > Main Class File: > > public delegate void StatusChangedEventHandler(); > public delegate void NotificationEventHandler(); > > [ClassInterface(ClassInterfaceType.None),ComSourceInterfaces(typeof(IClientControl_Events))] > [Guid("6612B82C-3C47-4c99-AE5E-FC83C397AF2C")] > [ComVisible(true)] > public partial class ClientControl : UserControl, IClientControl, > IDisposable > public event NotificationEventHandler Notification; > public event StatusChangedEventHandler StatusChanged; > > Code to fire event: > > if (StatusChanged != null) > { > StatusChanged(); > } > > If anyone has any pointers, I'd love to hear them! > > Best Regards > Chris
Hi Jayme, I think this is what you are referring to :) : // ClientControlEventSink.h #pragma once #import "ClientControl.tlb" named_guids raw_interfaces_only #define IDC_ClientControl 998 // CClientControlEventSink command target class CClientControlEventSink : public CCmdTarget { DECLARE_DYNAMIC(CClientControlEventSink) public: CClientControlEventSink(); virtual ~CClientControlEventSink(); virtual void OnFinalRelease(); // ClientControl overrides void OnStatusChanged(); protected: DECLARE_MESSAGE_MAP() DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP() // ClientControlEventSink.cpp : implementation file // #include "stdafx.h" #include "tryclientcontrol.h" #include "ClientControlEventSink.h" // CClientControlEventSink IMPLEMENT_DYNAMIC(CClientControlEventSink, CCmdTarget) CClientControlEventSink::CClientControlEventSink() { EnableAutomation(); } CClientControlEventSink::~CClientControlEventSink() { } void CClientControlEventSink::OnFinalRelease() { // When the last reference for an automation object is released // OnFinalRelease is called. The base class will automatically // deletes the object. Add additional cleanup required for your // object before calling the base class. CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CClientControlEventSink, CCmdTarget) END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CClientControlEventSink, CCmdTarget) DISP_FUNCTION_ID(CClientControlEventSink,"StatusChanged", 0x00000001, OnStatusChanged,VT_EMPTY,VTS_I4 VTS_I4) END_DISPATCH_MAP() // Note: we add support for IID_IClientControlEventSink to support typesafe binding // from VBA. This IID must match the GUID that is attached to the // dispinterface in the .IDL file. // {6998F069-5D1D-45A3-9E42-384B6C5FA9B1} //static const IID IID_IClientControlEventSink = //{ 0x6998F069, 0x5D1D, 0x45A3, { 0x9E, 0x42, 0x38, 0x4B, 0x6C, 0x5F, 0xA9, 0xB1 } }; static const IID IID_IClientControlEventSink = { 0x548B0682, 0xAA8E, 0x437C, { 0x83, 0x9C, 0x87, 0x7B, 0xF9, 0xCA, 0xDE, 0x3B } }; BEGIN_INTERFACE_MAP(CClientControlEventSink, CCmdTarget) INTERFACE_PART(CClientControlEventSink, ClientControl::DIID_IClientControl_Events, Dispatch) END_INTERFACE_MAP() // CClientControlEventSink message handlers void CClientControlEventSink::OnStatusChanged() { int i = 1000; } // ATlClientContainer.h : Declaration of the CATlClientContainer #pragma once #include "resource.h" // main symbols #include <atlhost.h> #include <string> #import "ClientControl.tlb" named_guids raw_interfaces_only #define IDC_ClientControl 998 // CATlClientContainer class CATlClientContainer; typedef IDispEventImpl<IDC_ClientControl, CATlClientContainer, &ClientControl::DIID_IClientControl_Events, &ClientControl::LIBID_ClientControl> VoipIMControlEvent; class CATlClientContainer : public CAxDialogImpl<CATlClientContainer>, public VoipIMControlEvent { public: CATlClientContainer() { } ~CATlClientContainer() { } enum { IDD = IDD_ATLCLIENTCONTAINER }; BEGIN_MSG_MAP(CATlClientContainer) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) CHAIN_MSG_MAP(CAxDialogImpl<CATlClientContainer>) END_MSG_MAP() BEGIN_SINK_MAP(CATlClientContainer) //Make sure the Event Handlers have __stdcall calling convention SINK_ENTRY_EX(IDC_ClientControl, ClientControl::DIID_IClientControl_Events, 0x00000001, StatusChanged) SINK_ENTRY_EX(IDC_ClientControl, ClientControl::DIID_IClientControl_Events, 0x00000002, Notification) END_SINK_MAP() // Handler prototypes: // LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); // LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); // LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); protected: // Events VOID __stdcall StatusChanged() { } VOID __stdcall Notification() { //OnClientControlNotification(); } private: CComPtr<ClientControl::IClientControl> m_pClientControl; CAxWindow m_VoipWnd;
Don't see what you're looking for? Try a search.
|