如何使用ATL处理控制台应用程序中的COM事件 - 客户端的暂停

时间:2011-12-03 07:48:20

标签: events visual-c++ com atl com-server

我是COM编程的新手。

我有很大的问题。我正在尝试通过COM Server处理来自CANoe应用程序的事件。首先,我尝试用原生C ++做但没有结果。现在我正在尝试使用ATL。我做错了什么,但我不知道是什么。当事件发生时,我的客户端应用程序暂停自身和CANoe。关闭客户端应用程序后CANoe工作正常。所以我知道我的客户端应用程序处理来自CANoe的事件但它无法提供服务。我的源代码中的代码注释部分也被使用但结果相同。

#import "CANoe.tlb" //importing CANoe type library
#include "stdafx.h"
#include <atlbase.h> //COM Server methods
#include <iostream>
#include <atlhost.h>

using namespace CANoe;
using namespace std;

_ATL_FUNC_INFO infoZero = { CC_STDCALL, VT_EMPTY, 0, 0};
_ATL_FUNC_INFO infoOne = { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };

class CANoeComClient : 
    //IDispEventSimpleImpl<1, CANoeComClient, &__uuidof(_IMeasurementEvents)>,
    //IDispEventSimpleImpl<2, CANoeComClient, &__uuidof(_IEnvironmentVariableEvents)>
    IDispEventSimpleImpl<1, CANoeComClient, &__uuidof(_IApplicationEvents)>
{
    IApplicationPtr pApp; //Pointer to the Application Object
    IMeasurementPtr pMeasure; //Pointer to the Measurement object
    _IMeasurementEventsPtr pMEvent; //Pointer to the Measurement's Events
    IEnvironmentPtr pEnvironment; //Pointer to the Environment Object
    IEnvironmentVariable2Ptr pEnvironmentVar; //Pointer to the Environment Variable Object
    ICAPL2Ptr pCAPL; //Pointer to the CAPL Object
    CLSID clsid; //globally unique identifier that identifies a COM class object
    HRESULT result; //results of COM functions

public:
    //typedef IDispEventSimpleImpl<2, CANoeComClient, &__uuidof(CANoe::_IEnvironmentVariableEvents)> EnvVarEventsHandler;
    //typedef IDispEventSimpleImpl<1, CANoeComClient, &__uuidof(CANoe::_IMeasurementEvents)> MeasurementEventsHandler;  
    typedef IDispEventSimpleImpl<1, CANoeComClient, &__uuidof(CANoe::_IApplicationEvents)> ApplicationEventsHandler;
    void __stdcall OnStart(void);
    void __stdcall OnStop(void);
    void __stdcall OnOpen(void);
    void __stdcall OnQuit(void);

    BEGIN_SINK_MAP(CANoeComClient)
        //SINK_ENTRY_INFO(1, __uuidof(CANoe::_IMeasurementEvents), 0x02, OnStart, &info)
        //SINK_ENTRY_INFO(1, __uuidof(CANoe::_IMeasurementEvents), 0x03, OnStop, &infoZero)
        SINK_ENTRY_INFO(1, __uuidof(CANoe::_IApplicationEvents), 0x01, OnOpen, &infoZero)
        SINK_ENTRY_INFO(1, __uuidof(CANoe::_IApplicationEvents), 0x02, OnQuit, &infoZero)
    END_SINK_MAP()

    void __stdcall OnChange();
/*
    BEGIN_SINK_MAP(CANoeComClient)
        SINK_ENTRY_INFO(2, __uuidof(CANoe::_IEnvironmentVariableEvents), 0x01, OnChange, &info)
    END_SINK_MAP()*/

    CANoeComClient(_bstr_t configPath);
    HRESULT createEventConnection();
    HRESULT startMeasurement();
    HRESULT stopMeasurement();
};
void CANoeComClient::OnStart()
{
    cout << "kurka wodna 1" << endl;
}
void CANoeComClient::OnStop()
{
    cout << "kurka wodna 2" << endl;
}
void CANoeComClient::OnChange()
{
    cout << "kurka wodna 2" << endl;
}
void CANoeComClient::OnOpen()
{
    cout << "kurka wodna 1" << endl;
}
void CANoeComClient::OnQuit()
{
    cout << "kurka wodna 1" << endl;
}
CANoeComClient::CANoeComClient(_bstr_t configPath)
{
    /* Initialization COM library: */
    if (FAILED(CoInitialize(NULL))) 
    {
        cerr << "Initialization COM Library error" << endl;
        system("pause");
        return;
    }

    /* Actualization clsid variable with CANoe.Application path: */
    if((result = CLSIDFromProgID(L"CANoe.Application", &clsid)) != S_OK) 
    {
        cerr << "Problem with opening application" << endl;
        system("pause");
        return;
    }

    /*Opening CANoe application: */
    result = pApp.CreateInstance(__uuidof(CANoe::Application));
    if(result != S_OK)
    {
        cerr << "pApp fault" << endl;
        return;
    }
    else
        cout << "CANoe opened succesfully" << endl;

    /* Opening CANoe configuration: */
    result = pApp->Open(configPath, FALSE, TRUE); //Opening test.cfg file
    if(result != S_OK)
    {
        cerr << "Opening configuration fault" << endl;
        return;
    }
    else 
        cout << "Configuration loaded succesfully" << endl;

    /*Definitions of all objects: */
    //pMeasure.CreateInstance(__uuidof(CANoe::Measurement));
    pEnvironment = pApp->Environment;
    pEnvironmentVar = pEnvironment->GetVariable(L"env_ClientReq");
    pCAPL = pApp->CAPL;
    result = ApplicationEventsHandler::DispEventAdvise(pApp);
//  result = MeasurementEventsHandler::DispEventAdvise(pMeasure);
    //result = EnvVarEventsHandler::DispEventAdvise(pEnvironmentVar);
    if(result != S_OK)
    {
        cerr << "Creating connection fault" << endl;
        return;
    }
    else 
        cout << "Creating conenction succesfully" << endl;
}

