C# einbindung dynamischer C++-bibliotheken

bog

Ensign
Registriert
Apr. 2008
Beiträge
254
hey!

um meine c++- und c#-kenntnisse, gerade mit dem build-prozess unter windows, war es nie uebertrieben gut bestellt. aktuell scheitere ich am im titel genannten versuch, eine in c++ geschriebene und kompilierte DLL in ein in c# geschriebenes programm einzubinden (p/invoke).

die C++-bibliothek:

dabei handelt es sich um recht ueberschaubaren code, der per undokumentierter windows com schnittstelle das standard-audio-ausgabegeraet umstellt. der obige link enthaelt unten einen download eines kompletten VS projekts. das kompiliert auch fein und funktioniert.

ich habe im enthaltenen code den aufruf an die windows-schnittstelle insofern ausgekapselt, als dass die CLI-parameteruebergabe nur noch in der main-funktion stattfindet und diese dann eine funktion folgender signatur aufruft, die ich dann auch vom c#-projekt heraus verwenden moechte:
C++:
int ChangeAudioDevice(int option)

zum offenlegen der funktion habe ich in der headerdatei folgende zeilen angebracht, die ich aus dem internet adaptiert habe:
C++:
#ifdef ENDPOINTCONTROLLER_EXPORTS
#define ENDPOINTCONTROLLER_API __declspec(dllexport)
#else
#define ENDPOINTCONTROLLER_API __declspec(dllimport)
#endif

extern "C" ENDPOINTCONTROLLER_API int ChangeAudioDevice(int option);

in den property pages des projekts habe ich unter configuration properties -> general -> project defaults den configuration type auf dynamic library, sowie den CLR support angeschalten. das ganze kompiliert fein, wenn ich es als .exe kompiliere laeuft das auch wie zuvor prima von der kommandozeile aus, und das .dll-kompilat kopiere ich nun in mein C#-projekt.

dort importiere ich die funktion wie folgt als methode:
C#:
[DllImport("EndPointController.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "ChangeAudioDevice")]
static extern int ChangeAudioDevice(int option);

das kompiliert auch fein, der c#-code fuehrt fehlerfrei aus, jedoch bleibt die funktion des c++-codes komplett aus:
C#:
Console.WriteLine(ChangeAudioDevice(-1));
gibt mir einen wert von "-2147417850" zurueck, das audiogeraet wird nicht geaendert, und eine ausgabe der audiogeraete per stdout wie im code des c++-projektes gedacht geschieht nicht.

der int-datentyp ist fuer die beiden sprachen soweit ich das verstehe gleich, daher kein marshalling noetig. ueberseh ich hier was?
 
Zuletzt bearbeitet:
Hi,

das Problem ist simple: HRESULT hr = CoInitialize(NULL); im C++ Code gibt S_FALSE (https://docs.microsoft.com/de-de/wi...e/nf-objbase-coinitialize?redirectedfrom=MSDN) zurück. Da das C# Programm aber der "Ausführer" ist, ist das OK.

Der Fix ist die Löschung der Prüfung von CoInitialize:
C:
HRESULT hr = CoInitialize(NULL);
//if (SUCCEEDED(hr))

Notfalls musst du noch bei deinem C# Programm das STAThread Attribute setzen (ich meine, dass STAThread und CoInitialize die gleiche Bedeutung haben)
C#:
[STAThread]
public static void Main(string[] args)
{
    ...
}

Beachte: Das Console.WriteLine(ChangeAudioDevice(-1)); gibt nicht die Liste aus, sondern den "hr", also den errorCode der letzten Ausführung. ChangeAudioDevice(-1); reicht, damit es in der Console steht
 
hoppler schrieb:
das Problem ist simple: HRESULT hr = CoInitialize(NULL); im C++ Code gibt S_FALSE (https://docs.microsoft.com/de-de/wi...e/nf-objbase-coinitialize?redirectedfrom=MSDN) zurück. Da das C# Programm aber der "Ausführer" ist, ist das OK.
fast!
C++:
printf("S_FALSE: %d\n", S_FALSE);
printf("RPC_E_CHANGED_MODE: %d\n", RPC_E_CHANGED_MODE);
printf("HR: %d\n", hr);
=>
Code:
S_FALSE: 1
RPC_E_CHANGED_MODE: -2147417850
HR: -2147417850
hoppler schrieb:
Notfalls musst du noch bei deinem C# Programm das STAThread Attribute setzen (ich meine, dass STAThread und CoInitialize die gleiche Bedeutung haben)
ah! das ist 'ne gute info. die dokumentation hatte ich nach identifikation des fehlercodes auch schon gefunden, konnte mir aber auf die beschreibung wirklich gar keinen reim machen.
hoppler schrieb:
Beachte: Das Console.WriteLine(ChangeAudioDevice(-1)); gibt nicht die Liste aus, sondern den "hr", also den errorCode der letzten Ausführung. ChangeAudioDevice(-1); reicht, damit es in der Console steht
jepp, ich dachte zwar nicht, dass ich die liste per return zurueck erhalte, aus irgendeinem grund war ich aber der ueberzeugung, dass ich einfach den eingabeparameter option (int) zurueckbekomme und war dann tageszeitenlang(!) davon ueberzeugt, dass beim parameter passing von managed zu unmanaged code was schief geht. der code im c++-programm lief ja problemlos. die konvention fuer main-returncodes >0 => fehler fiel mir auch erst eben ein.

lieben dank fuer die ausfuehrung, das problem ist damit geloest.
 
Zuletzt bearbeitet:
Zurück
Oben