Outlook eating up delete keypress Options

R

Reinwald

Our VB6.0 Outlook addin loads a panel (written in VC++) containing an
internet explorer control in both the inspector and explorer views.
The internet explorer control displays an HTML file with a simple text
input. We faced similar issues with the backspace and delete key
events being eaten up by Outlook and not forwarded to the text input.
So we tried out a solution similar to the one posted by you, where we
used SetWindowsHookEx to catch the delete and backspace keypress
events and send appropriate messages to the panel window. While this
does seem to work for backspace in both the explorer and inspector
views, the delete keypress event *still* seems to be eaten up by
Outlook. This is what our callback for the SetWindowsHookEx looks
like :

LRESULT CALLBACK LowLevelKeyboardProc(INT nCode, WPARAM wParam, LPARAM
lParam){
LRESULT lRes;
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;


if ( pkbhs->vkCode == VK_DELETE || pkbhs->vkCode == VK_BACK)
{
if(outlook_mainwindow_Handle)
{
HWND panel = FindWindowEx(outlook_mainwindow_Handle,
NULL, NULL, _T
("PanelDialog"));


if (panel)
{
HWND hWndCtl = ::GetFocus();
if:):IsChild(panel, hWndCtl))
{


if (wParam == WM_KEYDOWN)
{
::SendMessage(hWndCtl,
WM_KEYDOWN, pkbhs->vkCode, 0);
}
return 1;
}
}
}
}


lRes = CallNextHookEx (0, nCode, wParam, lParam);
return lRes;



}


Any idea how we can get the delete key working?
 
D

Dmitry Streblechenko

I have no problem with the following hook in Outlook (Delphi):

initialization
g_hook := SetWindowsHookEx(WH_GETMESSAGE, RAHLEditorHookProc, 0,
GetCurrentThreadId());
finalization
UnhookWindowsHookEx(g_hook);
end.


var g_hook : HHOOK;
function RAHLEditorHookProc(Code : integer; wParam : WPARAM; lParam :
LPARAM):LResult;stdcall;
var pMsg : ^TMsg;
//ClassName:string;
Ctrl{, NextCtrl} : TWinControl;
ParentFrm : TCustomForm;
begin
pMsg:=pointer(lParam);
if ((wParam and PM_REMOVE) = PM_REMOVE) then begin
if (pMsg.message >= WM_KEYFIRST) and (pMsg.message <= WM_KEYLAST)
then begin
if ((pMsg.message = WM_KEYDOWN) or (pMsg.message = WM_KEYUP)) and
(pMsg.wParam <> VK_RETURN) and //ignore "Return" keys
((pMsg.wParam = VK_BACK) or (pMsg.wParam = VK_DELETE) or
(pMsg.wParam = VK_TAB) or (pMsg.wParam = VK_SPACE) or
//(pMsg.wParam = VK_LEFT) or (pMsg.wParam = VK_RIGHT) or
(GetKeyState(VK_CONTROL) < 0) or //Control key
(GetKeyState(VK_MENU) < 0) or //Alt key
((pMsg.lParam and (1 shl 24)) <> 0) or //extended key
{(pMsg.wParam = VK_RETURN) or} (pMsg.wParam = VK_UP) or
(pMsg.wParam = VK_DOWN))
then begin
//SetLength(ClassName, 1024);
//SetLength(ClassName, GetClassName(pMsg.hwnd, PChar(ClassName),
Length(ClassName)));
//if (ClassName = 'TRAHLEditor') then begin
Ctrl:=FindDelphiControl(pMsg.hwnd);
if Ctrl <> nil then begin //is it a Delphi control?
if (pMsg.wParam = VK_TAB) then begin
if (pMsg.message = WM_KEYDOWN) then begin
ParentFrm:=GetParentForm(Ctrl);
if ParentFrm <> nil then begin
TCheatControl(ParentFrm).SelectNext(Ctrl, true, true);
//PostMessage(ParentFrm.Handle, WM_NEXTDLGCTL, 0, 0);
end;
end;
end
else begin
TranslateMessage(pMsg^);
SendMessage(pMsg.hwnd, pMsg.message, pMsg.wParam, pMsg.lParam);
end;
pMsg.message :=WM_NULL;
end;
end
end
end;
Result:=CallNextHookEx(g_hook, Code, wParam, lParam);
end;





--
Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
-
 
R

Reinwald

Hey,
We tried using TranslateMessage(message) and then calling sendmessage ,but
it stills doesnt work.
Using spy ++ i monitored the keystrokes and i clearly see the after
installing our hook the delete message goes to the appropriate window but
somehow i feel outlook is eating up the delete key.
To confirm my doubt i even mapped the delete key to another key say "?" and
when i press the delete key the "?" symbol gets printed .

As i mentioned before this hook works for the backspace key which prior to
this wasnt working.Any other suggestion to get the delete key working?

Thanks
 
R

Reinwald

Hey,
The code we tried out after reading your suggestion

llKeyHook = SetWindowsHookEx(WH_GETMESSAGE, GetMessageProc, 0,
GetCurrentThreadId());



