Laden...

DLLImport und Kommunikation mit C++ DLLs

Erstellt von vnvjan vor 3 Jahren Letzter Beitrag vor 3 Jahren 425 Views
V
vnvjan Themenstarter:in
74 Beiträge seit 2006
vor 3 Jahren
DLLImport und Kommunikation mit C++ DLLs

Folgendes Szenario: In einem C# Programm sollen Funktionen aus einer C++ DLL aufgerufen werden, die wiederum weitere C++ DLLs nachlädt, um dort Funktionen aufzurufen usw usw usw...bisher wird DLLImport zum Laden der DLL im C# Programm verwendet.

Unter C++, VB und Delphi funktioniert das alles ohne Probleme. Zielstellung ist aber, es unter C# zum Laufen zu bekommen. In C# bricht das Programm ohne Exception einfach zusammen, wenn die geladene DLL weitere Funktionsaufrufe aus anderen DLLs nachlädt. Selbst in einem try-catch Block gibt es nichts zurück.
Jetzt hab ich mal windbg darüber laufen lassen und folgende Log Meldung hier bekommen.

(d7c.3b90): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
\*** WARNING: Unable to verify checksum for Fire.DLL

In welche Richtung muss man hier schauen oder hat schon mal selbst jemand solch ein Szenario durchlebt? Ich bin in diesem Thema etwas unbeholfen.

4.939 Beiträge seit 2008
vor 3 Jahren

Hallo,

das könnte dann einfach ein Marshelling-Fehler sein?
Wie sieht denn die Signatur der C++-Funktion (bzw. C) aus und wie hast du es nach C# übersetzt? Außerdem noch: 32 oder 64 Bit?

V
vnvjan Themenstarter:in
74 Beiträge seit 2006
vor 3 Jahren

Die DLLs sind 32-bit und mein Programm wird auch nur für x86 kompiliert.

Ich initialisiere mittels DLLImport eine 3D Anwendung über einen IntPtr, stellvertretend für ein Panel.Handle und bekomme auch wie gewünscht ein sichtbares Ergebnis in Form einer 3D Ansicht zurück, dargestellt im Panel, zurück. Die C++ Funktion hat im Initialisierungs-Code Übergabeparameter, welche als HWND definiert sind und in dieser Funktion als gecastetes DWORD weitergereicht werden. Soweit, so richtig und funktioniert auch.

Jetzt kann man der DLL normale String Befehle übergeben, welche über weitere Funktion starten, was im Großen und Ganzen funktioniert. So lassen sich z.B. 3D Daten laden, die auch im Panel angezeigt werden.
Das Problem dabei, in VB oder Delphi wird von dieser DLL eine zusätzliche Audioschnittstelle über eine weitere DLL nachgeladen und initialisiert. Von C# aus tut sie das aber nicht. Man kann diese auch nicht von außen initialisieren und einbinden. Ich befürchte das es nicht am Marshalling liegt, sondern eher ein Speicher-/Thread Problem ist.

4.939 Beiträge seit 2008
vor 3 Jahren

Wie genau wird denn die andere DLL nachgeladen (dynamisch mit LoadLibrary)?
Wird dabei überprüft, ob die DLL geladen werden kann (0xc0000005 ist ja eine Zugriffsverletzung / Access Violation)?
Und liegt die andere DLL im gleichen Verzeichnis wie die EXE und die Import-DLL?

V
vnvjan Themenstarter:in
74 Beiträge seit 2006
vor 3 Jahren

Die DLL wird über DLLImport und nicht LoadLibrary geladen...letzteres habe ich auch schon mit selben Nebeneffekten probiert.
Alle Dateien liegen im selben Verzeichnis.

Der folgende Code initialisiert die 3D Anwendung und gibt mir eine 3D Ansicht im Panel zurück.
Mit SendCommand schick ich dann weitere Befehle an die Master.dll, z.b. zum Laden von Daten etc pp.

Beim Laden der Daten wird in Abhängigkeit der verwendeten Inhalte zusätzliche Bibliotheken von der Master.dll nachgeladen, wie z.b. Audioausgabe und an dieser Stelle steigt C# aus. Unter VB und Delphi wird die Audioausgabe ohne Probleme nachgeladen.


[DllImport(@"Master.dll", EntryPoint = "?Init@@YGXPAUHWND__@@0@Z", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern void Init(IntPtr hWndMain);
[DllImport(@"Master.dll", EntryPoint = "?SendCommand@@UAEPB_WW4E@@@Z", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern void SendCommand(string cmd);

        public Form1()
        {
            InitializeComponent();

            try
            {
                InitView();
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void InitView()
        {
             Init(this.Handle);
             SendCommand("CALL SHOWVIEW WND=" + panel.Handle);
        }

4.939 Beiträge seit 2008
vor 3 Jahren

Ich meinte, wie wird die andere DLL (mit der Audioschnittstelle) von der C++-DLL nachgeladen (oder hast du nicht den Source-Code zur master.dll?)? Denn damit hast du doch Probleme.

Und warum hat diese master.dll keine vernünftige C-Schnittstelle - mittels extern "C" (wenn sie auch von anderen Sprachen wie VB oder Delphi aus angesprochen wird)?

6.911 Beiträge seit 2009
vor 3 Jahren

Hallo vnvjan,

das eigentliche Problem hab ich zu wenig verfolgt, aber bei


[DllImport(@"Master.dll", EntryPoint = "?Init@@YGXPAUHWND__@@0@Z", CallingConvention = CallingConvention.StdCall, SetLastError = true)]

"muss" ich darauf hinweise, dass dieses Vorgehen sehr fragil ist, da durch das Name mangling der EntryPoint bei jeder Version von Master.dll anders sein kann.

Der korrekte Weg wäre hier einen C-Wrapper (zumindest einen extern "C" Export) für die C++ Bibliothek zu erstellen und dann diesen Namen im EntryPoint zu verwenden.
Sonst gibt es später einmal ein Problem und dessen Ursachenforschung mag schwierig sein, da an dies eher nicht gedacht wird (zumindest nicht sofort).

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"