0

私がやりたいことは、COM インターフェイスにアクセスして、そのインターフェイスの " Open " メソッドを呼び出すことです。正常に動作する 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 でいくつかのドキュメントとこの質問を読んだ後、次のコードを書きました。

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から受け取った ClassID をCoCreateInstanceの最初のパラメーターとして使用しても機能せず、次のエラーが返されます:クラスが登録されていません
  • ProgID CanapeCom.CanapeCom (レジストリを調べて見つけた) を使用すると、CoCreateInstanceが機能します。ただし、pdisp->GetIDsOfNamesを使用すると、次のエラー メッセージが表示されます: Unkown name。これは、メソッドが見つからなかったことを意味すると思います。私は別の ProgID を使用しているので、これは論理的に思えますが、探しているインターフェイスにアクセスする方法がわかりません。
  • また、結果の CLSIDをCoCreateInstanceCLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);の 4 番目の引数として使用しようとしましたが、「そのようなインターフェイスはサポートされていません」というエラーが発生しました。

ソフトウェアのdllファイルは必要ですか? VB の例では、dll ファイルを使用してインターフェイスを取得し、ProgID を使用して新しいオブジェクトを作成します。C ++で同じことをする必要があるのか​​ 、それともこれがどのように機能するのかわかりません。

私は本当にここで立ち往生しており、誰かが私を助けてくれることを願っています.

4

1 に答える 1

1

コメントしてくれてありがとう。私は問題を解決しましたが、解決策はちょっと恥ずかしいです... 私の弁護では、私はまだ学生で、この種のものは初めてです。

Process Monitor を使用して、VB スクリプトを実行したときに何が起こるかを確認しました。そこで使用されている CLSID は によって返された ID であることがわかりました。つまり、CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);これは正しいものである必要があり、問題は別の場所にあるはずです。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; 
}
于 2013-08-20T23:19:25.220 に答える