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

B

Bill Rogers

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
 
M

Mattias Sjögren

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
 
B

Bill Rogers

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
 
M

Mattias Sjögren

Bill,
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.

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
 
B

Bill Rogers

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);
 
Joined
Jan 14, 2009
Messages
1
Reaction score
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!
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Top