简体   繁体   English

使用CSExeCOMServer如何在VS C ++中接收事件

[英]Using CSExeCOMServer how do I receive the event in VS C++

Starting with Microsoft's C# .NET CSExeCOMserver (out of proc EXE) example - I have the following: 从Microsoft的C#.NET CSExeCOMserver(不包含proc EXE)示例开始-我具有以下内容:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;


namespace CSExeCOMServer
{
#region Interfaces

[Guid(CSSimpleObject.InterfaceId), ComVisible(true)]
public interface ICSSimpleObject
{
    #region Properties

    float FloatProperty { get; set; }

    #endregion

    #region Methods

    string HelloWorld();

    void GetProcessThreadID(out uint processId, out uint threadId);

    #endregion
}

[Guid(CSSimpleObject.EventsId), ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICSSimpleObjectEvents
{
    #region Events

    [DispId(1)]
    void FloatPropertyChanging(float NewValue, ref bool Cancel);

    #endregion
}

#endregion

[ComVisible(true)]
[Guid(CSSimpleObject.ClassId)]
[ClassInterface(ClassInterfaceType.None)]           // No ClassInterface
[ComSourceInterfaces(typeof(ICSSimpleObjectEvents))]
public class CSSimpleObject : ReferenceCountedObject, ICSSimpleObject
{
    #region COM Component Registration

    internal const string ClassId =
        "DB9935C1-19C5-4ed2-ADD2-9A57E19F53A3";
    internal const string InterfaceId =
        "941D219B-7601-4375-B68A-61E23A4C8425";
    internal const string EventsId =
        "014C067E-660D-4d20-9952-CD973CE50436";

    // These routines perform the additional COM registration needed by 
    // the service.

    [EditorBrowsable(EditorBrowsableState.Never)]
    [ComRegisterFunction()]
    public static void Register(Type t)
    {
        try
        {
            COMHelper.RegasmRegisterLocalServer(t);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message); // Log the error
            throw ex; // Re-throw the exception
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    [ComUnregisterFunction()]
    public static void Unregister(Type t)
    {
        try
        {
            COMHelper.RegasmUnregisterLocalServer(t);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message); // Log the error
            throw ex; // Re-throw the exception
        }
    }

    #endregion

    #region Properties

    private float fField = 0;

    public float FloatProperty
    {
        get { return this.fField; }
        set
        {
            bool cancel = false;
            // Raise the event FloatPropertyChanging
            if (null != FloatPropertyChanging)
                FloatPropertyChanging(value, ref cancel);
            if (!cancel)
                this.fField = value;
        }
    }

    #endregion

    #region Methods

    public string HelloWorld()
    {
        return "HelloWorld";
    }

    public void GetProcessThreadID(out uint processId, out uint threadId)
    {
        processId = NativeMethod.GetCurrentProcessId();
        threadId = NativeMethod.GetCurrentThreadId();
    }

    #endregion

    #region Events

    [ComVisible(false)]
    public delegate void FloatPropertyChangingEventHandler(float NewValue, ref bool Cancel);
    public event FloatPropertyChangingEventHandler FloatPropertyChanging;

    #endregion
}

/// <summary>
/// Class factory for the class CSSimpleObject.
/// </summary>
internal class CSSimpleObjectClassFactory : IClassFactory
{
    public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, 
        out IntPtr ppvObject)
    {
        ppvObject = IntPtr.Zero;

        if (pUnkOuter != IntPtr.Zero)
        {
            // The pUnkOuter parameter was non-NULL and the object does 
            // not support aggregation.
            Marshal.ThrowExceptionForHR(COMNative.CLASS_E_NOAGGREGATION);
        }

        if (riid == new Guid(CSSimpleObject.ClassId) ||
            riid == new Guid(COMNative.IID_IDispatch) ||
            riid == new Guid(COMNative.IID_IUnknown))
        {
            // Create the instance of the .NET object
            ppvObject = Marshal.GetComInterfaceForObject(
                new CSSimpleObject(), typeof(ICSSimpleObject));
        }
        else
        {
            // The object that ppvObject points to does not support the 
            // interface identified by riid.
            Marshal.ThrowExceptionForHR(COMNative.E_NOINTERFACE);
        }

        return 0;   // S_OK
    }

    public int LockServer(bool fLock)
    {
        return 0;   // S_OK
    }
}

/// <summary>
/// Reference counted object base.
/// </summary>
[ComVisible(false)]
public class ReferenceCountedObject
{
    public ReferenceCountedObject()
    {
        // Increment the lock count of objects in the COM server.
        ExeCOMServer.Instance.Lock();
    }

