GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 03-Jan-2006, 00:12
blank blank is offline
Junior Member
 
Join Date: May 2005
Posts: 39
blank is on a distinguished road

Getting Input from a Window


I dont know if this belongs here or .net

Hey guys, I'm not sure if I named my thread right, but here goes. My goal is to create an application that will receive and analyze window xyz's output.

So, have this game based on the quake 3 engine. It has a 'console', which is seperate from the main window. This console shows the output of all the events that have happened, who said what in chat, etc. What I want to do is analyze this output in my program so that I could do certain things based on the output. Say in game my name is Player, and I say !hello, the program would scan the output for !hello, and then do accordingly. I know this could be done since there are many examples (killtrackers). I had a control in VB.Net that did particularly this, however, the source wasn't included. I've asked the guy who made it and all he tells me is it was done using the .net framework. I dont know if he means the GUI part or the actual system part where it analyzes the output of the console.

In my understandment, a window could be a button. Basically I'd like to know how I could see what the text in a certain button (for which I have the window handle etc.) is, so then I could later analyze this text and compare it against my variables. Perhaps a button isn't the best example, since I am mostly accessing this 'console' by it's name (maybe by using the FindWindowEx function passed with the window name). After I have this 'window', I'd like to analyze, or better yet, 'capture' this data into my program. Am I clear? Could someone please point me in the right direction?
  #2  
Old 06-Jan-2006, 06:17
Levia Levia is offline
Junior Member
 
Join Date: Jan 2006
Posts: 65
Levia is on a distinguished road

Re: Getting Input from a Window


Yes i wanna know this one too
  #3  
Old 06-Jan-2006, 23:15
ubergeek ubergeek is offline
Regular Member
 
Join Date: Jan 2005
Posts: 775
ubergeek is a jewel in the roughubergeek is a jewel in the roughubergeek is a jewel in the rough

Re: Getting Input from a Window


Well you're on the right track with FindWindow function. Download the program AutoIt. this is a windows scripting language, but what you want is hte AutoIt Window Spy (I've also heard of a Spy++ but don't know what this is or where to get it). Anyways, the Window Spy lets you click on any window and it displays information you need for FindWindow, text and class name. Additionally, click on a control and you can get the control's text, class, etc. Once you have a handle to the control, you can call GetWindowText() and then you have a string you can search.
that was rather dense. here's some code:
CPP / C++ / C Code:
#include "windows.h"
void getControlText(char *wndname, char *wndclass, char *ctrltext, char *ctrlclass, char *output)
{
    HWND hParent = FindWindowEx(NULL, NULL, wndclass, wndname); //call with NULL as parent to search top-level windows for this "console" window
    HWND hControl = FindWindowEx(hParent, NULL, ctrlclass, ctrltext); //call with parent window to find textbox/button/whatever
    long length = GetWindowTextLength(hControl); //get length of text in control
    output = (char*)malloc(length + 2); //allocate enough memory, +2 to be err on the side of caution
    GetWindowText(hControl, output, length + 1); //get the text (length parameter includes NULL char)
}
This function will allocate memory and put the text into output of the control specified by its parent window's text and class, and its own text and class. The client MUST free(output). Note that the function does absolutely no error checking. I also did not test it, so post back if it doesn't work.
P.S. Whoops, I'm so used to C++. I just realized that I wrote C code (I even remembered to use malloc instead of new) but put C++ single-line comments...oops.
  #4  
Old 07-Jan-2006, 21:09
blank blank is offline
Junior Member
 
Join Date: May 2005
Posts: 39
blank is on a distinguished road

Re: Getting Input from a Window


Haha, I'm a C++er but I often find myself writing C lol. Anyways, thanks for the help. Anyways, I used a program called WinSpector, I encourage you to try it out (like Spy++, free).

Anyways, in my program (I had an example to look at, although it was in VB6). Anyways, I got it working, here is an older version of my working source ( http://blank.cjb.cc/code4/?a=sb&i=22 ), but by now it already has more features. Anyways, I have encountered another 'problem'.

The 'line' varaible (LPSTR) gets updated constantly. See, what I'm doing is monitoring a console 'Edit control' of a game I play. Everything that happens is logged/shown in the edit control. The last line (which is the line I get, doesn't show that in the link I gave however) is therefore constantly changing of value, to the last line logged by the console (for example, if I say 'Hi', if I die, if someone leaves, etc.). So now my problem is trying to somehow always keep an updated version. I'm stumped though, since I always think at large even when I'm not supposed to, and I dont know what to do.

Someone told me to hook the edit control and wait for an EN_UPDATE message to see if the text changed, someone else said that was overkill, but do look for the EN_UPDATE message (how, using GetMessage()?). What I was thinking was either making a loop (how would I make it? what type, for or while?) or implement a timer and get the new value every certain amount of milliseconds (maybe creating this process as it's own thread).

If you have any pointers on this I'd greatly appreciate. The hard thing would be testing if it worked, since you most likely dont have the game (Jedi Outcast), so pointers/hints/suggestions would be nice. The code in the link doesn't match what I have, I already implemented a 'GetLastLine' function, which I will upload later (just reformatted).

EDIT: updated the code, I'll post it here as well just in case it's hard to read:

Q3Tracker.cpp
CPP / C++ / C Code:
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "fmodvc.lib")

