How do I run a COM (.ocx) object in a C++ command line interface program. (VS2017)
After many hours of research I have the following. I think the COM object is loading as trio is populated. But I do not know how to run it successfully. It may need to be attached to a CWND or something.
I have this code, which may be the wrong rabbit hole. It crashes horribly.
HRESULT hr;
hr = CoInitialize(0);
assert(SUCCEEDED(hr));
{
static CLSID const clsid
= { 0xf1933967, 0x74b0, 0x11d3,{ 0x8a, 0x13, 0x0, 0x40, 0x33, 0x93, 0xb2, 0x36 } };
//CLSID ClassID;
//hr = CLSIDFromProgID(OLESTR("TrioPCLib.TrioPC"), &ClassID);
assert(SUCCEEDED(hr));
TrioPCLib::_DTrioPCPtr trio;
IID iid = TrioPCLib::_DTrioPCPtr::GetIID();
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, reinterpret_cast<void**>(&trio));
assert(SUCCEEDED(hr));
trio->Release();
}
CoUninitialize();
The COM object has GUI which I do not need to use it. I just want to call the API.
UPDATE: The ActiveX is loaded and I can call, for example, AboutBox() and it is displayed. It crashes on the CoUninitialize() with an exception...
Unhandled exception at 0x779CA899 (ntdll.dll) in TestVpu.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77A05910).
I'd be willing to bet that the exception is actually happening at the close brace, not the CoUninitialize
call. It looks like you might be releasing the COM object twice, once explicitly and once implicitly.
You are explicitly calling trio->Release()
. You are also using a TrioPCLib::_DTrioPCPtr
, which is probably a COM smart pointer produced by the Visual C++ compiler encountering an #import
. This class automatically calls Release
on the referenced object when it goes out of scope.
You should either use a TrioPCLib::_DTrioPC*
or you should not call trio->Release()
. (FWIW: I would prefer to use TrioPCLib::_DTrioPCPtr
and not explicitly call trio->Release()
.)
The following appears to be much more stable. It uses pointers and calls the Release. The import has some extra params. The import generates code that you can look at. The class is derived from IDispatch and calls are made using _com_dispatch_method(). Up to now I have not needed to worry about a message pump.
#include "stdafx.h"
#include <iostream>
using namespace std;
#import "C:/Users/*****/Documents/Trio Motion Solutions/TrioMCTools/Debug/Win32/TrioPC.ocx" named_guids no_namespace
int main(int, char**)
{
CoInitialize(0);
{
bool inOK = false;
int length = 3;
_DTrioPC* pitd = 0;
HRESULT hr = CoCreateInstance(CLSID_TrioPC, 0, CLSCTX_ALL, DIID__DTrioPC, reinterpret_cast<void**>(&pitd));
if (SUCCEEDED(hr)) cout << "ok" << endl; else cout << "nok" << endl;
pitd->SetHost("192.168.0.250");
bool openOK = pitd->Open(2, 0);
if (openOK) cout << "ok" << endl; else cout << "nok" << endl;
SAFEARRAY *data = SafeArrayCreateVectorEx(VT_R8, 0, length, NULL);
if (data)
{
double *safe_data;
hr = SafeArrayAccessData(data, (void **)&safe_data);
if (SUCCEEDED(hr))
{
int i;
for (i = 0; i < length; i++)
safe_data[i] = i+532;
SafeArrayUnaccessData(data);
VARIANT arg;
VariantInit(&arg);
arg.vt = VT_ARRAY | VT_R8;
arg.parray = data;
inOK = pitd->SetTable(1000, 3, &arg);
}
}
pitd->Release();
}
CoUninitialize();
return 0;
}
User contributions licensed under CC BY-SA 3.0