    ~ReferenceCountedObject()
    {
        // Decrement the lock count of objects in the COM server.
        ExeCOMServer.Instance.Unlock();
    }
}
}

The above registers and I output a test.tlb file just fine - I have a COM client that uses the above COM Server in standard visual C++ as follows: 上面的寄存器,我输出了一个test.tlb文件-我有一个COM客户端,它在标准的Visual C ++中使用上面的COM服务器,如下所示:

#include "stdafx.h"
#include <objbase.h>
#include <comutil.h>

#import <C:\Users\ndavis\Documents\Visual Studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\test.tlb> no_namespace named_guids

int _tmain(int argc, _TCHAR* argv[])
{

ULONG procID;
ULONG threadID;

//initialize COM for this thread
//HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HRESULT hr = CoInitialize(NULL);

ICSSimpleObjectPtr pSimple_1;
hr = pSimple_1.CreateInstance(CLSID_CSSimpleObject, NULL, CLSCTX_LOCAL_SERVER);
_bstr_t hw_response = pSimple_1->HelloWorld();
_bstr_t testID = pSimple_1->GetProcessThreadID(&procID, &threadID);

pSimple_1->FloatProperty = 1.7f;

CoUninitialize();

    return 0;

}

All the above works: pSimple_1->HelloWorld(); 以上所有工作:pSimple_1-> HelloWorld(); returns correct response, pSimple_1->GetProcessThreadID(...) returns correct response; 返回正确的响应,pSimple_1-> GetProcessThreadID(...)返回正确的响应; and pSimple_1->FloatProperty = 1.7f sets the FloatProperty correctly. 并且pSimple_1-> FloatProperty = 1.7f可以正确设置FloatProperty。

QUESTION: How do I receive the FloatPropertyChanging(float value, bool* cancel) event in my visual C++ client code above? 问题:如何在上面的可视C ++客户端代码中接收FloatPropertyChanging(浮点值,布尔值*取消)事件? (please no ATL). (请不要使用ATL)。

Thanks 谢谢

Additional information that has gotten me a little farther - I have added the following to my code: 使我走得更远的其他信息-我在代码中添加了以下内容:

Adding the following class to my client: 将以下类添加到我的客户端:

class EventHandler : public ICSSimpleObjectEvents
{

public:
EventHandler(void) { }
~EventHandler(void) { }

HRESULT __stdcall QueryInterface(const IID &, void **);
ULONG __stdcall AddRef(void) { return 1; }
ULONG __stdcall Release(void) { return 1; }

virtual HRESULT __stdcall GetTypeInfoCount(UINT * pTypeInfoCount) { return -1; }
virtual HRESULT __stdcall GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return -1; }
virtual HRESULT __stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return -1; }
virtual HRESULT __stdcall Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { return -1; }

virtual HRESULT __stdcall raw_FloatPropertyChanging(float x, VARIANT_BOOL * cancel) { return -1; }

HRESULT __stdcall FloatPropertyChanging(float NewValue, bool *Cancel);
};

HRESULT __stdcall EventHandler::FloatPropertyChanging(float NewValue, bool *Cancel) {
printf("float value changing: NewValue = %f", NewValue);
return S_OK;
}

HRESULT __stdcall EventHandler::QueryInterface(const IID &iid, void **pp) {

if(iid == __uuidof(ICSSimpleObjectEvents) || iid == __uuidof(IUnknown) || iid == __uuidof(IDispatch))
{
    *pp = this;
    AddRef();
    return S_OK;
}
return E_NOINTERFACE;
}

And adding the following to get IConnectionPoint: 并添加以下内容以获得IConnectionPoint:

IUnknown *pUnk = NULL;

hr = CoCreateInstance(CLSID_CSSimpleObject, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnk);

IConnectionPointContainerPtr pContainer;
IConnectionPointPtr pConnection;
hr = pUnk->QueryInterface(__uuidof(IConnectionPointContainer), (void**) &pContainer);
hr = pContainer->FindConnectionPoint(__uuidof(ICSSimpleObjectEvents), (IConnectionPoint**) &pConnection);


EventHandler* pSink = new EventHandler;

DWORD dwAdviseCookie;

hr = pConnection->Advise((IUnknown*)pSink, &dwAdviseCookie);

pSimple_1->FloatProperty = 1.7f;

