Why GetCaretPos returns different from GetTextExtentPoint32 for a remote edit

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