LRESULT CALLBACK GetMessageProc(int code, WPARAM wParam, LPARAM lParam)
{
const MSG *pMsg = (MSG *) lParam;

HWND panel = FindWindowEx(application_Handle, NULL, NULL, _T("PanelDialog"));

if (panel)
{
HWND hWndCtl = ::GetFocus();

if:):IsChild(panel, hWndCtl))
{
if (wParam & PM_REMOVE)
{
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
{
if (pMsg->message == WM_KEYDOWN &&
(pMsg->wParam == VK_BACK || pMsg->wParam == VK_DELETE))
{
::TranslateMessage(pMsg);
return ::SendMessage(hWndCtl, pMsg->message, pMsg->wParam,
pMsg->lParam);
}
}
}
}
}

return ::CallNextHookEx(0, code, wParam, lParam);
}

As i mentioned before this hook works for the backspace key.Any other
suggestion to get the delete key working?
 
R

Reinwald

Hey,
Well this article helped me also and now the keystrokes work on the internet
explorer control.
Also thanks Dmitry for the help.

------------i have pasted the article below --------------------------------

ATL and Standard C++

When hosting the WebBrowser control in either an ATL application or one
written in standard C++, the solution is sometimes rather simple. All you
have to do is query the WebBrowser control for the IOleInPlaceActiveObject
interface and call its TranslateAccelerator method. Typically, you call this
method in your handler function for the WM_KEYDOWN message. Figure 2 contains
ATL and standard C++ code that shows how to call the TranslateAccelerator
method to fix the keystroke problem.

Sometimes your application will not automatically be sent WM_KEYDOWN
messages for accelerator keys. In this case, you must manually send this
message to your window. Here is a sample message pump that sends all keyboard
messages to the window of your application:

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);

// Send all keyboard messages to the window of your
// application. hwndApp is the window handle of
// your application.
//
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
::SendMessage(hwndApp, msg.message, msg.wParam, msg.lParam);

DispatchMessage(&msg);
}

Win32 SDK Modal Dialogs

The Win32? dialog box functions (DialogBox, DialogBoxIndirect,
DialogBoxIndirectParam, and DialogBoxParam) are very helpful when creating
modal dialog boxes. They take care of handling the message pump for your
application. However, this creates a problem when you are trying to fix these
keystroke problems. Where do you put the call to TranslateAccelerator?

Unfortunately, if you need to host the WebBrowser control in a dialog,
it is not a good idea to use these functions to create the modal dialog. The
reason for this is simple. When focus is set to a control on a dialog, the
control is sent the WB_GETDLGCODE message. Controls typically respond to this
message by returning DLGC_WANTALLKEYS. Then the control is given a chance to
handle all keys entered by the user.

The WebBrowser control returns DLGC_WANTARROWS| DLGC_WANTCHARS in
response to the WM_GETDLGCODE message. This means that it will not handle
certain keys such as Tab and Delete. Therefore, to work around these
keystroke problems, you need to have control of the message pump so that you
can call TranslateAccelerator.

For these reasons, I recommend that you do not use the Win32 dialog box
functions to create your modal dialog box. Create the dialog window yourself
so you have control of the message pump. You can use MFC or ATL to create
this dialog. In addition, if you just need a modal dialog that displays a Web
page, you can use the DHTML showModalDialog function provided by Microsoft
Internet Explorer.

There is one other option you can use to fix these problems, instead of
creating the dialog window manually. You can use a Windows hook. This will
enable you to retrieve all keyboard messages for the current thread and then
call TranslateAccelerator so that accelerator keys will be processed. There
is one problem with this approach, however. When the focus is on the
WebBrowser control and you attempt to change focus between controls on the
Web page by pressing tab, the focus will never leave the WebBrowser window.
This means that you can Tab between controls on the Web page or between
controls in your application, but not both.

There are four steps required to set up a Windows hook to work around the
keystroke problems in a Win32 SDK dialog. First, declare your hook procedure
in your header file.

static LRESULT CALLBACK GetMsgHookProc(int nCode, WPARAM wParam, LPARAM
lParam);

Next, set your hook procedure during initialization by calling
SetWindowsHookEx. Also, make sure to save the returned hook handle so that
you can unhook the procedure when you are shutting down or when it is no
longer needed.
// Declare this global handle in one of your project files.
HHOOK g_hook;

// Place this code inside an initialization
// method in your implementation file (.cpp)
g_hook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgHookProc,
NULL, GetCurrentThreadId());

After that, implement your hook procedure and call TranslateAccelerator.

LRESULT CALLBACK CYourClass::GetMsgHookProc(int nCode, WPARAM wParam,
LPARAM lParam)
{
LPCKFSEARCH pThis = (LPCKFSEARCH)GetWindowLong(hwndMain, DWL_USER);

if (pThis && nCode >= 0)
{
MSG* pMsg = (MSG*)lParam;

// m_pOleInPlaceActObj is an IOleInPlaceActiveObject
// data member of the view class that is initialized
// after the WebBrowser control is loaded.

if (pThis->m_pOleInPlaceActObj)
pThis->m_pOleInPlaceActObj->TranslateAccelerator(pMsg);

// This causes the tab to work in the WebBrowser window. If you do
not do
// this, tabbing will happen in the dialog only. You have the choice
of
// tabbing in the dialog or the WebBrowser window, not both.

if (pMsg->wParam == VK_TAB)
ZeroMemory(pMsg, sizeof(MSG));
}

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

Finally, when your application is shutting down or when you no longer need
the hook, unhook the procedure.
UnhookWindowsHookEx(g_hook);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top