我目前正在将C++
应用移植到C#
,但无法转换此特定功能。
此函数获取给定窗口句柄的文本/标题。
我发现重要的部分是对SendMessageTimeoutW
的2次调用,这些调用得到了我假设的窗口文本,但我无法弄清楚其余部分。
我也找不到UTF-16函数SendMessageTimeoutW
的任何P / Invoke签名,因此对SendMessageTimeout
的调用是等效的,如this post所示?
public static unsafe string GetWindowText(IntPtr hWnd)
{
// THIS PART MAY NOT BE NEEDED
string str2 = null;
WinHookEx* exPtr3;
WinHookEx* exPtr = @new(4);
try
{
exPtr3 = (exPtr == null) ? null : WinHookEx.{ctor}(exPtr);
}
fault
{
delete((void*) exPtr);
}
WinHookEx* exPtr2 = exPtr3;
*((int*) exPtr2) = hWnd.ToPointer();
HWND__* hwnd__Ptr = (HWND__*) hWnd.ToPointer();
uint modopt(IsLong) num = 0;
delete((void*) exPtr2);
// 1st call to SendMessageTimeoutW
if (SendMessageTimeoutW(hwnd__Ptr, 14, 0, 0, 2, 0x3e8, &num) == 0)
{
return null;
}
// whats happening here?
num++;
uint modopt(IsLong) num2 = num;
char* chPtr = @new((num2 > 0x7fffffff) ? uint.MaxValue : ((uint) (num2 * 2)));
chPtr[0] = '\0';
// 2nd call to SendMessageTimeoutW
if (SendMessageTimeoutW(hwnd__Ptr, 13, num, (int modopt(IsLong)) chPtr, 2, 0x3e8, &num) == 0)
{
return null;
}
str2 = new string(chPtr);
delete((void*) chPtr);
return str2;
}
我暂时将此功能移植到C#
,但它始终返回空白字符串。
我甚至尝试使用new StringBuilder(256)
启动字符串构建器,但它仍然不起作用。
我做错了什么?
public static unsafe string GetWindowText(IntPtr hWnd){
// send WM_GETTEXTLENGTH
if (SendMessageTimeout(hWnd, 14, 0, 0, 2, 0x3e8, IntPtr.Zero) == 0){
return null;
}
// send WM_GETTEXT
StringBuilder sb = new StringBuilder();
if (SendMessageTimeout(hWnd, 13, 0, sb, 2, 0x3e8, IntPtr.Zero) == 0){
return null;
}
return sb.ToString();
}
答案 0 :(得分:1)
对于WM_GETTEXT
,wParam
(SendMessageTimeout
的第三个参数)是
要复制的最大字符数,包括终止空字符。
你传递零。
此外,您正在调用WM_GETTEXTLENGTH
但未使用返回值:
返回值是以字符为单位的文本长度,不包括终止空字符。
使用它来指定StringBuilder
的初始大小。我刚刚证实了这一点:
static void Main(string[] args) {
var p = Process.GetProcessById(3484);
var h = p.MainWindowHandle;
string s = GetWindowTextTimeout(h, 100 /*msec*/);
}
[DllImport("User32.dll", SetLastError = true)]
public unsafe static extern int SendMessageTimeout(
IntPtr hWnd,
uint uMsg,
uint wParam,
StringBuilder lParam,
uint fuFlags,
uint uTimeout,
void* lpdwResult);
const int WM_GETTEXT = 0x000D;
const int WM_GETTEXTLENGTH = 0x000E;
public static unsafe string GetWindowTextTimeout(IntPtr hWnd, uint timeout)
{
int length;
if (SendMessageTimeout(hWnd, WM_GETTEXTLENGTH, 0, null, 2, timeout, &length) == 0) {
return null;
}
if (length == 0) {
return null;
}
StringBuilder sb = new StringBuilder(length + 1); // leave room for null-terminator
if (SendMessageTimeout(hWnd, WM_GETTEXT, (uint)sb.Capacity, sb, 2, timeout, null) == 0) {
return null;
}
return sb.ToString();
}
答案 1 :(得分:0)
你需要传递缓冲区的长度。
int size;
SendMessageTimeout((int)hWnd, WM_GETTEXTLENGTH, 0, 0, 2, 0x3e8, &size).ToInt32();
if (size > 0)
{
StringBuilder sb = new StringBuilder(size + 1);
SendMessageTimeout(hWnd, WM_GETTEXT, sb.Capacity, sb, 2, 0x3e8, IntPtr.Zero)
}