Setting a break point in the C# .NET COM Server at: 在以下位置的C#.NET COM服务器中设置断点:

    public float FloatProperty
    {
        get { return this.fField; }
        set
        {
            bool cancel = false;   <--- I set break point here
            // Raise the event FloatPropertyChanging
            if(FloatPropertyChanging != null)  <--- FloatPropertyChanging is null here?
                FloatPropertyChanging(value, ref cancel);
            if (!cancel)
                this.fField = value;
        }
    }

I see that FloatPropertyChanging is null so therefore FloatPropertyChanging(...) is never called? 我看到FloatPropertyChanging为null,所以从不调用FloatPropertyChanging(...)? Anybody see what I am doing wrong? 有人看到我在做什么错吗?

The sample documentation specifically calls for the event interface to be dispatch-only: 示例文档专门要求事件接口仅可调度:

在此处输入图片说明

But in your code you have made it a dual interface. 但是在您的代码中,您将其设为双重接口。

[Guid(CSSimpleObject.EventsId), ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICSSimpleObjectEvents

I also don't see an implementation of Invoke in your C++ client code. 我还没有在您的C ++客户端代码中看到Invoke的实现。 Well, I do. 好吧,我知道。 It's a badly broken one. 这是一个严重损坏的。

I strongly suggest you try implementing the events through IDispatch because that's how the sample instructs to do it. 我强烈建议您尝试通过IDispatch实现事件,因为这就是该示例指示的方式。 You can probably keep the dual interface and use DispInvoke to automatically implement IDispatch::Invoke in terms of the v-table. 您可能可以保留双接口,并使用DispInvoke根据v表自动实现IDispatch::Invoke

At an absolute minimum, put a breakpoint inside your empty implementation of Invoke and see if that gets hit when the event is fired. 在您的Invoke空实现中放一个断点,以查看是否在触发事件时命中断点。

Also, for example this sample (not .NET) also instructs that IDispatch should be used for the event source/sink. 同样,例如, 此示例(不是.NET)还指示IDispatch应该用于事件源/接收器。

you need to implement Invoke in your C++ client code, something like... 您需要在C ++客户端代码中实现Invoke,类似...

class EventHandler : public ICSSimpleObjectEvents
{

public:
EventHandler(void) { }
~EventHandler(void) { }

HRESULT __stdcall QueryInterface(const IID &, void **);
ULONG __stdcall AddRef(void) { return 1; }
ULONG __stdcall Release(void) { return 1; }

virtual HRESULT __stdcall GetTypeInfoCount(UINT * pTypeInfoCount) { return -1; }
virtual HRESULT __stdcall GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return -1; }
virtual HRESULT __stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return -1; }
virtual HRESULT __stdcall Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr);

virtual HRESULT __stdcall raw_FloatPropertyChanging(float x, VARIANT_BOOL * cancel) { return -1; }

HRESULT __stdcall FloatPropertyChanging(float NewValue, bool *Cancel);
};

HRESULT __stdcall EventHandler::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, 
    EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
    // The riid parameter is always supposed to be IID_NULL
    if (riid != IID_NULL)
        return DISP_E_UNKNOWNINTERFACE;

    if (pdispparams) //DISPID dispIdMember
    {
        float NewValue;
        bool * pCancel;

        switch (dispidMember) {
            case 1:
                NewValue = pdispparams->rgvarg[1].fltVal;
                pCancel = (bool *)pdispparams->rgvarg[0].pboolVal;
                return FloatPropertyChanging(NewValue, pCancel);

            default:
                return E_NOTIMPL;
        }
    } else return E_NOTIMPL;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在C ++ / CLI中为事件分配事件处理程序? - How do I assign an event handler to an event in C++/CLI? 当鼠标指针不在窗口中时,如何接收MouseWheel事件? - How do I receive the MouseWheel event when mouse pointer is not in the window? 我如何在 webBrowser 中使用 c# 执行点击事件 - how i do perform click event using c# in webBrowser 如何使用C#监听ArcMap中的TimeSlider事件 - How do I listen for TimeSlider Event in ArcMap using C# 如何使用C#从Arduino接收串行数据包? - How do I receive serial packet from Arduino using C#? 如何为lamda函数创建VS C#项目以处理Amazon IoT开发人员按钮事件? - How do I create a VS C# project for a lamda function to handle a Amazon IoT developer button event? VS2010 - 如何获取c#的控制事件处理程序定义 - VS2010 - How do I get control event handler definitions for c# 如何创建手动重置事件,该事件仅允许访问C ++中的特定用户帐户? - How do I create a manual reset event that only allows access to particular user accounts in C++? 如何在C#中接收和存储输入的数据? - How do I receive and store data input in C#? 我如何在c#中参数化事件 - how do I parameterize an event, in c#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM