Control is an illusion Elliot !

Hello again !

It’s been a while. Well today I wanna write about a small [useful at the time] program i made like, 7 years ago, using Visual Basic 6. I found it while I was looking through my old stuff in an old website.

Here’s a sneak peek of it (and a link to it):

WindowControl screenshot

So what does it do ? Simple : click on capture the window, and navigate with your mouse cursor on the screen, you’ll notice the “Name” and “Handle” text boxes, changing and reflecting the windows’ and objects’ names under your cursor. Now click on the window or object you wanna control. That way you’ll catch the object’s handle; after that, you’ll have the possibility to crawl through the siblings and children or parent of an object using the “Window Navigation” buttons. After you’ve settled on the desired object, you can select an action: whether you want to enable it, disable it, maximize, restore, flash, hide or show it…

Why would I go through this trouble ? Well, again, boredom, and just for fun. Also, remember those trial programs that used to give you a “Try” and “Buy” button ?  And the “Try” button would be disabled after the trial period have expired ? Well, I thought, may be there’s a way I can force that button to be enabled. So, I dived down into it, and I discovered all kinds of things I can do with the Win32 API, that also enabled me to do just that. It was a great fun exercise for me.

So the thing is, I found the exe, but I couldn’t find the source code, so again, for fun, I decided to rewrite the whole thing, using nothing but C, and Win32 API, from the ground up. Here is the link to the source code (it’s a VS2015 project), and here’s the exe link.

Now I’ll try to quickly scan the code and explain generally the logic and what each block does, but I’m not gonna go into specific details, if you want to know more about, I suggest you read follow this tutorial, it have been a great start for me: winprog.org/tutorial/.

The WinMain function is equivalent to the main()  function for console program; it is the entry point for GUI programs, and in it, we declare a window class, that hold and the properties of the window we’re going to create from cursor icon, to color, to the icon, and so on :

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nCmdShow) {

	WNDCLASSEX wc;
	HWND hwnd;
	MSG msg;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = 0;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	wc.lpszClassName = "FirstWnd";
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
	wc.lpszMenuName = NULL;
	wc.hInstance = hInstance;
	wc.lpfnWndProc = WndProc;
//[...]
}

After that, we need to register the window, create it and then show it in the screen :

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nCmdShow) {
//[...]

	if (!RegisterClassEx(&wc)) {
		MessageBox(NULL, "Error registering", "Error", MB_ICONEXCLAMATION | MB_OK);
	}
	hwnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_TOPMOST, "FirstWnd", "Parasite", WS_OVERLAPPEDWINDOW^WS_THICKFRAME^WS_MAXIMIZEBOX, 500, 100, 345, 420, NULL, NULL, hInstance, NULL);

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

//[...]
}

And finally, to finish off with the entry point, we start the message loop that’s gonna handle the message queue :

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nCmdShow) {
[...]
	while (GetMessage(&msg,NULL,0,0)>0){
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

Before I continue to the next part, I should point out that in this “new” version, you no longer have to click the capture button and click the object, all you have to do, is maintain the click on the button, and drag the mouse to your desired object (it’s like you’re simulating a drag and drop gesture). To accomplish that, I had to install a hook, that’ll intercept the mouse movements and process the outputs accordingly. Usually, to install a hook, you need to make a separate DLL file just for the hook and then use from your exe, but I wanted the program to be portable. So, I wrote the hook in the exe, and I will create a second thread, that’ll call the hook and intercept the mouse movements, and it goes something like this; I create the hook :

_declspec(dllexport) LRESULT CALLBACK MouseEvent(int Code, WPARAM wParam, LPARAM lParam) {
	
	if (Code == HC_ACTION) {
		switch (wParam)
		{
		case WM_MOUSEMOVE:
		{
//When the button is still clicked down, keep intercepting the mouse movements 
//and update the labels and the targetHandle, that store the handle of the targeted object
			if (interceptIsOn == 1) {
				MSLLHOOKSTRUCT mouse = *((MSLLHOOKSTRUCT*)lParam);
				targetHandle = WindowFromPoint(mouse.pt);
				updateLabelWithHandles();
			}			
		}
			break;
//when the mouse button is released, stop the interception
		case WM_LBUTTONUP:
			EnableWindow(hCaptureButton, true);
//This variable is to start or stop the interception
			interceptIsOn = 0;
			break;
//This means that the mouse left button was clicked down
		case WM_LBUTTONDOWN:
//In this part, I just verify if the mouse was clicked down on the capture button
			if (WindowFromPoint((*((MSLLHOOKSTRUCT*)lParam)).pt) == hCaptureButton){
//This variable is to start or stop the interception
				interceptIsOn = 1;
				EnableWindow(hCaptureButton,false);
			}
			break;
		default:
			break;
		}
		
	}
	return CallNextHookEx(hhk, Code, wParam, lParam);
}

And then, I setupt the hook in this function that will be called by the thread :

DWORD WINAPI HookThreadFunc(LPVOID Param) {
//Get the handle instance of our program
	HINSTANCE exeHandle = GetModuleHandle(NULL);
// and then import our hook from it and set it up
	hhk = SetWindowsHookEx(WH_MOUSE_LL, MouseEvent, exeHandle, NULL);
	MSG msg;
	while (GetMessage(&msg,NULL,0,0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	UnhookWindowsHookEx(hhk);
	return 1;
}

And to finish off with the hook, I create a thread that will set it up, in the WM_CREATE  event, which will be triggered upon the creation of our main window :

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
	switch (msg){
	case WM_CREATE: {
		HANDLE hookThread;
		DWORD dwThread;
		hookThread = CreateThread(0, 0, HookThreadFunc, NULL, NULL,&dwThread);
//[...]
}

The function WndProc , is the window function, that processes the messages sent to our window.

The rest of the work is done by sending messages to the target window, like what the navigation buttons do, or the actions list does.

To finish off, this is the switch case block responsible for executing the actions in the listbox :

if (HIWORD(wParam) == LBN_SELCHANGE){
				int selected = SendMessage(actionsList, LB_GETCURSEL, 0, 0);
				switch (selected) {
				case 0:
					EnableWindow(targetHandle, TRUE);
					break;
				case 1:
					EnableWindow(targetHandle, FALSE);
					break;
				case 2:
					SendMessage(targetHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
					break;
				case 3:
					SendMessage(targetHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
					break;
				case 4:
					ShowWindow(targetHandle, SW_SHOW);
					break;
				case 5:
					ShowWindow(targetHandle, SW_HIDE);
					break;
				case 6:
					FlashWindow(targetHandle, TRUE);
					break;
				case 7:
					SendMessage(targetHandle, WM_CLOSE,0,0);
					break;
				case 8:
					SendMessage(targetHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
					break;
				}

As I said, in this article, I didn’t get into details, I just wanted to explain the general idea of the program.

But if you have any questions, suggestions, comments, criticism or something you need to be clarified more, hit me in the comment section.

Btw, sorry, I couldn’t think of any funny movie references to go with this… may be next time.

See ya.

One thought on “Control is an illusion Elliot !

Leave a Reply

Your email address will not be published. Required fields are marked *