Why GetCaretPos returns different from GetTextExtentPoint32 for a remote edit

364 Views Asked by At

The edit is in a different program (DPI unaware). My program is trying to get the text width.

    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);

So GetTextExtentPoint32 behaves the same as DrawText. They both returns width as 32. Result of GetCaretPos changes from {1, 1} to {25, 1}, means the width is 24.

DPI is 150% on my computer. Those APIs return values don't change if I set DPI it to 100%. So I think it is not because of DPI impact.

What's the relationship of those 2 APIs?


With API monitor tool, I can see the program itself calls GetTextExtentPoint32A and returns [24, 12]. That behaves similar to GetCaretPos.

How could I get the same result as the target process itself?


Things become more interesting now! If I create the font and select it again, then GetTextExtentPoint32 returns [24, 12]!

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

If I DrawText to the edit before recreation, I can see the font is Bold, but after font recreation and redrawn, it looks Normal.

Could you explain this?

2

There are 2 best solutions below

8
David Heffernan On

The documentation for GetCaretPos says

This API does not participate in DPI virtualization.

On the other hand, the other two functions that you mention do participate in DPI virtualization.

0
Jeffreys On

'WM_GETFONT' return value is a handle to the font used by the control, or NULL if the control is using the system font. You can have a try like it:

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