Click to See Complete Forum and Search --> : Another Hook question


patrickmoe
August 17th, 2006, 04:01 PM
I'm trying to hook the creation of the 'Page Setup' dialog box. In particular, I am trying to hook the one that is created in Internet Explorer from the file menu.

I have created a global hook and hook proc in a dll file and have been succesful at testing a capture of the right mouse button and other things but I can't seem to find out what to do to catch the creation of any dialog box including the one that I am interested in.

Here's my code that I'm using to set the hook.
pData->g_hHook = SetWindowsHookEx (WH_GETMESSAGE, (HOOKPROC) SecProc, pData->g_hInstance, 0) ;
Is WH_GETMESSAGE the proper way to do this or is it done in another way?

I also don't know exactly which message I should be checking for. I'm assuming it would be WM_CREATE but I then would need to be able to distinghuish what is getting created and disregard it if it's not what I'm looking for. And I haven't been able to hook that message yet.

I know that I'll slap my self in the forehead once I have an answer to this but I'm up against a wall for an answer right now.

Thank you in advance for any input on this.

JohnCz
August 17th, 2006, 08:34 PM
Use WH_CBT hook.

You will be able to check window’s class name; for dialogs, property sheet and property sheets windows this class is #32770.

You will have to think about a method to uniquely identify window you need.

patrickmoe
August 17th, 2006, 09:35 PM
Thank you so much for the help.

I knew it would be a no brainer.

JohnCz
August 17th, 2006, 09:55 PM
You are very welcome.

patrickmoe
August 18th, 2006, 03:17 PM
I am still having problems intercepting the correct message in my hook procedure.

I am now using the WH_CBT method for setting the hook and I'm assuming that I need to filter for the HCBT_CREATEWND message in my hook procedure.

While testing, I open up a copy of Internet Explorer and click File->Page Setup in hopes of triggering this message and my hook procedure is not seeing it.

Here is the code from my dll file. What am I missing?

__declspec (dllexport) BOOL WINAPI SetHook(HWND hwnd)
{
/*If already hooked,don't hook again*/
if(hwndSecHook != NULL)
return FALSE;

pData->g_hWnd = hwnd;

pData->g_hHook = SetWindowsHookEx (WH_CBT, (HOOKPROC) SecProc, pData->g_hInstance, 0) ;
/*Should the 3rd argument for SetWindowsHookEx be NULL?*/
/*pData->g_hWnd is set eqaul to the hwnd passed from my test executable*/
if(pData->g_hHook)
{
/*Hook is set.*/
hwndSecHook = hwnd;
return TRUE;
}

/*Hook is not set*/
return FALSE;
}

__declspec (dllexport) BOOL WINAPI UnHook(HWND hwnd)
{
BOOL UnHooked;
if(hwnd != hwndSecHook)
return FALSE;
UnHooked = FALSE;
UnHooked = UnhookWindowsHookEx (pData->g_hHook);

if (UnHooked)
hwndSecHook = NULL;

return UnHooked;
}

LRESULT CALLBACK SecProc(int nCode, WPARAM wParam, LPARAM lParam)
{

//Hook procedure for hooking the 'Page Setup' dialog box
//I have assumed that I need to filter for the HCBT_CREATEWND message but it doesn't seem
//to be getting sent when I open I.E. and open File->Page Setup.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
TCHAR szClassName[64];
int nRet = GetClassName(/*hWnd*/pData->g_hWnd, szClassName, 64);
/*I think that hwnd in the previous line should be the hwnd of the dialog that I am trying to hook*/
/*I need to figure out how to get this so I can check the properties of this dialog and act accordingly*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////

LPMSG lpmsg;
BOOL success = FALSE;

if (nCode <0)
{
/*Pass it on*/
CallNextHookEx(pData->g_hHook, nCode, wParam, lParam);
return 0;
}

lpmsg = (LPMSG) lParam;

