Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 669
  • Last Modified:

Word, excel don't work with my hooking dll

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
UdiRaz
Asked:
UdiRaz
  • 5
  • 5
1 Solution
 
JohnGabyCommented:
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
 
UdiRazAuthor Commented:
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
 
UdiRazAuthor Commented:
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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
JohnGabyCommented:
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
 
UdiRazAuthor Commented:
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
 
JohnGabyCommented:
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
 
UdiRazAuthor Commented:
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
 
JohnGabyCommented:
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
 
UdiRazAuthor Commented:
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
 
JohnGabyCommented:
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 5
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now