Forum: PC-Programmierung Reload einer ActiveXDLL in C#


von Marcel (Gast)


Lesenswert?

Hi,

ich will eine in VB6 erstellte DLL in C# benutzen. In VB6 habe ich dafür 
eine ActiveXDLL erstellt und diese mittels TlbImp-Tool exportiert. Füge 
ich die DLL als Verweis ein, kann ich ganz regulär auf den Namespace 
zugreifen und meine Funktionen wie gewohnt nutzen.

Problem an dieser Methode ist allerdings, das die in der DLL aufgerufene 
Funktion, abstürzen kann. In C# reagiere ich mittels eines Watchdogs 
darauf, beende die Berechnung und zeige eine entsprechende Meldung an. 
Will ich jedoch anschließend eine neue Berechnung ausführen, bekomme ich 
nurnoch Timeouts und sehe die entsprechende Fehlermeldung. Das Problem 
liegt darin, das das "killen", den Zustand der DLL nicht sauber beendet.

Ich brauche daher ein Verfahren, was die DLL komplett aus dem Speicher 
löscht und für die nächste Berechnung neu lädt. Ich dachte, ich könnte 
das Problem durch das dynamische Laden der DLL lösen. Dafür habe ich 
eine AppDomain (newDomainName) erstellt, und darin über 
newDomainName.Load("KMDLLCSHARP") die DLL zur Laufzeit geladen. In einem 
finally{} Block entlade ich die Domain am Ende. Aber auch dieses 
Verfahren schlägt fehl, da auch dabei die DLL nicht wirklich aus dem 
Speicher entfernt wird.

Jetzt habe ich noch einen Ansatz über den Import mittels 
"LoadLibrary"-Aufrufes aus der Kernel32.dll gefunden. Das Beispiel 
schlägt dafür vor, das ganze zunächst in eine Klasse zu packen.

static class NativeMethods
{
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetProcAddress(IntPtr hModule, 
string procedureName);

        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);
}

Anschließend soll man die Sachen importieren können:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int info(ref string infostring);

...

IntPtr pDll = NativeMethods.LoadLibrary("KMDLLCSHARP");
IntPtr pAdressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, 
"info");
info infofunction = 
(info)Marshal.GetDelegateForFunctionPointer(pAdressOfFunctionToCall, 
typeof(info));


Das funktioniert so allerdings nicht. Ich sehe, das pDLL korrekt geladen 
wird (der wert ist zumindest ungleich 0), GetProcAddress liefert 
allerdings stets 0 zurück. Nun weiß ich allerdings nicht genau, warum. 
Gebe ich den Namen der Funktion falsch an oder ist die CallingConvention 
in VB6 falsch (kp. wie die genau ist, oder wie ich darauf Einfluss 
nehmen könnte).



Weiß da wer weiter?

von Markus V. (Gast)


Lesenswert?

Der richtige Ansatz wäre, Deine VB6-DLL so zu korrigieren, dass sie nach 
einem Absturz nicht in einem Zustand bleibt, so dass sie nicht mehr 
verwendbar ist. Das Problem von P-Invoke (DllImport, ...) ist nämlich, 
dass eine einmal geladene DLL solange im Speicher bleibt, bis das 
aufrufende Programm beendet wird. Da gibt es NICHTS dran zu drehen. Nimm 
also mal den VS-Debugger zur Hand und untersuche, warum Deine VB6-DLL 
abstürzt, so dass sie nicht mehr funktioniert.

Wenn Du unbedingt mit der Holzhammer-Methode Programmierfehler umgehen 
willst, dann gibt es noch eine Möglichkeit, native DLLs über LoadLibrary 
und FreeLibrary zu laden und entladen. Wie das richtig geht, kannst Du 
diesem englischsprachigen Artikel entnehmen: 
http://www.codeproject.com/Articles/258270/How-to-release-non-managed-library-loaded-into-man. 
Allerdings ist das Einbinden der DLL-Funktionen nicht ganz so 
komfortabel, wie mit P-Invoke und mit vergleichsweise viel manuell zu 
erstellendem Code verbunden.

Gruß
Markus

von Marcel (Gast)


Lesenswert?

Hey, danke schonmal für die Hilfe.

Prinzipiell wäre mir ein Programm, das nicht oder nur "sauber" abstürzt, 
lieber. Das Programm wird allerdings nicht in unserer Firma erstellt, 
sondern extern zugekauft. Einflussnahme habe ich so nicht direkt. Ich 
kann zwar einzelne Fallstricke (es geht um eine iterative Berechnung) 
aufzeigen, die behoben werden, an die implementierung eines Watchdogs 
oder ähnlichen Sicherheitsmaßnahmen, ist aber leider nicht zu denken. 
Daher der Bedarf an die Holzhammermethode!

So, habe mittlerweile herausgefunden, das meine Funktionen lediglich als 
"COM Method" exportiert wurden. Habe das ganze nun nochmal nach 
folgender Anleitung umgestellt: 
http://www.hermetic.ch/vbm2dll.htm#petrusha
Meine Funktionen werden nun korrekt als "Exported Function" exportiert, 
ein aufruf funktioniert prinzipiell. Verzweige ich aber nun innerhalb 
der Funktionen weiter, (also auf die ursprünglichen Funktionen, die ich 
mit der ursprünglichen Methode aufrufen konnte), erscheint lediglich 
folgende Exception:

"Attempted to read or write protected memory. This is often an 
indication that other memory is corrupt."

Ich habe nun allerdings keine Ahnung, wie ich das umgehen koennte?

von Markus V. (Gast)


Lesenswert?

Hi Marcel,

ich hatte den Eindruck, die VB6 DLL wäre von Dir...

Ok. VB (6, .NET) muss ich leider passen. Die Exception riecht aber 
irgendwie nach korruptem Stack. Das wiederum ist ein Indiz dafür, dass 
beim DllImport Attribut das Property CallingConvention auf den richtigen 
wert gesetzt werden sollte. Welcher das ist, kann ich leider nicht 
sagen. Wahrscheinlich hilft dir aber eine Internetsuche weiter. Die 
Calling Convention gibt an, wer den Stack nach einem Funktionsaufruf 
aufräumt (Aufrufer oder Aufgerufene Funktion).

Gruß
Markus

von Marcel (Gast)


Lesenswert?

Hi,

mit den Calling Conventions habe ich bereits rumgespielt. Prinzipiell 
funktioniert ja auch der Aufruf, aber nicht die weiterführung. D.h. wenn 
das Programm innerhalb der Funktion bleibt, die ich aufrufe, klappt es. 
(Ich kann Rückgabe und Übergabewerte regulär benutzen.) Nur der Aufruf 
einer weiteren Funktion/Sub führt zum Absturz/Wurf der Exception. 
Irgendwie sehr dubios.

Ich denke, ich werde mir eine weitere, WrapperDLL schreiben, die den 
Aufruf der VB6DLL für mich übernimmt und die ich dynamisch in C# 
nachladen kann. Würde das so funktionieren? Irgendwie traue ich dieser 
scheinbar einfachen Sache nichtmehr so ganz! =[

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.