2010-09-20 11 views
11

Wenn meine C# .NET 2.0-Anwendung einen Aufruf an GetProcAddress aufruft, gibt es aus irgendeinem Grund immer Null zurück.C# GetProcAddress gibt Null zurück

public class MyClass 
{ 
    internal static class UnsafeNativeMethods 
    { 
     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     internal static extern IntPtr LoadLibrary(string lpFileName); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     internal static extern bool SetDllDirectory(string lpPathName); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 
    } 

    private void MyFunc() 
    { 
     IntPtr _dllHandle; 
     IntPtr _fptr; 
     string _fullPath = ".\\mydll.dll"; 
     string _procName = "MyDllFunc"; 

     _dllHandle = UnsafeNativeMethods.LoadLibrary(_fullPath); 
     _fptr = UnsafeNativeMethods.GetProcAddress(_dllHandle, _procName); // <-- Always returns zero. 
    } 
} 

Ich bin sicher, dass der Funktionsname richtig geschrieben ist, und _fullPath ist vermutlich richtig, weil _dllHandle immer einen Wert ungleich Null zugewiesen wird. Jeder Einblick, den Sie möglicherweise bereitstellen können, wird geschätzt. Vielen Dank.

Antwort

13

GetProcAddress kommt nur in einem ANSI-Flavor, daher helfen wir der Laufzeit, indem wir ihm mitteilen, immer ANSI zu verwenden, wenn der String-Parameter parallelliert wird. Wir verhindern auch, dass die Laufzeitumgebung nach einer nicht vorhandenen GetProcAddressA sucht, da der Standardwert für C# ExactSpelling auf false festgelegt ist.

http://www.pinvoke.net/default.aspx/kernel32.getprocaddress

+0

+1, du hast das, bevor ich es sah. –

+0

Das hat den Trick gemacht! Vielen Dank! –

+0

+1 Ich habe meinen Kopf stundenlang an die Wand gelehnt, bis mich Google hierher geschickt hat!Schließlich war es nur eine Frage des Hinzufügens von ** CharSet = CharSet.Ansi ** zu den benannten Parametern des ** DllImport ** -Attributs, damit es funktioniert. –

1

Sie haben nicht gezeigt, wie Sie die Funktion aus der DLL exportieren, aber ich vermute, das Problem ist, dass der exportierte Name nicht das ist, was Sie ding es ist. Sie können dumpbin /exports mydll.dll ausführen, um die Exporte der DLL anzuzeigen, um den Namen zu überprüfen.

Wenn Sie das Code-Snippet des Exports zeigen, könnte ich direktere Ratschläge geben. Sie können versuchen, die exportierte Funktion mit extern "C" dekorieren, um den Namen Mangling als Test zu beseitigen.

2

Sie müssen wirklich einige Fehlerprüfung hinzufügen. Überprüfen Sie mindestens, ob _dllHandle! = IntPtr.Zero. Abhängig vom aktuellen Arbeitsverzeichnis ist auch gefährlich, verwenden Sie Assembly.GetEntryAssembly(). Location, um einen vollständigen Pfadnamen zu erhalten.

Der Funktionsname ist wahrscheinlich falsch. Exporte werden tendenziell dekoriert, wie _MyDllFunc oder _MyDllFunc @ 4. Eher wild, wenn es von einem C++ - Compiler kompiliert wurde. Verwenden Sie Dumpbin.exe/exportiert in Ihrer DLL, um die echten Namen anzuzeigen.

Zurück zur Fehlerbehandlung, verwenden Sie SetLastWin32Error im Attribut [DllImport]. Wirf Win32Exception, wenn die Funktion false oder IntPtr.Zero zurückgibt.


Edit: Ich sehe das wahre Problem. Die Verwendung von CharSet.Auto für GetProcAddress() ist falsch. Sehr unglücklich, es ist nur über die nur Windows-API-Funktion, die nur eine ANSI-Version hat. Sie müssen CharSet.Ansi verwenden. Ein guter Ort, um richtige [DllImport] -Deklarationen zu erhalten, ist pinvoke.net

+0

Abstimmen für falschen Namen. exportierte Funktionsnamen sieht normalerweise sehr seltsam aus. –

+0

Ich habe den Error-Handler-Code entfernt, um das Code-Snippet einfacher zu machen. –

+0

@Jim: hast du tatsächlich SetLastWin32Error entfernt, bevor du gepostet hast? Ich weiß, Smart-Ass Bemerkung :) –

0

Ist Ihr Export in der. DEF-Datei für die DLL die Eingabe hier? Sie können dumpbin verwenden, um herauszufinden, was exportiert wird, nach anderen Antworten hier.

Was ist der zugrunde liegende Win32-Fehler unter GetProcAddress(), per GetLastError()?

Sie könnten dies in nativem Code versuchen, um die richtigen Eingaben zuerst ohne das zusätzliche Gepäck von P/Invoke auszuarbeiten.

+2

BTW können Sie den letzten Fehler erhalten, indem Sie eine Win32Exception: 'werfen neue Win32Exception();' Der parameterlose Konstruktor ruft 'Marshal.GetLastWin32Error()' und gibt eine detaillierte Fehlermeldung. – dtb