VBA - PPT Keyboard Hook not working with Office 64-bit

B

bourgui

Hi all,

I have created an addin for PowerPoint, in which I have setup a
keyboard hook to assign shortcuts for my functions.

The problem I have is with Office 2010, the 64-bit version. When I
attempt to register the hook using SetWindowsHookEx, I get a
LastDLLError of 126, which is apparently "Module not found". I'm
guessing this has to do with the handle to PPT that I am passing on to
SetWindowsHookEx, but I'm not able to go any further.

The code looks like:
Code:
Public Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpFn As LongPtr,
ByVal hmod As LongPtr, ByVal dwThreadId As Long) As Long
Public Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias
"GetModuleHandleA" (ByVal lpModuleName As String) As Long
Public Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" ()
As Long

Private hWndPPT As Long

Sub SetHook()
Dim lThreadID As Long

If Not GetPPTHandle Then Exit Sub

If isHooked Then Exit Sub  'We should NEVER set the same hook twice,
as
lThreadID = GetCurrentThreadId

'Set a local hook
HookHandle = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyHandler,
hWndPPT, lThreadID)

If HookHandle <> 0 Then isHooked = True
End Sub

Function GetPPTHandle() As Boolean
GetPPTHandle = True
hWndPPT = GetModuleHandle(vbNullString)
If IsNull(hWndPPT) Then GetPPTHandle = False
End Function

I have tried "casting" the module's handle to a LongPtr, since I
reckon that's what it wants, but no luck, SetWindowsHookEx always
returns the error.

Any idea what I'm doing wrong? I have never worked with 64-bit before.

Thanks!
 
K

Karl E. Peterson

bourgui brought next idea :
I have created an addin for PowerPoint, in which I have setup a
keyboard hook to assign shortcuts for my functions.

The problem I have is with Office 2010, the 64-bit version. When I
attempt to register the hook using SetWindowsHookEx, I get a
LastDLLError of 126, which is apparently "Module not found". I'm
guessing this has to do with the handle to PPT that I am passing on to
SetWindowsHookEx, but I'm not able to go any further.

Ummmm, well, yeah. You're trying to call a 32-bit DLL from a 64-bit
process. It's right there, in the name, afterall:
 
B

bourgui

bourgui brought next idea :



Ummmm, well, yeah.  You're trying to call a 32-bit DLL from a 64-bit
process.  It's right there, in the name, afterall:

Well, thanks for the response, but, err, no. ;o)
The name is misleading. Windows 64 bit uses "User32.dll" for both
versions. There are 2 versions of it, one under System 32, the other
under SysWow64. The one that's actually used at run-time will be
determined by Windows depending on the calling app/dll.
That's the case for many various names that are used throughout
Windows, and is a legacy of the transition days between 16-bit and 32-
bit systems (guess they never thought there might be a transition to
64-bit someday).

Anyway, I found the fix, which is rather obvious: all DLL functions
declarations need to be updated to the appropriate data types. Not to
mention that I must check against running as a 64-bit app as opposed
VBA7.

So, in case anyone is ever interested, this works for me:
Code:
#If Win64 Then
Public Declare PtrSafe Function UnhookWindowsHookEx Lib
"user32" (ByVal hHook As LongPtr) As LongLong
Public Declare PtrSafe Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As LongLong, ByVal lpFn As LongPtr,
ByVal hmod As LongPtr, ByVal dwThreadId As LongLong) As LongLong
Public Declare PtrSafe Function CallNextHookEx Lib "user32" (ByVal
hHook As LongPtr, ByVal nCode As LongLong, ByVal wParam As LongLong,
lParam As Any) As LongLong
Public Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias
"GetModuleHandleA" (ByVal lpModuleName As String) As LongLong
Public Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" ()
As LongLong
Public Declare PtrSafe Function GetKeyState Lib "user32" (ByVal
nVirtKey As LongLong) As Integer
Private hWndPPT As LongPtr
Private HookHandle As LongPtr
#Else
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook
As Long) As Long
Public Declare Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpFn As Long, ByVal
hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As
Long, ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As
Long
Public Declare Function GetModuleHandle Lib "kernel32" Alias
"GetModuleHandleA" (ByVal lpModuleName As String) As Long
Public Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Public Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As
Long) As Integer
Private hWndPPT As Long
Private HookHandle As Long
#End If

Private isHooked As Boolean

Sub SetHook()
#If Win64 Then
Dim lThreadID As LongLong
#Else
Dim lThreadID As Long
#End If

If Not GetPPTHandle Then Exit Sub

If isHooked Then Exit Sub  'We should NEVER set the same hook twice,
as it cannot be released otherwise
lThreadID = GetCurrentThreadId
'Set a local hook
HookHandle = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyHandler,
hWndPPT, lThreadID)
If HookHandle <> 0 Then isHooked = True
End Sub

Function GetPPTHandle() As Boolean
GetPPTHandle = True
hWndPPT = GetModuleHandle(vbNullString)
If IsNull(hWndPPT) Then GetPPTHandle = False
End Function
[\CODE]

At least it seems to work in the limited testing I've done in the last
15 minutes.

Cheers!
 

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