Solved

Word, excel don't work with my hooking dll

Posted on 2008-06-10
10
636 Views
Last Modified: 2013-11-20
Hi,
I created a hooking dll. It works well for all applications but no in word or excel. I am interested in WM_KEYDOWN, WM_KEYUP and WM_CHAR to replace characters according to my logic. For some reason, when Word is in focus WM_CHAR does not reached to my hook proc. Only WM_KEYDOWN and KEYUP.

below is a code snippest of my dll
// my app call this method

BOOL SetHook()

{

	hHook = SetWindowsHookEx(WH_CALLWNDPROC, HookProc, hMod, NULL );
 

	return(hHook ? TRUE : FALSE);

}
 

// upon enter or exit from focus

LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)

{

	LRESULT	ret	= 0;
 

	if (code == HC_ACTION)

	{

		CWPSTRUCT	*	pData	= (CWPSTRUCT *) lParam;
 

		if (pData->message == WM_SETFOCUS)

		{

			SubclassWindow(pData->hwnd);

		}

		else if (pData->message == WM_KILLFOCUS)

		{

			UnSubclassWindow(pData->hwnd);

		}

	}
 

	return(CallNextHookEx(hHook, code, wParam, lParam));

}
 

// and 

void SubclassWindow(HWND hWnd)

{

	if (hWnd != hEdit)

	{

		UnSubclassWindow(hEdit);
 

		hEdit   = hWnd;
 

		pOldWndProc	= (WNDPROC) SetWindowLong(hEdit, GWL_WNDPROC, (LONG) MyWndProc);

	}

}
 

// finally, the method that does the work.

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{
 

	switch (msg)

	{

	case WM_CHAR:

		return HandleCharMessage(hWnd, msg, wParam, lParam);

	case WM_KEYDOWN:

		return HandleKeyDownMessage(hWnd, msg, wParam, lParam);

	case WM_KEYUP:

		return HandleKeyUpMessage(hWnd, msg, wParam, lParam);

	default:

		return(CallWindowProc(pOldWndProc, hWnd, msg, wParam, lParam));

	} 	

}

Open in new window

0
Comment
Question by:UdiRaz
  • 5
  • 5
10 Comments
 
LVL 9

Accepted Solution

by:
JohnGaby earned 500 total points
Comment Utility
I looked into it, and you are correct, the window doesn't seem to ever receive a WM_CHAR message.  However, if you use the WH_GETMESSAGE hook you will find that Word IS getting the WM_CHAR message in it's call to GetMessage, but for some reason is not sending it directly to the window.  It is anyone's guess as to why.

If, however, all you want to do is substitute your own character for the characters the user types, then you can do that completely with the WH_GETMESSAGE hook alone.  This hook, unlike the WH_CALLWNDPROC which you are using, allows you to actually change the message.  This means that you would not need to subclass the window at all, but you could change the message in the hook  function itself.  (If you need to do something more sophisticated than just replacing the character (e.g. showing a dialog or something that would cause the program to re-enter a message look), I am not sure doing it in the hook function would be a good idea).

Attached is the code for a DLL which can hook Word and replace all typed 'x's with 'y's.  I have tried this with both Word and Notepad and it seems to work.

I would like, once again, to caution you about using a global hook like this.  I don't know how you plan on using this, but global hooks should be used in only very special cases (such as spy++, which is a debug tool), and not in general applications.

// HookDll.cpp

//

// This is the DLL which sets a hook which

//      substitutes the letter 'y' when the user types

//      the letter 'x'

//
 

#include <windows.h>

#include <stdio.h>

#include <tchar.h>
 

HINSTANCE   hMod;

HHOOK       hHook;
 

BOOL APIENTRY DllMain(  HANDLE hModule, 

                        DWORD  ul_reason_for_call, 

                        LPVOID lpReserved)

{

    hMod	= (HINSTANCE) hModule;
 

    return TRUE;

}
 

#ifdef __cplusplus

extern "C" {

#endif
 

LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)

{

    LRESULT ret = 0;
 

    if (code == HC_ACTION)

    {

        MSG * pMsg = (MSG *) lParam;
 

        if (pMsg->message == WM_CHAR)

        {

            if (pMsg->wParam == 'x')

            {

                pMsg->wParam = 'y';

            }

        }

    }
 

    return(CallNextHookEx(hHook, code, wParam, lParam));

}
 

__declspec(dllexport) BOOL SetHook(DWORD threadId)

{

    hHook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, hMod, threadId);
 

    return(hHook ? TRUE : FALSE);

}
 

__declspec(dllexport) void ClearHook(void)

{

    if (hHook)

    {

        UnhookWindowsHookEx(hHook);

        hHook = 0;

    }

}
 

#ifdef __cplusplus

}

#endif

Open in new window

0
 

Author Comment

by:UdiRaz
Comment Utility
Thanks again.
Although this example is working with word, it has it own problems.
In real life, I am replacing Hindi characters. Unfortunatly, Unlike english ,there are some hindi letters that are made of more then one character. What I do to replace the original key stroke with the characters I want is to hook the WM_KEYDOWN, simulate some WM_CHAR messages and don't pass the next WM_CHAR and WM_KEYUP. This solution works fine with the code you sent me before. The implementation of HandleKeyDownMessage() ( from my original question above ) does the job. So when I took the code you sent me here, I first modified it to work with my logic on the x and y example. It works fine ( see code snippet below ). Then, happy that it is working on word, I tried to create a hindi letter that made of three characters ( attached, is an image of character ). This letter is typed when you press the apostrophe button ( left to the enter ).Nothing was printed.

