2010-09-20 123 views
11

由於某種原因,每當我的C#.NET 2.0應用程序調用GetProcAddress時,它總是返回零。C#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總是被分配一個非零值。任何你可能能夠提供的洞察力都是值得讚賞的。謝謝。

回答

13

GetProcAddress只包含ANSI風格,因此我們通過在編組字符串參數時告訴它始終使用ANSI來幫助運行時。我們還阻止運行時查找不存在的GetProcAddressA,因爲C#的默認設置是將ExactSpelling設置爲false。

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

+0

+1,我在看到它之前就已經明白了。 – 2010-09-20 18:53:29

+0

這個伎倆!謝謝! – 2010-09-20 20:56:14

+0

+1我一直暗示着我的頭靠在牆上幾個小時,直到谷歌送我到這裏!畢竟這只是將** CharSet = CharSet.Ansi **添加到** DllImport **屬性的命名參數才能使其工作的問題。 – 2013-04-26 22:24:08

1

你沒有顯示如何從DLL中導出函數,但我懷疑問題是導出的名稱不是你現在的東西。您可以運行dumpbin /exports mydll.dll查看dll的導出以驗證名稱。

如果您顯示導出的代碼段,我可以提供更直接的建議。您可以嘗試使用extern "C"裝飾導出的函數,以消除名稱混亂作爲測試。

2

你真的需要添加一些錯誤檢查。至少驗證_dllHandle!= IntPtr.Zero。另外,根據當前的工作目錄是危險的,使用Assembly.GetEntryAssembly()。Location來獲取完整的路徑名。

函數名稱可能是錯誤的。出口往往是裝飾,像_MyDllFunc或_MyDllFunc @ 4。如果它是由C++編譯器編譯的話,會更瘋狂。使用您的DLL上的Dumpbin.exe/exports來查看真實姓名。

返回錯誤處理,請在[DllImport]屬性中使用SetLastWin32Error。如果函數返回false或IntPtr.Zero,則拋出Win32Exception。


編輯:我看到了真正的問題。對於GetProcAddress()使用CharSet.Auto是錯誤的。非常不幸的是,它只是只有 Windows API函數,只有ANSI版本。你必須使用CharSet.Ansi。獲得正確的[DllImport]聲明的好地方是pinvoke.net

+0

爲錯誤的名字投票。導出的函數名稱通常看起來很奇怪。 – 2010-09-20 18:44:59

+0

我刪除了錯誤處理程序代碼以使代碼片段更簡單。 – 2010-09-20 20:55:33

+0

@Jim:在發佈之前是否真的刪除了SetLastWin32Error?我知道,聰明屁股的評論:) – 2010-09-20 21:10:23

0

您在.DEF文件中爲DLL導出與此處的輸入是否匹配?您可以使用dumpbin來查找導出的內容,以及此處的其他回覆。

GetProcAddress(),根據GetLastError(),底層的Win32錯誤是什麼?

您可以在本地代碼中嘗試使用此功能,以便在沒有額外的P/Invoke行李的情況下首先計算出正確的輸入。

+2

順便說一句,你可以通過拋出一個Win32Exception得到最後一個錯誤:拋出新的Win32Exception();無參的構造函數調用Marshal.GetLastWin32Error()並給出詳細的錯誤信息。 – dtb 2010-09-20 19:19:16