#include <windows.h>
#include <mmsystem.h>
#include <inc/fmod.h>

#include "Tracker.h"

// GLOBALS

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("Q3Tracker");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	wndclass.style			= CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= 0;
	wndclass.cbWndExtra		= DLGWINDOWEXTRA;	// note
	wndclass.hInstance		= hInstance;
	wndclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)(COLOR_BTNFACE +1);
	wndclass.lpszMenuName	= NULL;
	wndclass.lpszClassName	= szAppName;

	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
		return 0;
	}
	
	hwnd = CreateDialog(hInstance, szAppName, 0, NULL);

	ShowWindow(hwnd, iCmdShow);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;

	switch(message)
	{
		case WM_CREATE:
			return 0;

		case WM_PAINT:
			return 0;

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

Tracker.h
CPP / C++ / C Code:
#ifndef TRACKER_H
#define TRACKER_H

#include <windows.h>

class Tracker
{
	public:
		Tracker(LPSTR wndname);
		~Tracker();

		LPSTR GetLine(int linenumber);
		LPSTR GetLastLine();
		LRESULT CountLines();
		HWND GetConsole(LPSTR conswndname);

	private:
		HWND console;
		LPSTR lastline;
};
#endif

Tracker.cpp
CPP / C++ / C Code:
#include "Tracker.h"

Tracker::Tracker(LPSTR wndname)
{
	GetConsole(wndname);
}

Tracker::~Tracker()
{
	// -
}

LPSTR Tracker::GetLine(int linenumber)
{
	int lineindex;
	LRESULT length;
	LRESULT chars;
	LPSTR buff;

	lineindex = SendMessage(console, EM_LINEINDEX, (WPARAM)linenumber, 0);
	length = SendMessage(console, EM_LINELENGTH, (WPARAM)lineindex, 0);
	
	buff = (LPSTR)GlobalAlloc(GPTR, length+1);
	*(WORD *)buff = (WORD)length;
	
	chars = SendMessage(console, EM_GETLINE, (WPARAM)linenumber, (LPARAM)buff);
	buff[chars] = '\0';

    return buff;
}

LPSTR Tracker::GetLastLine()
{
	LRESULT lines = CountLines();
	int lastline = (lines - 2);
	LPSTR line = GetLine(lastline);
	return line;
}

LRESULT Tracker::CountLines()
{
	LRESULT linecount = SendMessage(console, EM_GETLINECOUNT, 0, 0);
	return linecount;
}

HWND Tracker::GetConsole(LPSTR consolename)
{
	HWND winh;
	HWND edith1;
	HWND edith2;

    if((winh = FindWindow(consolename, NULL)) == NULL)
		return NULL;

    if((edith1 = FindWindowEx(winh, 0, "edit", NULL)) == NULL)
		return NULL;
	
    if((edith2 = FindWindowEx(winh, edith1, "edit", NULL)) == NULL)
		return NULL;
	
	return edith2;
}
  #5  
Old 08-Jan-2006, 00:16
ubergeek ubergeek is offline
Regular Member
 
Join Date: Jan 2005
Posts: 775
ubergeek is a jewel in the roughubergeek is a jewel in the roughubergeek is a jewel in the rough

Re: Getting Input from a Window


i believe you may actually have to use a hook. Here is why. first a little background: You obviously know about the concept of a window procedure; your main window has one. the window containing the edit control you're tracking has a window procedure, too. that window procedure receives EN_CHANGE and EN_UPDATE messages. you want those messages. the obvious choice would be subclassing, the idea of which is substituting your own function for another window's window procedure, in which you snoop in thte messages you're interested in and then call the original window procedure. this would work for you (i think) if you have a version of Windows before NT/2000/XP. However, NT/2k/XP have decided that you can't subclass windows that aren't in your process. how inconvenient. that's why you would have to use a message hook.
A hook is a function that you register with Windows, that receives notification when certain things occur. there are many kinds of hooks -- some listen to window creation and destruction, some to mouse clicks, some to messages. the last one is what you want.
there are two kinds of hooks -- system hooks and thread-specific hooks. you really only care about the messages in one specific thread (the thread containing the console), so you don't need to bog down the whole system by checking every message. because the thread you want to hook is in another process (here comes those annoying security features again) you'll need to put your hook handler in a DLL.
you register the hook by calling SetWindowsHookEx(). In this case, we'll want a WH_GETMESSAGE hook, so we can sniff out EN_UPDATE. you'll need to give it an HMODULE returned from LoadLibrary() of your DLL as the hMod parameter, and for the lpfn parameter, the pointer to your hook function received by GetProcAddress(). Now, you ask, all i have is the HWND, but i want the thread ID? good question. for this there is the GetWindowThreadProcessId() function. you would call it with the window containing the console, not the edit control itself, although it probably wouldn't matter.
Then, you would check WM_COMMAND messages in your hook handler, and when you got an EN_UPDATE notification, check if it's the HWND of the edit control you are tracking, and if it is, call your GetLastLine function.

look up all these functions on MSDN for more reference. if i went over something too fast, don't hesitate to ask me to elaborate. i can also help in creating the DLL, as i have done this before and started out as clueless about it as you may be.

hth, ubergeek
  #6  
Old 08-Jan-2006, 13:37
blank blank is offline
Junior Member
 
Join Date: May 2005
Posts: 39
blank is on a distinguished road

Re: Getting Input from a Window


I greatly appreciate all your help, ubergeek. I at first didn't want to use hooks because as much as I tried, I didn't know where to start (what functions to use, etc.). This is very informative, and I wouldn't like to bother you anymore, so I'll look them up on my own. However, if possible, could you please provied a 'pseudo-code like' snippet? Just showing the order in which these functions are called, so I can know what to look up and what to pass to what (although you explained that very well). Also, do you mean I have to create a dll? or inject my hook into one? Thanks a lot for the information, greatly appreciated.
  #7  
Old 08-Jan-2006, 17:46
ubergeek ubergeek is offline
Regular Member
 
Join Date: Jan 2005
Posts: 775
ubergeek is a jewel in the roughubergeek is a jewel in the roughubergeek is a jewel in the rough

Re: Getting Input from a Window


hookSetter.cpp (in a .exe file):
Code:
HMODULE hDLL = LoadLibrary(name_of_your_dll) HOOKPROC phandlerFunc = GetProcAddress(hDLL, "name_of_handler_function") hConsole = FindWindowEx etc //find the jedi outcast console window DWORD jedi_outcast_thread = GetWindowThreadProcessId(hConsole, NULL) HHOOOK token = SetWindowHookEx(hDLL, WH_GETMESSAGE, phandlerFunc, jedi_outcast_thread, etc) //here you have to wait until you're done. you could WaitForSingleObject on Jedi Outcast, or just enter your message loop and wait till the user closes your main window, or set a tray icon (i can help w/ that if you want) and wait for that, or whatever UnhookWindowsHookEx(token)
in handler.cpp (in the .dll)
Code:
LRESULT __declspec(dllexport) CALLBACK GetMsgHandlerProc(int code, WPARAM wParam, LPARAM lParam) { check the message to see if it's headed for your target window, and if it's an EN_UPDATE notification, and if it is handle it. the wParam and lParam here don't correspond to what is in the window procedure. look it up on MSDN; basically the LPARAM contains a MSG structure, which will tell you the HWND, message code, and real wParam/lParam }
a DLL is a kind of binary file that is not executable by itself. rather, it is some functions in a file, and other programs can call the programs that the DLL exports. the DLL is not part of your program, it has its own variables, so it would be a good idea to have a setup function in your DLL that your listener program would call just before setting the hook, to give the DLL the HWND to test for and a way to call home. the way you export a function (so that it can be accessed via GetProcAddress) is by putting __declspec(dllexport) after the return type, like in the example. that's for gcc, im not sure about other compilers.
i hope that explanation was almost follow-able, tell me what you're still confused about
  #8  
Old 12-Jan-2006, 11:07
blank blank is offline
Junior Member
 
Join Date: May 2005
Posts: 39
blank is on a distinguished road

Re: Getting Input from a Window


Thanks man, anyways, for the

Code:
LRESULT __declspec(dllexport) CALLBACK GetMsgHandlerProc(int code, WPARAM wParam, LPARAM lParam) { check the message to see if it's headed for your target window, and if it's an EN_UPDATE notification, and if it is handle it. the wParam and lParam here don't correspond to what is in the window procedure. look it up on MSDN; basically the LPARAM contains a MSG structure, which will tell you the HWND, message code, and real wParam/lParam }

IS it like a simple message looop? So I'd do

Code:
LRESULT __declspec(dllexport) CALLBACK GetMsgHandlerProc(int code, WPARAM wParam, LPARAM lParam) { WH_GetMessage: ? }

I dont need the stuff exactly just bit more uh, hintier, thanks for the help so far ubergeek!
 
 

Recent GIDBlogToyota - 2008 November Promotion by Nihal

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
How to minimize a application to the system tray? Thomas555 C++ Forum 12 20-May-2005 14:35
#including resource file causing window procedure to be undeclared??? ubergeek C++ Forum 3 07-Feb-2005 15:39
Changing window start colour Rosdahale C++ Forum 5 19-Jan-2005 16:51
[C] Discarding input Alhazred C Programming Language 8 04-Aug-2004 12:45
IP tables rogermark100 C Programming Language 6 18-Apr-2004 08:22

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 06:00.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.