I'm totally new in COM programming.
I have big problem. I’m trying to handle events from CANoe application via COM Server. Firstly I tried do it in native C++ but without results. Now I’m trying it by using ATL. I'm doing something wrong but I don’t have any idea what. When the event occurs, my client application suspends itself and CANoe. After closing client application CANoe works fine. So I know that my client application handles Events from CANoe but it can’t serve it. The commented parts of code in my source code were also used but with the same results.
#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);
}
Here is description of Measurement Object and Event from OLE-COM object viewer:
[
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();
};
I attach CANoe.tlb: http://www.sendspace.com/file/j2zloj
Thank you for your attention Damian
STA
and you're doing while(1);
, however note that you are expected to implement a message pump on the thread (hint: a quick check if this is the reason is to show a message box instead of endless loop)SINK_ENTRY_INFO
and not SINK_ENTRY
as any tutorial would suggest?pMeasure->
call there; did you check if it freezes inside this call, or it returns a failure result (or the event handler is called on wrong thread).As console application has no Window (which handles events queue used by STA), you have either to call
CoInitializeEx(NULL,COINIT_MULTITHREADED);
to use MTA instead of STA
or implement Message pump
MSG msg;
while(GetMessage(&msg,0,0,0))
DispatchMessage(&msg);
I also had to add following code to stdafx.h to prevent crash in ATL classes:
class CDummyModule : public CAtlExeModuleT<CDummyModule> {};
CDummyModule _Module;
User contributions licensed under CC BY-SA 3.0