有關Win32 SendMessage
函數的正確簽名的信息來源有衝突。SendMessage的真正簽名是什麼,它應該如何在C#中調用?
微軟WINAPI文檔指出它的簽名是:
LRESULT WINAPI SendMessage(
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam);
因此,我們有以下幾種類型來解決:
LRESULT
WPARAM
LPARAM
使用微軟的'Windows Data Types'頁面,我能夠做出一些發現。
LRESULT
的類型是LONG_PTR
。 LONG_PTR
具有以下定義:
#if defined(_WIN64)
typedef __int64 LONG_PTR;
#else
typedef long LONG_PTR;
#endif
long
在WINAPI始終是一個32位有符號的數量,根據該相同的「Windows Data Types」頁。
接下來是WPARAM
,其類型爲一個UINT_PTR
。 UINT_PTR
具有以下定義:
#if defined(_WIN64)
typedef unsigned __int64 UINT_PTR;
#else
typedef unsigned int UINT_PTR;
#endif
int
(就像long
)在WINAPI始終是一個32位有符號的量。
最後,LPARAM
,其類型爲另一個LONG_PTR
。
因此,要總結,我們有:
LRESULT
- >LONG_PTR
- >簽署32位/ 64位取決於平臺。WPARAM
- >UINT_PTR
- >無符號的32位/ 64位取決於平臺。LPARAM
- >LONG_PTR
- >根據平臺簽名的32位/ 64位。
就這樣我們在C#簽名(忽略的符號性)將是:
[DllImport("User32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
P-Invoke.Net的documentation on SendMessage
證實了這一 - 它們有幾乎相同的簽名,除了符號性,以及它們的文檔有地說:
2)不要使用 「內部」 或 「整數」 作爲lParam的。您的代碼將在64位窗口上崩潰。只能使用IntPtr,「ref」結構或「out」結構。
3)切勿使用「bool」,「int」或「integer」作爲返回值。你的核心將在64位窗口上崩潰。只能使用IntPtr。使用bool不安全 - pInvoke無法將IntPtr編組爲布爾值。
到目前爲止一切都很有意義。
然而,兩條信息不同意這一點。
一個我自己的代碼,已經在64位和32位上運行了幾個月而沒有崩潰,使用int wparam
和int lparam
。爲什麼不這樣墜毀?
二,在微軟自己的源代碼,System.Windows.Forms.UnsafeNativeMethods
,我們看到很多很多的定義都違反了這個分析。最糟糕的,其中上線1044:
[DllImport(ExternDll.User32, CharSet = CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);
他們特別聲明lParam
爲int,應該崩潰。
什麼是SendMessage
正確的簽名?
微軟的簽名被破壞了嗎?
爲什麼沒有'破損'的簽名造成崩潰?
因爲它是一個寄存器調用約定,所以你可以在64位上避開它。 IntPtr是正確的。 –
'lParam'和'wParam'確實是'IntPtr'(指針大小值)。如果您在64位進程中將*指針*傳遞給某些數據,並且此指針超過32位大小 - 如果通過此無效指針引用數據,它將被截斷(如果將其聲明爲* int *)並且您的收件人發生崩潰 – RbMm
@RbMm - 在這個問題的背景下,你的評論沒有意義。 – antiduh