/*I eventually need to filter for what ever message it is that creates the Page Setup Dialog.*/
/*I thought this was it but it doesn't seem to be getting triggered.*/
if (lpmsg->message == HCBT_CREATEWND)
{
success = ShowCustomDialog(0);
}

return CallNextHookEx (pData->g_hHook, nCode, wParam, lParam);
}

BOOL ShowCustomDialog(int Style)
{
/*Style can equal anything right now. It is for future use*/

PAGESETUPDLG lppsd;
int RetVal;

memset(&lppsd, 0, sizeof(lppsd));

lppsd.lStructSize = sizeof(lppsd);
lppsd.Flags = PSD_DISABLEPRINTER;


RetVal = PageSetupDlg(&lppsd);
return RetVal;

}

Brenton S.
August 18th, 2006, 07:59 PM
Hi patrickmoe,

Your CBT procedure has the wrong format. Try something like this:


LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)
return CallNextHookEx(NULL, nCode, wParam, lParam);
else if(nCode == HCBT_CREATEWND)
{
HWND hwnd = (HWND)wParam;
CHAR szClassName[255];
CHAR szWindowName[255];

GetClassName(hwnd, szClassName, 255);

GetWindowText(hwnd, szWindowText, 255);

if(!lstrcmp(szClassName, "#32770") && !lstrcmp(szWindowText, "Page Steup"))
{
// Show custom dlg
return 1;
}
}

return CallNextHookEx(NULL, nCode, wParam, lParam);
}

JohnCz
August 20th, 2006, 10:24 AM
Please, next time use CODE tags. It is very hard to read snippets without this tags.
I am now using the WH_CBT method for setting the hook and I'm assuming that I need to filter for the HCBT_CREATEWND message in my hook procedure.
WH_CBT method? WH_CBT is a hook type, not a method.
HCBT_CREATEWND is the right choice of code for checking window creation.

A question: What is hwndSecHook? Is this variable in the shared memory segment?

pengch
August 21st, 2006, 02:19 AM
The 'Page Setup' dialog box is created by PageSetupDlg API.

patrickmoe
August 21st, 2006, 09:30 AM
Please, next time use CODE tags. It is very hard to read snippets without this tags.

WH_CBT method? WH_CBT is a hook type, not a method.
HCBT_CREATEWND is the right choice of code for checking window creation.

A question: What is hwndSecHook? Is this variable in the shared memory segment?

Yes WH_CBT hook type. I used the wrong terminology for it. I used the word method pretty loosely not thinking about it's meaning to the programming community. Sorry.

As far as I know. hwndSecHook is in the shared segment if this is the correct way to do that.

This code is just after my includes in the source code for my dll.


#pragma data_seg(".SHARED")
static HWND hwndSecHook = NULL;
#pragma data_seg()


I am also aware of the PageSetupDlg API. I'm not having a problem with this part. I've gotten the code created already to create my own Page Setup dialog with the things disabled that I need secured.

I really appreciate the help from you guys.

I have never had to work with hooks before and have done very little with dlls.

I will be modifying my code according to the advice here and re-testing again this morning.

JohnCz
August 21st, 2006, 01:09 PM
That looks OK.
I have to admit, that first time I have overlooked pData. What is it?

All variables that you are using across processes should be placed in shared, read, write memory segment. Are they?

You have to tell linker to use memory as rws. Did you?

