我想要做的是访问COM接口,然后调用该接口的“打开”方法。 我在Visual Basic中有一个示例代码可以正常工作,但我需要用C ++编写它,我似乎无法使它工作。
首先,这是有效的VB代码:
Dim CANapeApplication As CANAPELib.Application
CANapeApplication = CreateObject("CANape.Application")
Call CANapeApplication.Open("C:\Users\Public\Documents\Vector\CANape\12\Project", 0)
CANape.Application 是选择我需要的接口的ProgID。
在msdn.microsoft.com和this question阅读了一些文档后,我写了这段代码:
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 << "init error";
return 1;
}
// Open CANape
if (OpenCANape() != 0) {
std::cout << "Failed to open CANape Project" << 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)&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"), &ClassID);
hresult = CLSIDFromProgID(OLESTR("CanapeCom.CanapeCom"), &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 **)&pdisp);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// Call QueryInterface to see if object supports IDispatch
hresult = pdisp->QueryInterface(IID_IDispatch, (void **)&pdisp);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
std::cout << "success" << 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->GetIDsOfNames(
IID_NULL,
&szMember,
1,
LOCALE_SYSTEM_DEFAULT,
&idFileExists);
if (!SUCCEEDED(hresult)) {
std::cout << "GetIDsOfNames: ";
ErrorDescription(hresult);
return 1;
}
unsigned int puArgErr = 0;
VARIANT VarResult;
VariantInit(&VarResult);
DISPPARAMS pParams;
memset(&pParams, 0, sizeof(DISPPARAMS));
pParams.cArgs = 2;
VARIANT Arguments[2];
VariantInit(&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->Invoke(
dispid,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&pParams,
&VarResult,
NULL,
&puArgErr
);
SysFreeString(pParams.rgvarg[0].bstrVal);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
return 0;
}
这有几个问题。
CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);
中生成的CLSID作为 CoCreateInstance 的第4个参数,但这导致“没有支持此类界面”错误我需要软件的dll文件吗?在VB示例中,dll文件用于获取接口,然后使用ProgID创建新对象。我不确定我是否需要在C ++中做同样的事情或者它应该如何工作。
我真的被困在这里,希望有人可以帮助我。
答案 0 :(得分:1)
感谢您的评论。 我已经解决了这个问题,虽然解决方案有点令人尴尬...... 在我的辩护中,我仍然是一名学生并且对这种东西不熟悉。
我使用Process Monitor来检查执行VB脚本时会发生什么。
我看到那里使用的CLSID是CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);
返回的ID,这意味着这必须是正确的,问题必须在其他地方。我再次查看了 CoCreateInstance ,然后查看了其他参数。事实证明,上下文 CLSCTX_LOCAL_SERVER 是错误的,它必须是 CLSCTX_INPROC_SERVER 。我不知道为什么我首先将它设置为local_server,或者为什么我从未质疑过它。我几天前编写了部分代码,然后过分关注CLSID和IID而不是其他参数。
我还考虑了Alex的第一条评论并创建了一个tlb文件。
这是有效代码的简化版本:
#import "CANape.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
_bstr_t path = "C:\\Users\\Public\\Documents\\Vector\\CANape\\12\\Project";
CLSID idbpnt;
CoInitialize(NULL);
HRESULT hr = CLSIDFromProgID (L"CANape.Application", &idbpnt);
CANAPELib::IApplication *app;
hr = CoCreateInstance(idbpnt,NULL,CLSCTX_INPROC_SERVER,__uuidof(CANAPELib::IApplication),(LPVOID*)&app );
app->Open(path,0);
CoUninitialize();
return 0;
}