Note that there are some explanatory texts on larger screens.

plurals
  1. POProblems accessing a COM interface in C++
    primarykey
    data
    text
    <p>What I want to do is access a COM interface and then call the "<strong>Open</strong>" method of that interface. I have a sample code in Visual Basic which works fine, but I need to write it in C++ and I can't seem to get it to work.</p> <p>First of all, this is the working VB code:</p> <pre><code>Dim CANapeApplication As CANAPELib.Application CANapeApplication = CreateObject("CANape.Application") Call CANapeApplication.Open("C:\Users\Public\Documents\Vector\CANape\12\Project", 0) </code></pre> <p><strong>CANape.Application</strong> is the ProgID which selects the interface I need.</p> <p>After reading some docs at msdn.microsoft.com and <a href="https://stackoverflow.com/questions/2313432/how-to-retrieve-the-interface-id-of-a-com-class-so-that-it-can-be-passed-to-cocr">this question</a>, I wrote this code: </p> <pre><code>void ErrorDescription(HRESULT hr); //Function to output a readable hr error int InitCOM(); int OpenCANape(); // Declarations of variables used. HRESULT hresult; void **canApeAppPtr; IDispatch *pdisp; CLSID ClassID; DISPID FAR dispid; UINT nArgErr; OLECHAR FAR* canApeWorkingDirectory = L"C:\\Users\\Public\\Documents\\Vector\\CANape\\12\\Project"; int main(){ // Instantiate CANape COM interface if (InitCOM() != 0) { std::cout &lt;&lt; "init error"; return 1; } // Open CANape if (OpenCANape() != 0) { std::cout &lt;&lt; "Failed to open CANape Project" &lt;&lt; std::endl; return 1; } CoUninitialize(); return 0; } void ErrorDescription(HRESULT hr) { if(FACILITY_WINDOWS == HRESULT_FACILITY(hr)) hr = HRESULT_CODE(hr); TCHAR* szErrMsg; if(FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&amp;szErrMsg, 0, NULL) != 0) { _tprintf(TEXT("%s"), szErrMsg); LocalFree(szErrMsg); } else _tprintf( TEXT("[Could not find a description for error # %#x.]\n"), hr); } int InitCOM() { // Initialize OLE DLLs. hresult = OleInitialize(NULL); if (!SUCCEEDED(hresult)) { ErrorDescription(hresult); return 1; } // Get CLSID from ProgID //hresult = CLSIDFromProgID(OLESTR("CANape.Application"), &amp;ClassID); hresult = CLSIDFromProgID(OLESTR("CanapeCom.CanapeCom"), &amp;ClassID); if (!SUCCEEDED(hresult)) { ErrorDescription(hresult); return 1; } // OLE function CoCreateInstance starts application using GUID/CLSID hresult = CoCreateInstance(ClassID, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&amp;pdisp); if (!SUCCEEDED(hresult)) { ErrorDescription(hresult); return 1; } // Call QueryInterface to see if object supports IDispatch hresult = pdisp-&gt;QueryInterface(IID_IDispatch, (void **)&amp;pdisp); if (!SUCCEEDED(hresult)) { ErrorDescription(hresult); return 1; } std::cout &lt;&lt; "success" &lt;&lt; std::endl; return 0; } int OpenCANape() { //Method name OLECHAR *szMember = L"Open"; // Retrieve the dispatch identifier for the Open method // Use defaults where possible DISPID idFileExists; hresult = pdisp-&gt;GetIDsOfNames( IID_NULL, &amp;szMember, 1, LOCALE_SYSTEM_DEFAULT, &amp;idFileExists); if (!SUCCEEDED(hresult)) { std::cout &lt;&lt; "GetIDsOfNames: "; ErrorDescription(hresult); return 1; } unsigned int puArgErr = 0; VARIANT VarResult; VariantInit(&amp;VarResult); DISPPARAMS pParams; memset(&amp;pParams, 0, sizeof(DISPPARAMS)); pParams.cArgs = 2; VARIANT Arguments[2]; VariantInit(&amp;Arguments[0]); pParams.rgvarg = Arguments; pParams.cNamedArgs = 0; pParams.rgvarg[0].vt = VT_BSTR; pParams.rgvarg[0].bstrVal = SysAllocString(canApeWorkingDirectory); pParams.rgvarg[1].vt = VT_INT; pParams.rgvarg[1].intVal = 0; // debug mode // Invoke the method. Use defaults where possible. hresult = pdisp-&gt;Invoke( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &amp;pParams, &amp;VarResult, NULL, &amp;puArgErr ); SysFreeString(pParams.rgvarg[0].bstrVal); if (!SUCCEEDED(hresult)) { ErrorDescription(hresult); return 1; } return 0; } </code></pre> <p>There are several problems with this. </p> <ul> <li>Using the ClassID received from <strong>CLSIDFromProgID</strong> as the first parameter of <strong>CoCreateInstance</strong> does not work, it returns the error: <strong>class not registered</strong></li> <li>If i use the ProgID <strong>CanapeCom.CanapeCom</strong> (I found it by looking in the Registry), <strong>CoCreateInstance</strong> works. However, when I use <strong>pdisp->GetIDsOfNames</strong> I get the error message: <strong>Unkown name</strong>. Which I think means that the method was not found. That seems logical because I've used a different ProgID, but I just can't figure out how to get to the interface I'm looking for.</li> <li>I have also tried to use the resulting CLSID from <code>CLSIDFromProgID(OLESTR("CANape.Application"), &amp;ClassID);</code> as the 4th argument of <strong>CoCreateInstance</strong> but that resulted in a <strong>"No such interface supported"</strong> error.</li> </ul> <p>Do I need the dll file of the software? In the VB example the dll file is used to get the interface and then create a new object using the ProgID. I'm not sure if I need to do the same in C++ or how this should work.</p> <p>I'm really stuck here and hope that someone can help me.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload