14

出于某种原因,每当我的 C# .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它总是被分配一个非零值。感谢您提供的任何见解。谢谢。

4

4 回答 4

19

GetProcAddress 仅具有 ANSI 风格,因此我们通过告诉运行时在编组字符串参数时始终使用 ANSI 来帮助运行时。我们还阻止运行时查找不存在的 GetProcAddressA,因为 C# 的默认设置是将 ExactSpelling 设置为 false。

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

于 2010-09-20T18:38:14.173 回答
2

您确实需要添加一些错误检查。至少验证 _dllHandle != IntPtr.Zero 是否。此外,根据当前工作目录是否危险,使用 Assembly.GetEntryAssembly().Location 获取完整路径名。

函数名可能是错误的。导出往往会被修饰,例如 _MyDllFunc 或 _MyDllFunc@4。如果它是由 C++ 编译器编译的,那就更疯狂了。使用 DLL 上的 Dumpbin.exe /exports 查看真实名称。

回到错误处理,在 [DllImport] 属性中使用 SetLastWin32Error。如果函数返回 false 或 IntPtr.Zero,则抛出 Win32Exception。


编辑:我看到了真正的问题。将 CharSet.Auto 用于 GetProcAddress() 是错误的。很不幸,它只是唯一一个只有 ANSI 版本的 Windows API 函数。你必须使用 CharSet.Ansi。获得正确的 [DllImport] 声明的好地方是 pinvoke.net

于 2010-09-20T18:34:11.863 回答
1

您还没有展示如何从 DLL 导出函数,但我怀疑问题在于导出的名称不是您想要的。您可以运行dumpbin /exports mydll.dll以查看 dll 的导出以验证名称。

如果您显示导出的代码片段,我可以提供更直接的建议。您可以尝试使用来装饰导出的函数extern "C"以消除名称修改作为测试。

于 2010-09-20T18:33:43.217 回答
0

您在 DLL 的 .DEF 文件中的导出是否与此处的输入匹配?您可以dumpbin根据此处的其他回复了解导出的内容。

什么是潜在的 Win32GetProcAddress()错误GetLastError()

您可以在本机代码中尝试此操作,以首先计算出正确的输入,而无需额外的 P/Invoke 包袱。

于 2010-09-20T18:36:02.920 回答