I found my sample in this thread (http://www.codeguru.com/forum/showthread.php?t=336822) showing mouse hook set up, but you can use it to hook WH_CBT type.

patrickmoe
August 21st, 2006, 03:35 PM
pData is a pointer to this structure

typedef struct
{
HHOOK g_hHook;
HWND g_hWnd;
HINSTANCE g_hInstance;
} SCGLOBALDATA;


The hInstance variable gets set to the hModule argument in DLLMain. The other two are getting initialized to NULL.

Should this variable also be in shared memory?

I'm also not familiar with how to tell the linker to use shared, read/write. I'll be taking a look into that.

I will also be taking a closer look at our sample code.

In the mean time, I am cleaning up my code a little bit and getting rid of the stuff I've commented out. I'm confused enough already without that stuff there.

I've also found that debugging dll files can be a PITA.

JohnCz
August 21st, 2006, 08:49 PM
Couple of things to point:

1. Sample shows how to hook certain process (thread) and uses Notepad as an example.
2. If you want hook to be injected to all running processes set thread ID in SetWindowsHookEx to NULL and pass only DLL’s instance.
3. All variables that are used in a hook procedure must be global in shared, writable and readable memory. Moreover, they must be initialized. If not they are process bound.
4. You have to tell linker to use memory that was marked shared by either using def fiel and setting SECTIONS (def statement) and marking .WhateverSegmentName to SWR.
You can also use project settings and enter /SECTION specifying name of the segment and attribute.
The mos popular is using #pragma comment(linker, "/SECTION:. WhateverSegmentName)

Dot is optional and used by convention.

The reason for using shared memory id that each process is running in different address space and if variables are not shared, they will point into a lala land in other than DLL loading processes. By placing variables in shared chunk of memory, you assure that each process will map variables properly in own address space.

Since initializing custom data (arrays, structures and so on) is not simple, using custom data would not be possible, hence you must use simple types.

JohnCz
August 21st, 2006, 08:56 PM
I've also found that debugging dll files can be a PITA.Why? it is as simple as debugging exe module.

patrickmoe
August 22nd, 2006, 03:48 PM
I wanted very badly to get to this project again today and try the stuff you guys told me but it got pre-empted by a more important project.

I will let you know how things turn out.

I can't seem to get a break point set inside the Hook Procedure in my DLL or in my Custom Dialog function.

I think some stuff may have gotten out of sync between the exe and the dll.

I'll be working on it some more tonight and tomorrow.

Thanks again.

patrickmoe
August 24th, 2006, 04:11 PM
I am still having mixed results with this project.

I can not seem to get my hook procedure to get hit by the creation of a dialog box unless I create that dialog from within my test application.

As far as I know, I have got the hook set as a system hook but the messages aren't getting caught by it.

hook = SetWindowsHookEx(WH_CBT, (HOOKPROC) HookProc, hinstance, 0);

hinstance is a global static variable of type HINSTANCE and getting initialized to NULL on creation.

It is getting set equal to hModule from DLLMain.

All I am trying to do is hook the creation of the Page Setup dialog box and open my own dialog in it's place. This has to be hooked and modified no matter what application opens this dialog.

I am out of ideas here and I know that it is something really stupid I am overlooking.

For anyone who cares enough to help a moron, I am attaching a zip file with my project in it.

And I'd appreciate it if you don't laugh to hard looking at it. :rolleyes:

Thanks.

JohnCz
August 30th, 2006, 10:11 AM
Most likely you are not missing anything in your code.

You have to remember that hook dll is inserted into each running process address space; therefore OutputDebugString will not serve as good indicator of reaching parts of code.

Your string output goes to another procedd and since you are not debugging it you won’t see the output.

Run your program and then using another instance of VS, connect to the IE process. After connecting set your hook and try to invoke a print dialog. You will see your messages now.

On the other hand, preventing dialog from appearing and replacing by another will not do you any good. You may try to subclass dialog window and set printing parameters you need when dialog initializes. I will try to do that when the time permits.

Let us know how did it go.

patrickmoe
August 30th, 2006, 10:33 AM
Thank you very much because I am still trying my hand at this and not having any success. I will try the advice that you just gave me though.

patrickmoe
August 30th, 2006, 11:28 PM
I finally have it kind of working with a few minor problems that I'll probably ask about in the morning. For now (11:27 P.M.) It's time to go to bed.

I think that I didn't have my call to SetWindowsHookEx coded properly is what was causing the main part of the problem.

Thank you all for your help and your patience.

Pat

patrickmoe
August 31st, 2006, 10:04 AM
OK... I determined that most of my problem was getting caused by the way I was trying to debug. M break points and debug strings were not getting hit or triggered by anything outside of my test application.

I also at one time had the 3rd argument of SetWindowsHookEx set to the hinstance of the test application.

Now, there are some other things I need to address.

I am finally able to trap the WH_CREATEWND message and get the text from the new dialog. I am filtering for that and then calling my own modified Page Setup dialog box.

If I just leave it at that, this gets triggered at least 7 times and if I try to return 1 from my CBTProc, I get an error.

Is there a different way I should be doing this?

JohnCz
August 31st, 2006, 11:16 PM
OK... I determined that most of my problem was getting caused by the way I was trying to debug. M break points and debug strings were not getting hit or triggered by anything outside of my test application. That is exactly what I have stated. You are trying to debug code injected into another process. I also at one time had the 3rd argument of SetWindowsHookEx set to the hinstance of the test application.Not good. I am finally able to trap the WH_CREATEWND message and get the text from the new dialog.
.
.
.
Is there a different way I should be doing this?Yes. IN a hook procedure while processing HCBT_CREATEWND code, window is not created yet.
You can either subclass dialog and check window text in WM_CREATE handler but it is easier to retrieve pointer to a CREATESTRUCT. For HCBT_CREATEWND code lParam is a pointer to the CBT_CREATEWND structure that in turn has a member of the CREATESTRUCT. lpszName member of create structure carries the name if the window. Use this for comparison. If I just leave it at that, this gets triggered at least 7 times and if I try to return 1 from my CBTProc, I get an error.I am not sure why and withour seeing youe code I am not able to voice any comments. I am finally able to trap the WH_CREATEWND message and get the text from the new dialog. I am filtering for that and then calling my own modified Page Setup dialog box.I am still not sure what you are trying to accomplish but most likely that will not work. Since you are failing original dialog’s creation, invoking application will receive an error.

If you want to replace certain values you would have to be able to modify original dialog’s PAGESETUPDLG members and that is not easy if not impossible.

Can you tell me what is it that you are trying to do?

patrickmoe
September 1st, 2006, 08:58 AM
My ultimate goal here is to catch the creation of the Page Setup dialog and prevent it from happening and display a modified Page Setup dialog with a couple of button on it either removed or disabled.

I'm doing that like this.


void ShowModifiedDialog()
{
PAGESETUPDLG psd;


DialogCreated = TRUE;
memset(&psd, 0, sizeof(psd));

psd.lStructSize=sizeof(psd);
psd.Flags=PSD_DISABLEPRINTER;

PageSetupDlg(&psd);
}


Here is the CBTProc from my DLL.

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode<0)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
if(nCode==HCBT_CREATEWND)
{
HWND hwnd=(HWND)wParam;

CBT_CREATEWND *ccw=(CBT_CREATEWND *)lParam;

CHAR szClassName[255];

GetClassName(hwnd, szClassName, 255);

if(!lstrcmp(szClassName, "#32770") && !lstrcmp(ccw->lpcs->lpszName, "Page Setup"))
{
// Show custom dlg
ShowModifiedDialog();
return 0;
}

}
CallNextHookEx (g_hHook, nCode, wParam, lParam) ;
return 0;
}


Coded this way, my modified dialog DOES get displayed but..... After closing it, I wind up back inside the 'if(!lstrcmp(szClassName, "#32770") && !lstrcmp(ccw->lpcs->lpszName, "Page Setup"))' test 6 or 7 more times and getting an equal amount of custom dialogs displayed.

I'm not sure that I really need to be displaying my own dialog at all like I am in the ShowCustomDialog function. If there is a way to modify the properties of the original dialog that I trapped in the first place, I'd rather just do that.

patrickmoe
September 1st, 2006, 02:54 PM
So.... Is it possible to stop the original Page Setup dialog from getting created and open a freah one that has some flags set in the PAGESETUPDLG structure that gets sent to it?

Am I going about this the wrong way? Should I be modifying the dialog that was originally caled to open?

Shoud I subclass it? If so, how do you go about subclassing a dialog box that is getting created by a different application?