2012-09-14 51 views
1

我遵循了許多關於如何在C++中使用COM對象的詳細教程。我正在使用VS 2010 pro。我提出了一個名爲TestComInterop的新解決方案。製作了一個名爲TestMath的C#項目。通過選擇properties->Assembly Information->Make assembly COM-visible中的選項使其可見。然後我去簽名財產,簽署名爲MyMathCom.snk(無密碼)的大會。然後我使用GUID generator並製作了2個GUID。然後把這段代碼放到我的程序中並編譯。 (成功)在C++中使用託管的COM對象

using System.Runtime.InteropServices; 
namespace TestMath 
{ 
    [Guid("599AD473-B0A9-4A6E-B260-CF6FDEBF151B"),InterfaceType(ComInterfaceType.InterfaceIsDual)] 
    public interface IClass1 
    { 
     void AddNumbers(byte[] array); 
    } 
    [Guid("62FBC3A9-E2C0-4B53-9BF3-FDE22AA0CFF2"),ClassInterface(ClassInterfaceType.None)] 
    public class Class1 : IClass1 
    { 

     public void AddNumbers(byte[] array) 
     { 
      ulong number = 0; 
      foreach (var item in array) 
      { 
       number += item; 
      } 
      System.Console.WriteLine("The answer is {0}", number); 
      System.Windows.Forms.MessageBox.Show("DOrk"); 
     } 
    } 
} 

然後,我爲控制檯應用程序做了一個C++項目。允許MFC。

然後我添加了一個Typelib MFC類。我能夠使用下拉框找到TestMath<1.0>,它有我的iClass1。我選擇了,這讓頭文件對我來說

// Machine generated IDispatch wrapper class(es) created with Add Class from Typelib Wizard 

#import "C:\\Users\\rsny\\Desktop\\TestComInterop\\TestComInterop\\TestMath\\bin\\Debug\\TestMath.tlb" no_namespace 
// CClass1 wrapper class 

class CClass1 : public COleDispatchDriver 
{ 
public: 
    CClass1(){} // Calls COleDispatchDriver default constructor 
    CClass1(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {} 
    CClass1(const CClass1& dispatchSrc) : COleDispatchDriver(dispatchSrc) {} 

    // Attributes 
public: 

    // Operations 
public: 


    // IClass1 methods 
public: 
    void AddNumbers(SAFEARRAY * array) 
    { 
     static BYTE parms[] = {VTS_NONE} ; 
     InvokeHelper(0x60020000, DISPATCH_METHOD, VT_EMPTY, NULL, parms, array); 
    } 

    // IClass1 properties 
public: 

}; 

編譯,並取得了tlhtli文件我..成功..

那麼接下來最後一步是我的代碼運行。打開TestComInterop.cpp,這是我無法找到一個「標準」的做法。我已經嘗試了各種不同的東西,但不知道要放什麼......這是我爲

// TestComInterop.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include "TestComInterop.h" 
#include "CClass1.h" 

#ifdef _DEBUG 
#define new DEBUG_NEW 
#endif 


// The one and only application object 

CWinApp theApp; 

using namespace std; 

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 
{ 
    int nRetCode = 0; 

    HMODULE hModule = ::GetModuleHandle(NULL); 

    if (hModule != NULL) 
    { 
     // initialize MFC and print and error on failure 
     if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0)) 
     { 
      // TODO: change error code to suit your needs 
      _tprintf(_T("Fatal Error: MFC initialization failed\n")); 
      nRetCode = 1; 
     } 
     else 
     { 
      // TODO: code your application's behavior here. 
     } 
    } 
    else 
    { 
     // TODO: change error code to suit your needs 
     _tprintf(_T("Fatal Error: GetModuleHandle failed\n")); 
     nRetCode = 1; 
    } 
    CClass1* myMath = new CClass1; 
    myMath->CreateDispatch("62FBC3A9-E2C0-4B53-9BF3-FDE22AA0CFF2"); 
    //bool result = myMath. 
    if (myMath) 
     cout << "AWESOME" << endl; 
    else 
     cout << "LAME" << endl; 

    unsigned char numbers[5] = {0x01,0x02,0x03,0x04,0x05}; 
    myMath->AddNumbers((SAFEARRAY*)numbers); 
    delete myMath; 
    getchar(); 
    return nRetCode; 
} 

現在,我期待它粘貼回答我的控制檯代碼..但沒有。我也期待它顯示一個消息框......什麼也不是。至少可以說我在COM對象上是一個新手。到目前爲止,對於所有的工具等等,這並沒有太困難......但是對於我來說,我無法實現這個目標。

