SendMessage 中的误导参数类型 (... IntPtr wParam ...)
Misleading parameter type in SendMessage (... IntPtr wParam ...)
在处理 中描述的问题时,我偶然发现了参数 wParam 及其类型 IntPtr 用于 SendMessage 函数。
原始函数的代码类似于
var length = (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var buff = new char[length + 1];
var iptr = Marshal.AllocHGlobal(buff.Length * sizeof(char));
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)(length + 1), iptr);
Marshal.Copy(iptr, buff, 0, length + 1);
Marshal.FreeHGlobal(iptr);
我不喜欢分配和复制部分,所以我尝试用
替换它
var length = 1 + (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var buffer = new char[length];
var bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var lengthHandle = GCHandle.Alloc(length, GCHandleType.Pinned);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, lengthHandle.AddrOfPinnedObject(), bufferHandle.AddrOfPinnedObject());
bufferHandle.Free();
lengthHandle.Free();
事实证明,这不会起作用,因为参数 wParam 不是指针(可以从其 IntPtr 类型得出结论) .
WM_GETTEXT 消息的具体描述可以在 MSDN 上找到(感谢 SO 社区指出这一点),这引导我们使用以下代码
var length = 1 + (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var buffer = new char[length];
var bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)length, bufferHandle.AddrOfPinnedObject());
bufferHandle.Free();
是否有针对特定消息专门或缩小的 SendMessage 函数的库或签名集合?
不要误会我的意思,PInvoke 已经通过将此功能提供给托管世界做了很多工作,我对此表示赞赏,但是单一方法的多用途性质使其更难使用。
您可以从 PInvoke page 中复制它们,但请注意,我经常必须修改 PInvoke 定义(它们通常是面向 32 位的,所以他们经常假设 sizeof(IntPtr) == sizeof(int)
,这是非常错误的!, 或者他们使用 "obsolete" ANSI API, 但现在应该始终使用 Unicode API...举个例子, 在链接页面中, SendMessage
与[MarshalAs(UnmanagedType.LPStr)] string lParam
使用的是 ANSI API,而带有 Int32 wParam
的将在 64 位上中断)
您的代码可以更改为:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, StringBuilder lParam);
var length = (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var sb = new StringBuilder(length + 1);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)sb.Capacity, sb);
string str = sb.ToString();
使用 pinvoke 子系统 "supports" StringBuilder
来编组字符串。
在处理
原始函数的代码类似于
var length = (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var buff = new char[length + 1];
var iptr = Marshal.AllocHGlobal(buff.Length * sizeof(char));
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)(length + 1), iptr);
Marshal.Copy(iptr, buff, 0, length + 1);
Marshal.FreeHGlobal(iptr);
我不喜欢分配和复制部分,所以我尝试用
替换它var length = 1 + (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var buffer = new char[length];
var bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
var lengthHandle = GCHandle.Alloc(length, GCHandleType.Pinned);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, lengthHandle.AddrOfPinnedObject(), bufferHandle.AddrOfPinnedObject());
bufferHandle.Free();
lengthHandle.Free();
事实证明,这不会起作用,因为参数 wParam 不是指针(可以从其 IntPtr 类型得出结论) .
WM_GETTEXT 消息的具体描述可以在 MSDN 上找到(感谢 SO 社区指出这一点),这引导我们使用以下代码
var length = 1 + (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var buffer = new char[length];
var bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)length, bufferHandle.AddrOfPinnedObject());
bufferHandle.Free();
是否有针对特定消息专门或缩小的 SendMessage 函数的库或签名集合?
不要误会我的意思,PInvoke 已经通过将此功能提供给托管世界做了很多工作,我对此表示赞赏,但是单一方法的多用途性质使其更难使用。
您可以从 PInvoke page 中复制它们,但请注意,我经常必须修改 PInvoke 定义(它们通常是面向 32 位的,所以他们经常假设 sizeof(IntPtr) == sizeof(int)
,这是非常错误的!, 或者他们使用 "obsolete" ANSI API, 但现在应该始终使用 Unicode API...举个例子, 在链接页面中, SendMessage
与[MarshalAs(UnmanagedType.LPStr)] string lParam
使用的是 ANSI API,而带有 Int32 wParam
的将在 64 位上中断)
您的代码可以更改为:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, StringBuilder lParam);
var length = (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
var sb = new StringBuilder(length + 1);
SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)sb.Capacity, sb);
string str = sb.ToString();
使用 pinvoke 子系统 "supports" StringBuilder
来编组字符串。