Ich sah mich in der letzten Woche damit konfrontiert, dass ich aus einer bestehenden unmanged C++ Anwenundung eine C# DLL aufrufen sollte, die wiederum auf einen Webservice zugreifen sollte. Ich habe für das Problem folgende Lösung gefunden:
Man kann aus C++ C# Komponenten aufrufen und diese verwenden. Im einfachsten Fall kann eine C# Komponente als COM Komponente realisiert werden. Auf diese Com-Komponente kann dann C++ zugreifen. Folgende Schritte sind hierfür notwendig:
Der C# Client
- In der C# Klasse ein Interface mit Funktionen für die Komponente erstellen
- Klasse realisieren, die das Interface erfüllt
- Klasse und Interface müssen ab VS05 als COM-Visible deklariert werden
- Der Klasse, die das Interface erfüllt muss zusätzlich den Interface Typen deklareien
- Damit Schnittstelle und realisierte Klasse im System eindeutig identifiziert werden können, werden diese mit einer GUID versehen.
-
Damit die Klassen auch sichtbar in COM sind, muss man für das Erstellen “Für COM Interop regestrieren” aktivieren
-
Meine Erfahrungen zeigen, dass bei der ersten Erstellung die tlb Datei nicht erstellt wird und die Kompoente nicht registriert wird, fesewgen muss diese manuell durch geführt werden
- Tlbexp XmlaService.dll
- regasm XmlaService.dll /tlb:com.XmlaService.tlb
Beispielhafte Realisierung:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace XmlaService
{
[ComVisible(true)]
[Guid("6F032C1C-B862-40dc-9DD2-78ADA8303176")]
public interface IDoService
{
string PerformRequest();
}
[ComVisible (true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("D4C231A6-1DFD-4add-8039-5B84A0BF0C40")]
public class DoXmlaService:IDoService
{
public DoXmlaService()
{ }
public string PerformRequest()
{
return "JUHU";
}
}
}
Ansprechen der Komponente in unmanged C++
- Die C++ KLasse muss einen Verweis auf den genauen Pfad der tlb-Datei besitzen
- Zusätzlich müssen noch die Argumente für den Inmport übergeben werden, einen Überblick gibt es unter http://msdn2.microsoft.com/en-us/library/8etzzkb6(VS.80).aspx
-
Den Aufruf der Komponente muss immer einzeln erfolgen
- Ebenfalls sollte darauf geachtet werden, dass tlh, komplett erstellt wurde, Beispiel siehe unten
Beispielhafte Realisierung
#include "stdafx.h"
#import "C:\Dokumente und Einstellungen\yteiken\Desktop\ComZeug\ManagedCOM\MyInterop\bin\Debug\MyInterop.tlb" named_guids raw_interfaces_only
#import "C:\Dokumente und Einstellungen\yteiken\Eigene Dateien\Visual Studio 2005\Projects\XmlaService\XmlaService\bin\Debug\XmlaService.tlb" named_guids raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
long result;
result = 5;
long parameter;
parameter = 5;
CoInitialize(NULL);
MyInterop::IMyDotNetInterfacePtr pDotNetCOMPtr;
HRESULT hRes = pDotNetCOMPtr.CreateInstance(MyInterop::CLSID_MyDotNetClass);
if (hRes == S_OK)
{
pDotNetCOMPtr->ShowDialog (parameter, &result);
}
CoUninitialize ();
BSTR string;
XmlaService::IDoServicePtr test;
//
//XMLA Interface
HRESULT hRes2 = test.CreateInstance(XmlaService::CLSID_DoXmlaService);
if(hRes2 == S_OK)
{
test->PerformRequest(&string);
}
CoUninitialize ();
return 0;
}