Click here to Skip to main content
15,891,767 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
There are some windows where I can't get the text insicde with a WM_GETTEXT, so I tried to replace WndProc with a standard one.

I'm trying to replace the WndProc function from a window that has been created by another application. I'm trying to do it in a thread created by a windows hook to keyboard.

What I've tried without any success (3 different cases):

1. Create a "EDIT" window, get the WndProc and replace the WndProc of the app by the new:
(idea from: http://www.codeguru.com/Cpp/I-N/ieprogram/security/article.php/c4387[^])

String ^ReadWindowText(HWND g_hTarget)
{
	char buff1[MAX_DATASIZE];
	int err;
	
	this->ClearBuffer<char>(buff1, MAX_DATASIZE);
	
	HWND hParent = GetParent(g_hTarget); //g_hTarget is the edit handle we are interested
	HINSTANCE hInstance = (HINSTANCE) GetWindowLongPtr(hParent, GWLP_HINSTANCE); //Handle to the instance of the module to be associated with the window
	
	// Create new Edit window with standard WndProc
	HWND hwndEdit = CreateWindow(_T("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 0, 0, hParent, (HMENU) 111, hInstance, NULL);
	
	if (!hwndEdit) err = GetLastError();
	
	// Get the standard Windows Procedure of Edit class
	LONG_PTR lpNewProc = GetWindowLongPtr(hwndEdit, GWLP_WNDPROC);
	LONG_PTR lastProc = SetWindowLongPtr(g_hTarget, GWLP_WNDPROC, (LONG_PTR)lpNewProc);
	
	if (!lastProc) err = GetLastError();
	//Text reading
	int len = SendMessage(g_hTarget, WM_GETTEXT, MAX_DATASIZE, (LPARAM) buff1);
	len = SendMessage(g_hTarget, WM_GETTEXTLENGTH, 0, 0);
	buff1[len] = 0;
	
	//Reset the original Windows Procedure
	SetWindowLongPtr(g_hTarget, GWLP_WNDPROC, (LONG_PTR)lastProc);
	
	return gcnew String(buff1);
};


2. Same as before, this time create a HWND_MESSAGE window
(idea from: http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29#message_only[^])

String ^ReadWindowText1(HWND g_hTarget)
{
(...)
	
	// Create Message recieving window
	HWND hwndEdit = CreateWindow(_T("STATIC"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 0, 0,  HWND_MESSAGE, (HMENU) 111, hInstance, NULL);
	
(...)
};


3. Replace WndProc with my own procedure (in the application that creates the window). I'm not really sure if this could even work, but I wanted to be sure...
(idea from: http://www.gamedev.net/topic/511138-how-to-get-raw-input-data-from-the-win-32-api-thats-not-dependant-on-a-window/[^])

delegate LRESULT StaticWindowProcDelegate( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam );
delegate LRESULT WindowProcDelegate( HWND wnd, WNDPROC wnd_proc, UINT msg, WPARAM wParam, LPARAM lParam );
WindowProcDelegate^ sWindowStore;
LONG_PTR lastProc;

String ^ReadWindowText2(HWND g_hTarget)
{
(...)
	sWindowStore = gcnew WindowProcDelegate(this, &LectorHD::WindowProc);
	lastProc = GetWindowLongPtr( g_hTarget, GWLP_WNDPROC ); 
	if( !lastProc ) err = GetLastError();
	
	// Override window procedure
	StaticWindowProcDelegate^ swpd = gcnew StaticWindowProcDelegate(this, &LectorHD::StaticWindowProc);
	if(!SetWindowLongPtr( g_hTarget, GWLP_WNDPROC, (LONG_PTR) Marshal::GetFunctionPointerForDelegate(swpd).ToPointer()) ) // This is the override WndProc
		err = GetLastError();
	
(...)
};

LRESULT StaticWindowProc( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam ) 
{
	return sWindowStore( wnd, (WNDPROC) lastProc, msg, wParam, lParam );
};

LRESULT WindowProc( HWND wnd, WNDPROC wnd_proc, UINT msg, WPARAM wParam, LPARAM lParam ) 
{
	switch( msg ) 
	{
		case WM_GETTEXT:
		default: return CallWindowProc( wnd_proc, wnd, msg, wParam, lParam );
	}
};



Always same problem: lastProc=0 (err=0) with any application (i've tried 3 different programs, one of them is mine so I'm sure I have'nt replaced WndProc).. I can't get the text from the same windows where I could'nt do with WM_GETTEXT.

Maybe (I suspect) it is a problem of what it says in http://msdn.microsoft.com/en-us/library/ms644898%28v=vs.85%29.aspx[^]

"The SetWindowLongPtr function fails if the process that owns the window specified by the hWnd parameter is at a higher process privilege in the UIPI hierarchy than the process the calling thread resides in."

But I'm not sure if it is this, because in the first and second case I create the new window in the HWND that owns g_target (I get hInstance from the parent of g_target, so the processes must be the same for the two windows..) And if it is, I don't know how to assign higher provilege to my process.

Any help is really apreciated!
Posted
Updated 28-Mar-11 9:49am
v4
Comments
Albert Holguin 28-Mar-11 17:46pm    
This seems like a bad approach for your problem.
miqmago 28-Mar-11 17:48pm    
Thanks for your comment. Any idea on how it could be better done?
Albert Holguin 28-Mar-11 17:55pm    
any particular reason why you're avoiding MFC?
miqmago 28-Mar-11 17:59pm    
I'm not an expert in MFC and this is an icon tray application that is launched from a service when login is done, so I suposed a little difficult to do with MFC.
Albert Holguin 28-Mar-11 18:08pm    
the proper thing to do in this case would be to either:

1. Figure out why WM_GETTEXT isn't working off the back (does it support what you're trying to do in the first place?).

2. If WM_GETTEXT doesn't do exactly what you want, make your own message and event handling in the receiving window (this is very easy in MFC, would have to look up corresponding API calls).

it would take me a little bit to tell you exactly how to do it in native code, but this at least tells you the proper approach.

Hi,

If you are trying to replace the window proc from a thread that created by a low level keyboard hook then the dll is not injected into the target process. You need to inject your dll to the target process and replace the window proc definitely this will work. And are sure you will be able to get the text from a window/control that doesn't support WM_GETTEXT at all?. The owner of the control/window may directly drawing that text. In that case replacing the window proc simply causes the text to be not displayed in the window. In such a situation you need to do API hook/GDI hook to get text from the window/control

hope this helps.
 
Share this answer
 
Comments
miqmago 29-Mar-11 7:39am    
Thanks George. Good coments.
Now I'm wondering, if I do an API hook, how could I get the text when the text is already written?

The idea is: the user press Ctl+Shift+A, then the keyboard hook catches the sequence and launches a thread that EnumChildWnd from the current window. Then for the "EDIT" windows where there is text (WM_GETTEXTLENGTH>0) but can't read it with WM_GETTEXT, the thread replaces the WndProc (injecting the dll.. have to see how!). This thread should read the text of the target window..
Hi

if you only looking for EDIT box then this is possible by hooking and subclassing the window procedure.
 
Share this answer
 
Comments
miqmago 29-Mar-11 8:06am    
This is what I'm trying to do.. I think! And there is the question..

The problem is always the same:
SetWindowLongPtr(g_hTarget, GWLP_WNDPROC, (LONG_PTR)lpNewProc); returns 0 with GetLastError() = 0..
Do you know why (in the code I posted)?
Are you trying to subclass an EDIT box in another process? If yes you need to inject your dll and replace the win proc
 
Share this answer
 
v2
Comments
miqmago 29-Mar-11 8:21am    
Ok, in the code I posted, what I'm doing is:

1- Get the HWND hParent of the EDIT control that I want to subclass
2- Get the HWND to the instance of the module that created hParent, hInstance
3- Create hidden window inside hParent associated to hInstance <-- This is where I inject the WndProc of the new window¿?
4- Get the WndProc of the new window
5- Replace the WndProc of the target window by the WndProc of the injected hidden window.

And in step 5 there is the problem! When I try to replace the WndProc.. Is there any other way to do it?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900