Использование управляемого COM-объекта в Stack Overflow

Я следовал за несколькими подробными уроками о том, как использовать COM-объект в C ++. Я использую VS 2010 Pro. Я сделал новое решение под названием TestComInterop, Сделал проект на C # под названием TestMath, Сделайте это видимым, выбрав опцию в properties->Assembly Information->Make assembly COM-visible, Я тогда пошел в собственность Подписи, подписал Ассамблею под названием MyMathCom.snk (без пароля). Затем я использовал GUID generator и сделал 2 GUID. Затем поместите этот код в мою программу и скомпилируйте. (Успех)

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 ++ для консольного приложения. Разрешено МФЦ.

Затем я добавил 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:

};

скомпилирован, и это сделало tlh а также tli файлы для меня .. успех ..

Итак, последний шаг — запустить мой код. Открыл 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-объектов. Пока что сделать это не так уж сложно со всеми инструментами и так далее … но я не могу заставить это работать.

На всякий случай вот мои tlh а также tli файлы.

// 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)

1

Решение

Я не знаю, почему вы используете 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.

2

Другие решения

Других решений пока нет …