为什么GetCaretPos对于远程编辑返回不同于GetTextExtentPoint32的值

时间:2019-07-17 10:05:24

标签: winapi

该编辑位于其他程序中(不了解DPI)。我的程序正在尝试获取文本宽度。

    std::wstring text = L"1234";
    HWND edit = 0x04AC1BF0;
    // AttachThreadInput
    // ...
    auto ret1 = ::GetCaretPos(&pt1); // pt1 => {x=1 y=1}
    // Set text to "1234" here
    // ...
    ::Sleep(3000);
    auto ret2 = ::GetCaretPos(&pt2); // pt2 => {x=25 y=1}

    HDC hdc = GetDC(edit);
    auto hFont = (HFONT)SendMessage(edit, WM_GETFONT, 0, 0);
    auto oldObj = SelectObject(hdc, hFont);
    CSize size1;
    auto ret3 = GetTextExtentPoint32(hdc, text.c_str(), text.size(), &size1); // size1 => {cx=32 cy=16}
    CRect rect1;
    DrawText(hdc, text.c_str(), text.size(), &rect1, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE); // {LT(0, 0) RB(32, 16)  [32 x 16]}
    SelectObject(hdc, oldObj);
    ReleaseDC(edit, hdc);

因此GetTextExtentPoint32的行为与DrawText相同。它们都将宽度返回为32GetCaretPos的结果从{1, 1}变为{25, 1},表示宽度为24

我的计算机上DPI为150%。如果我将DPI设置为100%,则这些API返回的值请勿更改。所以我认为这不是因为DPI的影响。

这两个API有什么关系?


使用API​​监视工具,我可以看到程序本身调用GetTextExtentPoint32A并返回[24, 12]。行为类似于GetCaretPos。

我如何获得与目标进程本身相同的结果?


现在事情变得更加有趣了!如果我创建字体并再次选择它,那么GetTextExtentPoint32返回[24, 12]

LOGFONT font = { 0 };
::GetObject(hFont, sizeof(LOGFONT), &font);
hFont = ::CreateFontIndirect(&font);
auto oldObj = ::SelectObject(hdc, hFont);

如果我在重新创建DrawText之前对其进行编辑,则可以看到字体为Bold,但是在重新绘制并重新绘制字体之后,它看起来为Normal

您能解释一下吗?

2 个答案:

答案 0 :(得分:1)

GetCaretPos的{​​{3}}说

  

此API不参与DPI虚拟化。

另一方面,您提到的其他两个功能确实参与了DPI虚拟化。

答案 1 :(得分:0)

'WM_GETFONT'返回值是控件使用的字体的句柄,如果控件使用的是系统字体,则返回NULL。 您可以尝试一下:

HFONT hFont =(HFONT)SendMessage(edit,WM_GETFONT,0,0); 
if(NULL == hFont)
hFont =(HFONT)GetStockObject(SYSTEM_FONT);