how do I find a .net control's instance name from an hWnd

Discussion in 'Microsoft Dot NET Framework' started by Bill Rogers, Oct 16, 2003.

  1. Bill Rogers

    Bill Rogers Guest

    Hi all,
    I am writing an automated testing app for VB.net. I can find all of the
    window handles for the app under test, but now I need to get from the handle
    back to the .net control instance and examine its properties. First I want
    to find out its instance name, later I want to examine its other properties.
    I can get the type information corresponding to the window, but I am drawing
    a complete blank on how to get to the control instance associated with that
    window. I know this can be done because I have object browsers that do it.
    Thanks,
    Bill
     
    Bill Rogers, Oct 16, 2003
    #1
    1. Advertisements

  2. Bill,

    If you're in the same process, Control.FromHandle() does what you
    want. If you're in a different process, I don't think there's a way to
    do what you want.



    Mattias
     
    Mattias Sjögren, Oct 17, 2003
    #2
    1. Advertisements

  3. Bill Rogers

    Bill Rogers Guest

    Hi Mattias,
    Thanks for your suggestion.
    I am out of process so Control.FromHandle() won't work. I know it can be
    done because I have an object browser that can find the instance names of
    ..net controls out of process.
    Thanks,
    Bill
     
    Bill Rogers, Oct 17, 2003
    #3
  4. Bill,
    Well if the control name is all you need there are tricks to get that.
    Windows Forms controls response to a window message called
    WM_GETCONTROLNAME (get the message number with
    RegisterWindowMessage("WM_GETCONTROLNAME")). It takes a buffer length
    integer as the wParam and a buffer pointer as lParam and fills the
    buffer with the control name in Unicode or ANSI encoding, depending on
    the platform. If you pass in a NULL buffer pointer you get the
    required buffer byte length back. If the buffer is too small you get
    back -1, otherwise it returns the number of characters copied to the
    buffer.

    You could send this message to a Windows Forms control from another
    process, as long as you can provide a buffer pointer that's valid in
    the winforms app process. Given sufficient privileges, your app can
    get that with VirtualAllocEx.



    Mattias
     
    Mattias Sjögren, Oct 17, 2003
    #4
  5. Bill Rogers

    Bill Rogers Guest

    Hi Mattias,
    Thanks for the pointers. I have been successful in getting the name
    following your directions. Here is a C++ code snippet that does the trick
    for anyone else who might need to do the same thing.
    I think there are alternative methods for managed code using
    System.Reflection or the CLR debugging facilities. I have not investigated
    these possibilities.
    Regards,
    Bill

    /*
    given an hWnd, this code attempts to send a message to the window to get the
    instance name of the control bound to the window
    Steps:
    1. Get the Value of the WM_GETCONTROLNAME message (RegisterWindowMessage)
    2. Get the Process Info for this window (GetWindowThreadProcessId)
    3. Open the process and get a process handle (OpenProcess)
    4. Allocate memory within the target process (VirtualAllocEx)
    5. Send the target window a WM_GETCONTROLNAME message and a pointer to the
    memory (SendMessageTimeout)
    6. Read the response from the allocated memory (ReadProcessMemory)
    7. Close process handle, release memory
    */
    //we enter this code with hwnd set to a specific window handle
    //error checking omitted for brevity
    const int bufsize = 1024;
    wchar_t CtlName[bufsize];
    DWORD ProcessId;
    SIZE_T NumRead;
    unsigned int GetName = RegisterWindowMessage(L"WM_GETCONTROLNAME");
    DWORD dwResult = GetWindowThreadProcessId(hwnd, &ProcessId);
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,false,ProcessId);
    LPVOID OtherMem = VirtualAllocEx(hProcess, 0, bufsize, MEM_COMMIT,
    PAGE_READWRITE);
    LPARAM lpOtherMem = reinterpret_cast<LPARAM>(OtherMem);
    unsigned int SendFlags = SMTO_ABORTIFHUNG|SMTO_BLOCK;
    LRESULT lResult = SendMessageTimeout(hwnd, GetName, bufsize, lpOtherMem,
    SendFlags, 5000, &NumRead);
    //if lResult == 0 then failure or timeout, if GetLastError reports 0, then
    it is a timeout
    //if successful NumRead contains the number of characters, if NumRead == 0
    then the name is empty
    BOOL bResult = ReadProcessMemory(hProcess, OtherMem, CtlName, bufsize,
    &NumRead);
    //CtlName now contains the instance name of the control, or is empty if
    there is no name
    //clean up
    bResult = CloseHandle(hProcess);
    bResult = VirtualFreeEx(hProcess,OtherMem,1024,MEM_RELEASE);
     
    Bill Rogers, Oct 28, 2003
    #5
  6. Bill Rogers

    oliverikawood

    Joined:
    Jan 14, 2009
    Likes Received:
    0
    Hi Bill,
    I am doing this in VB 6. I follow this article http://msdn.microsoft.com/en-us/library/ms996405.aspx

    1. Get the Value of the WM_GETCONTROLNAME message (RegisterWindowMessage)
    2. Send message to the control's HWND for getting the specified controlname (SendMessage)
    3. The string comes back as Unicode. Convert to MultiByte and store it (WideCharToMultiByte)

    But I can't get the lparam return from SendMessage API, it always comes with null although the length is not 0. Do I use SendMessage uncorrectly? Because in your C++ code I saw that you're using GetWindowThreadProcessId, OpenProcess, and so on. Are they necessary for VB code also? Thanks!
     
    oliverikawood, Jan 14, 2009
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.