Как обрабатывать события COM в консольном приложении с помощью ATL - приостановки клиента - PullRequest
1 голос
/ 03 декабря 2011

Я абсолютно новичок в программировании COM.

У меня большая проблема.Я пытаюсь обрабатывать события из приложения CANoe через COM-сервер.Сначала я попытался сделать это на родном 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 ]

1 голос
/ 03 декабря 2011
  1. Вы инициализируете STA, и вы делаете while(1);, однако обратите внимание, что вы должны внедрить насос сообщений в потоке (подсказка: быстрая проверка, если это причина, чтобы показатьокно сообщения вместо бесконечного цикла)
  2. Почему SINK_ENTRY_INFO, а не SINK_ENTRY, как подсказывает любой учебник?
  3. Был ли у вас шанс увидеть, выполняется ли обработчик события, и ондостиг pMeasure-> звоните туда;Вы проверили, зависает ли он внутри этого вызова, или возвращает результат сбоя (или обработчик события вызывается не в том потоке).
0 голосов
/ 14 сентября 2017

Поскольку консольное приложение не имеет 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;
...