以防萬一需要這裏是我的tlhtli文件。

// Created by Microsoft (R) C/C++ Compiler Version 10.00.30319.01 (e323d9ba). 
// 
// c:\users\rsny\desktop\testcominterop\testcominterop\testcominterop\debug\testmath.tli 
// 
// Wrapper implementations for Win32 type library C:\\Users\\rsny\\Desktop\\TestComInterop\\TestComInterop\\TestMath\\bin\\Debug\\TestMath.tlb 
// compiler-generated file created 09/14/12 at 12:08:08 - DO NOT EDIT! 

#pragma once 

// 
// interface IClass1 wrapper method implementations 
// 

inline HRESULT IClass1::AddNumbers (SAFEARRAY * array) { 
    HRESULT _hr = raw_AddNumbers(array); 
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this)); 
    return _hr; 
} 

// Created by Microsoft (R) C/C++ Compiler Version 10.00.30319.01 (e323d9ba). 
// 
// c:\users\rsny\desktop\testcominterop\testcominterop\testcominterop\debug\testmath.tlh 
// 
// C++ source equivalent of Win32 type library C:\\Users\\rsny\\Desktop\\TestComInterop\\TestComInterop\\TestMath\\bin\\Debug\\TestMath.tlb 
// compiler-generated file created 09/14/12 at 12:08:08 - DO NOT EDIT! 

#pragma once 
#pragma pack(push, 8) 

#include <comdef.h> 

// 
// Forward references and typedefs 
// 

struct __declspec(uuid("d29ff1b5-bf10-4bbe-9bd9-cb5346f4bfaf")) 
/* LIBID */ __TestMath; 
struct __declspec(uuid("599ad473-b0a9-4a6e-b260-cf6fdebf151b")) 
/* dual interface */ IClass1; 
struct /* coclass */ Class1; 

// 
// Smart pointer typedef declarations 
// 

_COM_SMARTPTR_TYPEDEF(IClass1, __uuidof(IClass1)); 

// 
// Type library items 
// 

struct __declspec(uuid("599ad473-b0a9-4a6e-b260-cf6fdebf151b")) 
IClass1 : IDispatch 
{ 
    // 
    // Wrapper methods for error-handling 
    // 

    HRESULT AddNumbers (
     SAFEARRAY * array); 

    // 
    // Raw methods provided by interface 
    // 

     virtual HRESULT __stdcall raw_AddNumbers (
     /*[in]*/ SAFEARRAY * array) = 0; 
}; 

struct __declspec(uuid("62fbc3a9-e2c0-4b53-9bf3-fde22aa0cff2")) 
Class1; 
    // interface _Object 
    // [ default ] interface IClass1 

// 
// Wrapper method implementations 
// 

#include "c:\users\rsny\desktop\testcominterop\testcominterop\testcominterop\debug\testmath.tli" 

#pragma pack(pop) 

回答

2

我不知道你爲什麼用COleDispatchDriver派生類。

正如你所提到的.tlh/tli文件,我假設你已經導入了你的TLB文件。

因此,所有你需要使用它是這樣的(從頭部直寫,所以請忽略可能出現的錯誤):

// prepare values 
unsigned char numbers[] = {0x01,0x02,0x03,0x04,0x05}; 
SAFEARRAY* sa = SafeArrayCreateVector(VT_UI1, 0, 5); 
char* data; 
SafeArrayAccessData(sa, (void**)&data); 
memcpy(data, numbers, 5) 
SafeArrayUnaccessData(sa); 

// instantiate COM object and call the method 
IClass1Ptr obj(_uuidof(Class1)); 
obj->AddNumbers(sa); 

// clean up 
SafeArrayDestroy(sa); 

如果使用ATL,我建議使用CComSafeArray因爲它帶走了很多與SAFEARRAYs一起工作帶來的痛苦。

+1

以及你的代碼編譯:)但傷心的是我有一個訪問違規錯誤。它說CoInitialize尚未被調用。所以我要查找那個錯誤,看看它是什麼,並在一分鐘後再回來看看。感謝您的提示。我對SAFEARRAY位沒有任何線索。最後,我沒有做COleDispatchDriver,它是我使用類嚮導時創建的,並且是從typelib添加了一個新類。 –

+1

您需要在調用任何COM方法之前初始化COM。只需在應用程序的開始處調用'CoInitialize(NULL)'(例如'_tmain'開始) –