subClass.c
/*
$RCSfile: subClass.c $
$Revision: 1.3 $
$Date: 1997/03/13 15:49:42 $
$Author: doomer $
Copyright (c) 1997 John Dumais. All rights reserved.
*/
#include <windows.h>
#include "subClass.h"
/*
We maintain information about the state of our application
window and store that in a structure available only to
our DLL.
*/
static struct SubClassInfo subClassInfo;
/*
Our DLL's main entry point. When we first get loaded into an
application's process space, we find the window the application
created in its main thread. We then subclass that window, so that
we get a chance to react to window messages before the application
does.
This function also gets called when an application is unloading
the DLL. In this case, we want to remove our subclass function.
We remove the subclass function by restoring the original message-
processing function.
*/
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved){
BOOL returnVal=TRUE;
switch(reason){
case DLL_PROCESS_ATTACH:
subClassInfo.windowOfInterest=findApplicationWindow(&subClassInfo);
if(subClassInfo.windowOfInterest){
if(IT_FAILED(SubclassAppWindow(&subClassInfo, SubclassProc))){
returnVal=FALSE;
}
}
else{ /* subClassInfo.windowOfInterest */
returnVal=FALSE;
}
break;
case DLL_PROCESS_DETACH:
if(subClassInfo.windowIsSubclassed){
SubclassAppWindow(&subClassInfo, subClassInfo.originalWndProc);
}
break;
default:
break;
}
return returnVal;
}
/*
We need to be able to identify the window created by the attaching
application's main thread. We make a call to EnumThreadWindows()
which will cause the window system to continuously call a callback
function with the window identifier for all the current
top-level windows. Our callback function is called enumWindowsCallback.
*/
HWND findApplicationWindow(struct SubClassInfo *scInfo){
BOOL result;
scInfo->windowOfInterest=(HWND)0;
scInfo->windowThread=GetCurrentThreadId();
result=EnumThreadWindows(scInfo->windowThread,
enumWindowsCallback,
(LPARAM)scInfo);
return scInfo->windowOfInterest;
}
/*
As the window system calls this function with a window identifier,
we find out which thread created the associated window by calling
GetWindowThreadProcessId(). When we find the thread that matches
the main thread for the application that loaded our DLL, we know
that we have found the window our application created.
*/
BOOL CALLBACK enumWindowsCallback(HWND aWnd, LPARAM windowThreadInfo){
DWORD windowThreadId;
struct SubClassInfo *sci;
sci=(struct SubClassInfo *)windowThreadInfo;
windowThreadId=GetWindowThreadProcessId(aWnd, (LPDWORD)0);
if (windowThreadId == (DWORD)sci->windowThread) {
sci->windowOfInterest=aWnd;
/* we found our window. stop looking */
return(FALSE);
}
/* this isn't our window. continue looking */
return(TRUE);
}
/*
This is the function the windows system will call each time there
is an event ready for processing. We can elect to forward that message
on to the application's original message processing function or not.
In either case, we have the option to perform any action we want
in response to an event. In our case, we look for our application user
having pressed the F11 or F12 function key.
When we detect an F12 key press, we make the application window
cover the entire screen, remove all the 'decorations', and make it
the top-most window on the screen.
When we detect an F11 key press, we put all the 'decorations' back,
make the window occupy the upper left corner of the screen, and
remove the 'top-most' property.
Any event other than F11 and F12 key presses gets forwarded to our
application's message-processing function without intervention.
*/
LRESULT CALLBACK SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
TCHAR charCode;
switch(uMsg){
case WM_KEYDOWN:
charCode=(TCHAR)wParam;
switch(charCode){
case VK_F12:
CoverScreen(hwnd);
return FALSE;
case VK_F11:
UncoverScreen(hwnd);
return FALSE;
default:
break;
}
break;
default:
break;
}
return CallWindowProc(subClassInfo.originalWndProc,
subClassInfo.windowOfInterest,
uMsg,
wParam,
lParam);
}
/*
We subclass a window by instructing the window system to call a
function we specify, instead of calling the application's original
message-processing function, when a window event needs to be processed.
*/
BOOL SubclassAppWindow(struct SubClassInfo *sci, WNDPROC newProc){
BOOL returnVal=SUCCESS;
long result;
result=SetWindowLong(sci->windowOfInterest, GWL_WNDPROC, (LONG) newProc);
if(result){
sci->originalWndProc=(WNDPROC)result;
sci->windowIsSubclassed=TRUE;
}
else{
returnVal=FAILURE;
}
return returnVal;
}
/*
This function makes the associated window cover the entire computer
screen, turns off all the 'decorations', and sets the window's top-most
property. The top-most property prevents other windows from showing
on top of our application window.
Removing the 'decorations' involves turning off the window's style bits
governing certain window characteristics. We remove the caption bar, which
houses the minimize, maximize, and size boxes, as well as the system menu.
We also turn off the thick frame borders, which house the window sizing
handles.
The effect is that is is very difficult to move the window or switch away
from the application after calling this function.
*/
BOOL CoverScreen(HWND aWindow){
SetWindowLong(aWindow, GWL_STYLE, GetWindowLong(aWindow, GWL_STYLE)
& ~(STYLE_BITS));
SetWindowPos(aWindow, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN), 0 /* flags */);
return SUCCESS;
}
/*
This function restores the original 'decorations' to your application's
window. We move the window to the upper left corner of the screen and
remove the top-most property.
*/
BOOL UncoverScreen(HWND aWindow){
SetWindowLong(aWindow, GWL_STYLE, GetWindowLong(aWindow, GWL_STYLE)
| (STYLE_BITS));
SetWindowPos(aWindow, HWND_NOTOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN)/2,
GetSystemMetrics(SM_CYSCREEN)/2, 0 /* flags */);
return SUCCESS;
}
/*
$Log: subClass.c $
Revision 1.3 1997/03/13 15:49:42 doomer
a fully functional window subclassing DLL.
Revision 1.2 1997/03/13 11:30:40 doomer
functional window subclassing.
DllMain subclasses calling application's window when process attaches
dll, un-subclasses when process detaches.
The subclass procedure looks for wm_keydown messages and grabs f12.
Revision 1.1 1997/03/12 17:50:32 doomer
Initial revision
*/