Please look at he code snippet and advice
// x and y example. Works fine

LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)

	{

		LRESULT ret = 0;
 

		if (code == HC_ACTION)

		{

			MSG * pMsg = (MSG *) lParam;
 

			switch( pMsg->message )

			{

				case WM_KEYDOWN:

					if (pMsg->wParam == 'X')

					{

						pMsg->wParam  = 'y';

						pMsg->message = WM_CHAR;

						return(CallNextHookEx(hHook, code, wParam, lParam));

					}

					break;

				case WM_KEYUP:

					if (pMsg->wParam == 'X')

						return 0;

					else

						break;

				case WM_CHAR:

					if (pMsg->wParam == 'y' )

						return 0;

					else

						break;

			}

		}
 

		return(CallNextHookEx(hHook, code, wParam, lParam));

	}
 
 

// Not working :-(

LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)

{

	LRESULT ret = 0;
 

	if (code == HC_ACTION)

	{

		MSG * pMsg = (MSG *) lParam;
 

		switch( pMsg->message )

		{

		case WM_KEYDOWN:

			if (pMsg->wParam == 0xde)

			{

				g_ignoreChar = true;

				pMsg->wParam  = 0x936;

				pMsg->message = WM_CHAR;

				CallNextHookEx(hHook, code, wParam, lParam);

				pMsg->wParam  = 0x94d;

				CallNextHookEx(hHook, code, wParam, lParam);

				pMsg->wParam  = 0x200d;

				return(CallNextHookEx(hHook, code, wParam, lParam));

			}

			break;

		case WM_KEYUP:

			if (pMsg->wParam == 0xde)

				return 0;

			else

				break;

		case WM_CHAR:

			if ( g_ignoreChar == true)

			{

				g_ignoreChar = false;

				return 0;

			}

			else

				break;

		}

	}
 

	return(CallNextHookEx(hHook, code, wParam, lParam));

}

Open in new window

apostrophe.JPG
0
 

Author Comment

by:UdiRaz
Comment Utility
b.t.w. If you will add hindi and try to see what is typed, you will not see this letter.
The reason is that windows supports Inscript Hindi and not Remington Hindi, which is a different layout of the characters. since our clients wants Remington Hindi, I am replacing the characters...
0
 
LVL 9

Expert Comment

by:JohnGaby
Comment Utility
You are straying outside my area of knowledge, I am afraid.  I have not had a ton of experience with other languages.  Are you compiling for Unicode or Double Byte?  If you are not using Unicode, you might try switching to it.  Other than that, I don't think I can help much more.
0
 

Author Comment

by:UdiRaz
Comment Utility
I am using a unicode. But lets rephrase the question.

lets say that when a user press x, I would like to simulate y and z. it will not work.

Thanks
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 9

Expert Comment

by:JohnGaby
Comment Utility
I might add one other thing that I have mentioned before.  The WM_CHAR message is not generated by the keyboard at all.  It is posted when the application calls the TranslateMessage function with a WM_KEYDOWN.  Perhaps by controlling just the WM_KEYDOWN messages, you can get windows to generate the desired WM_CHAR messages?
0
 

Author Comment

by:UdiRaz
Comment Utility
1. most of the job does execute upon WM_KEYDOWN.
2. please try my code snippet but simulate two english characters. Only the second will be typed.
0
 
LVL 9

Expert Comment

by:JohnGaby
Comment Utility
So you are trying to change the WM_KEYDOWN message into a WM_CHAR message?  I really don't think that is a good idea, since the system will not then be getting the WM_KEYDOWN message at all.

Let me see if I understand what you want to do.  On certain WM_KEYDOWN messages, you want to generate 2 (or more) separate WM_CHAR messages, and you want to remove the normal WM_CHAR message that is generated when the WM_KEYDOWN message is processed by the TranslateMessage function?

Perhaps on the WM_KEYDOWN message you could use PostMessage to post the WM_CHAR messages that you want.  To get the real WM_CHAR message to disappear, you would need to change it into some other (hopefully benign) message. (I do not believe that returning 0 from your hook will prevent message from being sent).

I am just shooting from the hip here.  I don't know if any of this would work, and whether you are allowed to post messages in a hook.  Also, it is quite possible that because you are posting messages interspersed with key messages, that they may get out of order.

This whole thing is getting quite messy.  Maybe you should really be looking into how to get windows to handle your language correctly.  Perhaps you could post a query about that, that someone else may be able to answer.

0
 

Author Comment

by:UdiRaz
Comment Utility
You undrstand right.
I think that if I don't call CallNextHookEx at the end of this method, the windows won't know that it happen ( i.e. return 0 ). It works on MyWndProc when I selectively call CallWindowProc. What is the difference between the ?

I tried another approch. The original one ( yours ). I tried to use the subclassing code that works on all application but office and to use spy++ to get a handle of the edit control that handle the message but I didn't find such a control like you found on the notepad. Can you take a look, maybe you will find the right control.

Thanks
0
 
LVL 9

Expert Comment

by:JohnGaby
Comment Utility
I did use spy to spy on the edit window for word (the window class is _WwG).  Paradoxically, spy says that that window DOES receive the WM_CHAR message.  However, when I set the hook, I (like you) do not see it.  The only thing I can figure is that Word is treating the WM_CHAR message differently when it sees it returned from GetMessage in its message loop.  I cannot fathom why that would be.  I also don't understand why spy reports that the window is receiving the WM_CHAR message, when I am unable to intercept it.  Spy must be doing something different, but I am at a loss as to what it might be.

Perhaps someone else can explain?
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now