С# GetProcAddress возвращает ноль

По какой-то причине, когда мое приложение С#.NET 2.0 делает вызов GetProcAddress, оно всегда возвращает ноль.

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.
    }
}

Я уверен, что имя функции написано правильно, а _fullPath предположительно правильно, потому что _dllHandle всегда назначается ненулевое значение. Любое понимание, которое вы можете предоставить, ценится. Спасибо.

Ответ 1

GetProcAddress поставляется только в стиле ANSI, поэтому мы помогаем во время выполнения, сообщая ему всегда использовать ANSI при сортировке строкового параметра. Мы также предотвращаем, чтобы среда выполнения искала несуществующий GetProcAddressA, потому что по умолчанию для С# следует установить значение ExactSpelling в false.

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

Ответ 2

Вам действительно нужно добавить некоторую проверку ошибок. По крайней мере, проверьте, является ли _dllHandle!= IntPtr.Zero. Кроме того, в зависимости от текущего рабочего каталога является опасным, используйте Assembly.GetEntryAssembly(). Местоположение, чтобы получить полное имя пути.

Название функции, вероятно, неверно. Экспорт, как правило, оформляется, например, _MyDllFunc или _MyDllFunc @4. Более дико, если он был скомпилирован компилятором С++. Используйте Dumpbin.exe/exports в своей DLL, чтобы увидеть настоящие имена.

Вернуться к обработке ошибок, используйте SetLastWin32Error в атрибуте [DllImport]. Throw Win32Exception, если функция возвращает false или IntPtr.Zero.


Изменить: я вижу реальную проблему. Использование CharSet.Auto для GetProcAddress() неверно. Очень неудачно, это всего лишь единственная функция Windows API, которая имеет только версию ANSI. Вы должны использовать CharSet.Ansi. Хорошее место для получения правильных объявлений [DllImport] - pinvoke.net

Ответ 3

Вы не показывали, как вы экспортируете функцию из DLL, но я подозреваю, что проблема заключается в том, что экспортированное имя не то, что вы есть. Вы можете запустить dumpbin /exports mydll.dll, чтобы просмотреть экспорт DLL, чтобы проверить имя.

Если вы покажете фрагмент кода экспорта, я могу предоставить более прямые рекомендации. Вы можете попробовать украсить экспортированную функцию с помощью extern "C", чтобы исключить манипуляцию имени в качестве теста.

Ответ 4

Соответствует ли ваш экспорт в файле .DEF для DLL входным данным? Вы можете использовать dumpbin, чтобы узнать, что экспортировано, за другие ответы здесь.

Какова основная ошибка Win32 в GetProcAddress(), за GetLastError()?

Вы можете попробовать это в собственном коде для правильного ввода исходных данных без дополнительного багажа P/Invoke.