我对 Windows API RedrawWindow、ExtTextOut和 BitBlt有疑问。如果我使用参数 lprcUpdate = NULL 和 hrgnUpdate = NULL 调用 RedrawWindow,我将连接 ExtTextOut 以提取屏幕上的文本位置:
WindowWrapper.RedrawWindow(topWnd, IntPtr.Zero, IntPtr.Zero, RedrawWindowFlags.UpdateNow | RedrawWindowFlags.Frame | RedrawWindowFlags.Invalidate | RedrawWindowFlags.AllChildren | RedrawWindowFlags.Erase);
在挂钩函数 ExtTextOut 中,我调用 LPToDP API 将位置转换为设备上下文位置。然后它工作正常。文字位置正确。
WindowWrapper.LPtoDP(hdc, arrPoint, 2);
但是,如果我打电话
WindowWrapper.RedrawWindow(topWnd, ref location, IntPtr.Zero, RedrawWindowFlags.UpdateNow | RedrawWindowFlags.Frame | RedrawWindowFlags.Invalidate | RedrawWindowFlags.AllChildren | RedrawWindowFlags.Erase);
然后它失败了。位置不正确。我看到它通过使用 LPToDP 翻译到不正确的位置。
有人知道这个问题吗?我们该如何解决?
public static bool ExtTextOutW_Hook(IntPtr hdc, int X, int Y, uint fuOptions,
IntPtr lprc, [MarshalAs(UnmanagedType.LPWStr)] string lpString,
uint cbCount, IntPtr lpDx)
{
try
{
lock (IsRetrievingSynch)
{
if (IsRetrieving && !string.IsNullOrEmpty(lpString) && cbCount > 0)
{
TextData textData = new TextData();
textData.FuncName = "ExtTextOutW";
char[] text = new char[cbCount];
bool isGlyphIndex = ((fuOptions & 0x0010) == 0x0010);
//ETO_GLYPH_INDEX
if (isGlyphIndex)
{
FontMap fontMap = GlyphCharMap.LoadGlyphCharMap(hdc);
if (fontMap != null && fontMap.GlyphCharMap != null)
{
for (int i = 0; i < cbCount; i++)
{
ushort glyph = lpString[i];
if (glyph < fontMap.GlyphCharMap.Length)
{
if (fontMap.GlyphCharMap[glyph] != 0)
{
text[i] = (char)(fontMap.GlyphCharMap[glyph]);
}
else
{
text[i] = (char)32;
}
}
else
{
text[i] = (char)glyph;
}
}
}
}
else
{
for (int i = 0; i < cbCount; i++)
{
text[i] = lpString[i];
}
}
textData.Text = new string(text);
textData.Text = textData.Text.Normalize(NormalizationForm.FormKC);
//textData.Text = textData.Text.Trim();
if (!string.IsNullOrEmpty(textData.Text))
{
int realCount = textData.Text.Length;
TEXTMETRICW tm = new TEXTMETRICW();
WindowWrapper.GetTextMetricsW(hdc, out tm);
int[] nWidth = new int[1];
WindowWrapper.GetCharWidth32W(hdc, ' ', ' ', nWidth);
textData.CharHeight = tm.tmHeight;
textData.CharWidth = nWidth[0];
textData.CharWidths = new int[realCount];
for (int i = 0; i < realCount; i++)
{
nWidth = new int[1];
WindowWrapper.GetCharWidth32W(hdc, textData.Text[i], textData.Text[i], nWidth);
textData.CharWidths[i] = nWidth[0];
}
uint textAlign = WindowWrapper.GetTextAlign(hdc);
POINT ptStartPos = new POINT();
if ((textAlign & WindowWrapper.TA_UPDATECP) > 0)
{
WindowWrapper.GetCurrentPositionEx(hdc, out ptStartPos);
}
else
{
ptStartPos.X = X;
ptStartPos.Y = Y;
}
switch (textAlign & (WindowWrapper.TA_BASELINE | WindowWrapper.TA_BOTTOM | WindowWrapper.TA_TOP))
{
case WindowWrapper.TA_BOTTOM:
textData.Location.Top = Y - tm.tmHeight;
textData.Location.Bottom = Y;
break;
case WindowWrapper.TA_BASELINE:
textData.Location.Top = Y - tm.tmAscent;
textData.Location.Bottom = Y + tm.tmDescent;
break;
case WindowWrapper.TA_TOP:
default:
textData.Location.Top = Y;
textData.Location.Bottom = Y + tm.tmHeight;
break;
}
int nLAlign = 0, nRAlign = 0;
switch (textAlign & (WindowWrapper.TA_LEFT | WindowWrapper.TA_RIGHT | WindowWrapper.TA_CENTER))
{
case WindowWrapper.TA_LEFT:
nLAlign = 0;
nRAlign = 2;
break;
case WindowWrapper.TA_CENTER:
nLAlign = -1;
nRAlign = 1;
break;
case WindowWrapper.TA_RIGHT:
nLAlign = -2;
nRAlign = 0;
break;
}
SIZE size = new SIZE();
if (WindowWrapper.GetTextExtentPoint32W(hdc, lpString, (int)cbCount, ref size))
{
textData.Location.Left = X + nLAlign * (size.CX / 2);
textData.Location.Right = X + nRAlign * (size.CX / 2);
}
else
{
textData.Location.Left = X - 20;
textData.Location.Right = X + 20;
}
LogFactory.RemoteLog.TraceDebug(string.Format("1.ExtTextOutW {0} {1} {2} {3} {4}",
textData.Text, textData.Location.Left, textData.Location.Top,
textData.Location.Right - textData.Location.Left,
textData.Location.Bottom - textData.Location.Top));
//Utility.ClipViewPort(hdc, ref textData.Location);
POINT[] arrPoint = new POINT[2];
arrPoint[0] = new POINT()
{
X = textData.Location.Left,
Y = textData.Location.Top
};
arrPoint[1] = new POINT()
{
X = textData.Location.Right,
Y = textData.Location.Bottom
};
POINT ptDCOrg = new POINT();
WindowWrapper.LPtoDP(hdc, arrPoint, 2);
textData.Location.Left = arrPoint[0].X;
textData.Location.Top = arrPoint[0].Y;
textData.Location.Right = arrPoint[1].X;
textData.Location.Bottom = arrPoint[1].Y;
WindowWrapper.GetDCOrgEx(hdc, out ptDCOrg);
textData.Location.Left += ptDCOrg.X;
textData.Location.Top += ptDCOrg.Y;
textData.Location.Right += ptDCOrg.X;
textData.Location.Bottom += ptDCOrg.Y;
LogFactory.RemoteLog.TraceDebug(string.Format("2.ExtTextOutW {0} {1} {2} {3} {4}",
textData.Text, textData.Location.Left, textData.Location.Top,
textData.Location.Right - textData.Location.Left,
textData.Location.Bottom - textData.Location.Top));
StringBuilder fontName = new StringBuilder();
fontName.Capacity = 260;
WindowWrapper.GetTextFace(hdc, 260, fontName);
textData.Font = fontName.ToString();
IntPtr hWnd = WindowWrapper.WindowFromDC(hdc);
if (WindowWrapper.IsWindowVisible(hWnd))
{
textData.Hdc = hdc;
textData.Hwnd = hWnd;
textData.ZOrder = WindowWrapper.GetZOrder(hWnd);
if (Utility.IsIntersect(_location, textData.Location) && WindowWrapper.IsChildWindow(_topWindow, hWnd))
{
LogFactory.RemoteLog.TraceVerbose(string.Format("3.ExtTextOutW {0} {1} {2} {3} {4} Z-Order: {5}",
textData.Text,
textData.Location.Left,
textData.Location.Top,
textData.Location.Right - textData.Location.Left,
textData.Location.Bottom - textData.Location.Top,
textData.ZOrder));
if (TextDataChannel != null)
TextDataChannel.SendTextData(textData);
}
}
else
{
textData.Hdc = hdc;
//if (lpDx != IntPtr.Zero)
// Utility.ClipViewPort(hdc, ref textData.Location);
_tempDataList.Add(textData);
}
}
}
}
}
catch (Exception ex)
{
LogFactory.RemoteLog.TraceError("ExtTextOutW " + ex.Message);
}
return ExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx);
}
谢谢。