HRESULT CANoeComClient::startMeasurement()
{
    return pMeasure->Start();
}

HRESULT CANoeComClient::stopMeasurement()
{
    return pMeasure->Stop();
}

int _tmain(int argc, _TCHAR* argv[])
{
    int tmp = 0; //temporary variable to used to get envVar values
    HRESULT result; //results of COM functions
    CANoeComClient client(L"C:\\test\\test.cfg");
    while(1);
}

以下是来自OLE-COM对象查看器的测量对象和事件的描述:

[
  uuid(CD866FB6-44BF-11D3-8538-00105A3E017B),
  helpstring("Measurement Class")
]
coclass Measurement {
    [default] interface IMeasurement2;
    [default, source] dispinterface _IMeasurementEvents;
};

 [
  odl,
  uuid(A844C1E0-F5CE-11D3-8612-00105A3E017B),
  helpstring("IMeasurement2 Interface"),
  dual,
  oleautomation
]
interface IMeasurement2 : IMeasurement {
    [id(0x0000000a), propget, helpstring("property Running")]
    HRESULT Running([out, retval] VARIANT_BOOL* pVal);
};

[
  uuid(A844C1E0-F5CE-11D3-8612-00105A3E017B),
  helpstring("IMeasurement2 Interface"),
  dual
]
dispinterface IMeasurement2 {
    properties:
    methods:
        [id(0x00000001), propget, helpstring("property Application")]
        IDispatch* Application();
        [id(0x00000002), propget, helpstring("property Parent")]
        IDispatch* Parent();
        [id(0x00000003), helpstring("method Start")]
        void Start();
        [id(0x00000004), helpstring("method Stop")]
        void Stop();
        [id(0x00000005), helpstring("method Step")]
        void Step();
        [id(0x00000006), helpstring("method Animate")]
        void Animate();
        [id(0x00000007), helpstring("method Break")]
        void Break();
        [id(0x00000008), helpstring("method Reset")]
        void Reset();
        [id(0x00000009), propget, helpstring("property AnimationDelay")]
        long AnimationDelay();
        [id(0x00000009), propput, helpstring("property AnimationDelay")]
        void AnimationDelay([in] long rhs);
        [id(0x0000000a), propget, helpstring("property Running")]
        VARIANT_BOOL Running();
};

[
  uuid(CD866FB7-44BF-11D3-8538-00105A3E017B),
  helpstring("_IMeasurementEvents Interface")
]
dispinterface _IMeasurementEvents {
    properties:
    methods:
        [id(0x00000001), helpstring("method OnInit")]
        HRESULT OnInit();
        [id(0x00000002), helpstring("method OnStart")]
        HRESULT OnStart();
        [id(0x00000003), helpstring("method OnStop")]
        HRESULT OnStop();
        [id(0x00000004), helpstring("method OnExit")]
        HRESULT OnExit();
};

我附上了CANoe.tlb:http://www.sendspace.com/file/j2zloj

感谢您的关注 达米安

2 个答案:

答案 0 :(得分:1)

  1. 您正在初始化STA并且您正在执行while(1);,但请注意,您应该在线程上实现消息泵(提示:快速检查是否这是显示的原因)消息框而不是无限循环)
  2. 为什么SINK_ENTRY_INFO而不是SINK_ENTRY,正如任何教程所暗示的那样?
  3. 您是否有机会查看事件处理程序是否已执行,并且已在此处调用pMeasure->;你检查它是否在此调用中冻结,或者它返回失败结果(或者在错误的线程上调用事件处理程序)。

答案 1 :(得分:0)

由于控制台应用程序没有Window(处理STA使用的事件队列),因此您需要调用

CoInitializeEx(NULL,COINIT_MULTITHREADED); 

使用MTA而不是STA

或实施消息泵

MSG msg;
while(GetMessage(&msg,0,0,0))
  DispatchMessage(&msg);  

我还必须将以下代码添加到stdafx.h以防止ATL类崩溃:

class CDummyModule : public CAtlExeModuleT<CDummyModule> {};
CDummyModule _Module;