Home > Back-end >  How to use CHILDID_SELF?
How to use CHILDID_SELF?

Time:10-02

I found this article and tried to follow it to find the position of the caret in any Windows application:

How to get caret position in ANY application from C#?

However, I have a problem with following it.

This is the C# code I was following:

var guid = typeof(IAccessible).GUID;
object accessibleObject = null;
var retVal = WinApiProvider.AccessibleObjectFromWindow(hwnd, WinApiProvider.OBJID_CARET, ref guid, ref accessibleObject);
var accessible = accessibleObject as IAccessible;

accessible.accLocation(out int left, out int top, out int width, out int height, WinApiProvider.CHILDID_SELF);

But I have no idea how to put CHILDID_SELF in the fifth parameter of the IAccessible::accLocation() function:

Rect rect;
VARIANT varCaret;
varCaret.vt = VT_I4;
varCaret.lVal = CHILDID_SELF;

std::cout << object->accLocation(&rect.x, &rect.y, &rect.w, &rect.h, varCaret);

After some research, I found out that I should put CHILDID_SELF in this way. But it's not working as expected.

I assume this should be able to get the position of the caret in Microsoft Edge or Chrome, but it just returns S_FALSE.

The guy from the link also didn't get the caret position from Chrome or other windows, but made it work after adding CHILDID_SELF. So, I guess the problem I have is related to the way that I'm using CHILDID_SELF.

I'm also using 21H1 build 19043.1889, but still I'm using 21H1 so it shouldn't be the problem, in my opinion.

I also tried to just plug it in, but of course C didn't let me do that:

object->accLocation(&rect.x, &rect.y, &rect.w, &rect.h, CHILDID_SELF);
object->accLocation(&rect.x, &rect.y, &rect.w, &rect.h, (VARIANT)CHILDID_SELF);

What would be the solution of this problem? Am I doing something wrong?

FULL CODE

#include <iostream>
#include <Windows.h>
#include <oleacc.h>

#pragma comment(lib, "Oleacc.lib")

typedef struct {
    long x;
    long y;
    long w;
    long h;
} Rect;

int main(int argc, char* argv[]) {
    HWND hwnd;
    DWORD pid;
    DWORD tid;

    while (true) {
        system("cls");
        GUITHREADINFO info;
        info.cbSize = sizeof(GUITHREADINFO);

        hwnd = GetForegroundWindow();
        tid = GetWindowThreadProcessId(hwnd, &pid);

        GetGUIThreadInfo(tid, &info);

        IAccessible* object = nullptr;
        if (SUCCEEDED(AccessibleObjectFromWindow(info.hwndFocus, OBJID_CARET, IID_IAccessible, (void**)&object))) {
            Rect rect;
            VARIANT varCaret;
            varCaret.vt = VT_I4;
            varCaret.lVal = CHILDID_SELF;

            object->accLocation(&rect.x, &rect.y, &rect.w, &rect.h, varCaret);
            std::cout << rect.x << std::endl;

            object->Release();
        }

        Sleep(10);
    }

    return 0;
}

Used Microsoft Visual Studio 2019, x86, Debug to build

CodePudding user response:

Your first code snippet is the correct way to pass CHILDID_SELF in a VARIANT parameter, per the documentation:

How Child IDs Are Used in Parameters

When initializing a VARIANT parameter, be sure to specify VT_I4 in the vt member in addition to specifying the child ID value (or CHILDID_SELF) in the lVal member.

So, the problem must be something else. For instance, one thing I notice is that you are not initializing the COM library before calling AccessibleObjectFromWindow(). Try calling CoInitialize/Ex() first and see if it makes a difference.

Also, you are not checking the return value of accLocation() for failure before using the RECT coordinates.

Try this:

#include <iostream>
#include <Windows.h>
#include <oleacc.h>

#pragma comment(lib, "Oleacc.lib")

typedef struct {
    long x;
    long y;
    long w;
    long h;
} Rect;

int main(int argc, char* argv[]) {
    HWND hwnd;
    DWORD pid;
    DWORD tid;

    CoInitialize(nullptr); // <-- add this

    while (true) {
        system("cls");

        GUITHREADINFO info;
        info.cbSize = sizeof(GUITHREADINFO);

        hwnd = GetForegroundWindow();
        tid = GetWindowThreadProcessId(hwnd, &pid);

        GetGUIThreadInfo(tid, &info);

        IAccessible* object = nullptr;
        if (SUCCEEDED(AccessibleObjectFromWindow(info.hwndFocus, OBJID_CARET, IID_IAccessible, (void**)&object))) {
            Rect rect;

            VARIANT varCaret;
            varCaret.vt = VT_I4;
            varCaret.lVal = CHILDID_SELF;

            if (SUCCEEDED(object->accLocation(&rect.x, &rect.y, &rect.w, &rect.h, varCaret))) {
                std::cout << rect.x << std::endl;
            }

            object->Release();
        }

        Sleep(10);
    }

    CoUninitialize(); // <-- add this

    return 0;
} 
  • Related