Page 1 of 2
Writing a DLL
Posted: Fri Feb 21, 2014 6:02 pm
by nblackburn
I have tried creating a DLL that registers and unregisters windows event hooks, but when compiling and calling the library i always get an error.
Code: Select all
ProcedureDLL RegisterHook(type, callback, instance=0, thread=0)
ProcedureReturn SetWindowsHookEx_(type, callback, instance, thread)
EndProcedure
ProcedureDLL UnregisterHook(type, callback, instance=0, thread=0)
ProcedureReturn UnhookWindowsHookEx_(hook)
EndProcedure
When using
Import I get an error regarding an invalid machine type (using the lib) and when using
OpenLibary (using the dll) it always returns 0 regardless of which library I am using.
Code: Select all
If OpenLibrary(0, "hook.dll")
hdle = CallFunction(0, "RegisterHook", #WH_MOUSE, @HookMouse())
Debug hdle
EndIf
Just in case this is helpful I am running
Windows 8 (x64).
Any help would be appreciated as I am more than likely doing something wrong.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:15 pm
by srod
You are only passing 2 parameters to a DLL function expecting 4!
The client has no way of knowing that it should be passing 2 'dummy' values for the optional parameters. Either add 2 additional parameters to your CallFunction() or use Import/EndImport in which you can declare optional parameters, or use prototypes.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:19 pm
by srod
Sorry, didn't read your thread properly, though my comments still stand.
You sure the DLL isn't 32-bit? You cannot access a 32-bit dll from a 64-bit process. Are you accidentally trying to import the DLL (as opposed to the LIB) ?
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:30 pm
by srod
I have just created a 64-bit dll from your code and the following client loads the dll fine :
Code: Select all
Import "hook.lib"
RegisterHook(type, callback, instance=0, thread=0)
EndImport
Note that if I switch Import "hook.lib" to Import "hook.dll" then I get exactly the same error you report.
I can only think that you had switched the .dll for the .lib and vise versa!

Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:32 pm
by nblackburn
Do you need to use polink.exe to have a standalone lib?
The one compiled with the DLL requires the DLL which is giving me the invalid machine type error.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:37 pm
by srod
The .lib is a import library that is all. You still need to ship the dll. The import lib just makes accessing the dll easier from your client app point of view and simply contains information which the linker uses to build 'stubs' in your exe through which the dll functions are called.
If you really cannot get this to work bearing in mind my posts, then, well... Windows 8!!! Runs fine here on Win 7.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:41 pm
by nblackburn
Code: Select all
Import "hook.lib"
RegisterHook(type, callback, instance=0, thread=0)
EndImport
Procedure HookMouse(nCode, wParam, lParam)
Debug nCode
EndProcedure
RegisterHook(#WH_MOUSE, @HookMouse()) ; problem happens here!
The problem happens when I try and call the functions defined in the import.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:43 pm
by srod
Hang on, you said you were getting an invalid machine type error before? What error are you getting now?
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:45 pm
by nblackburn
Forgot the mention that I accidentally imported the DLL which obviously wont work.
Just discovered PureBasic doesn't compile it's temp exe to the working directory so it couldn't find the DLL needed. That hurdle is overcome but the function doesn't return anything to the console, like the code suggests...
Code: Select all
Import "hook.lib"
RegisterHook(type, callback, instance=0, thread=0)
EndImport
; doesn't happen
Procedure HookMouse(nCode, wParam, lParam)
Debug nCode
EndProcedure
Debug RegisterHook(#WH_MOUSE, @HookMouse()) ; consoles 0
If I though a debug next to the RegisterHook function then it consoles 0 which isn't right...
Re: Writing a DLL
Posted: Fri Feb 21, 2014 6:59 pm
by srod
The following works fine here (Win 7 x 64)
Code: Select all
Import "hook.lib"
RegisterHook(type, callback, instance=0, thread=0)
EndImport
Global nxtHook
Procedure HookMouse(nCode, wParam, lParam)
Debug "WM_ message : " + Str(wParam)
ProcedureReturn CallNextHookEx_(nxtHook, nCode, wParam, lParam)
EndProcedure
nxtHook = RegisterHook(#WH_MOUSE, @HookMouse(), 0, GetCurrentThreadId_()) ; problem happens here!
OpenWindow(0, 0, 0, 240, 140, "MouseBlock", #WS_CAPTION|#WS_SYSMENU|1)
Repeat
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
Re: Writing a DLL
Posted: Fri Feb 21, 2014 7:04 pm
by nblackburn
Your code works fine and now I understand what is not working, you are registering a local hook (application window) where as I am trying to register a global one (operating system) which isn't working.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 7:11 pm
by srod
I did wonder if that is what you were doing!
For a global hook you need the actual hook procedure to reside within the DLL and NOT the client. You also need to alter the parameters of the SetWindowsHookEx_() function.
The 'hMod' parameter must be the module identifier of the DLL. You can get this in the AttachProcess(Instance) entry point function. Just assign the 'Instance' variable to a global variable and set hMod equal to this value.
Also set the dwThreadId parameter to zero.
Your SetWindowsHookEx_() call will look something like :
Code: Select all
nxtHook = SetWindowsHookEx_(#WH_MOUSE, @DLL_HookMouse(), gInstance, 0)
Remember, the DLL_HookMouse() proc must be in the DLL itself. Do not attempt to have this function call into your client as it will potentially cross process boundaries.
I have never used a global hook (nasty things!

) and so am not 100% sure about the above info.
Re: Writing a DLL
Posted: Fri Feb 21, 2014 7:14 pm
by nblackburn
I have read they can be nasty, but this seems to be the only way to monitor and respond to mouse movement that isn't bound the the currently running application.
Re: Writing a DLL
Posted: Sat Feb 22, 2014 5:25 am
by chi
I wrote a program similar to dm2 (anyone remembers?

) a few years ago and never had problems with the global hook since!
Here are the core functions...
nlh.dll
Code: Select all
Enumeration
#NLH_DLL_CONTROL = #WM_USER + 101
EndEnumeration
ProcedureDLL NLH( nCode, wParam, *lParam.MOUSEHOOKSTRUCT )
If nCode < 0 : ProcedureReturn CallNextHookEx_( @NLH(), nCode, wParam, *lParam ) : EndIf
Select wParam
Case #WM_NCRBUTTONDOWN
Select *lParam\wHitTestCode
Case #HTCAPTION
ProcedureReturn PostMessage_(FindWindow_(0,"[ nlh ]"), #NLH_DLL_CONTROL, *lParam\hwnd, *lParam\wHitTestCode)
EndSelect
EndSelect
ProcedureReturn CallNextHookEx_( @NLH(), nCode, wParam, *lParam )
EndProcedure
nlh.exe
Code: Select all
Enumeration
#Window
#NLH_DLL
#NLH_DLL_CONTROL = #WM_USER + 101
EndEnumeration
OpenWindow(#Window, 0, 0, 320, 100, "[ nlh ]", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_Invisible)
TextGadget(0, 20,40,300,30, "Right-Click on any titlebar to minimize the selected window")
If OpenLibrary(#NLH_DLL, "nlh.dll")
NLH_DLL = SetWindowsHookEx_(#WH_MOUSE, GetFunction(#NLH_DLL, "NLH"), LibraryID(#NLH_DLL), #Null )
Else
MessageRequester("", "nlh.dll not found...")
End
EndIf
HideWindow(#Window, #False, #PB_Window_ScreenCentered)
Repeat
event = WaitWindowEvent()
Select event
Case #NLH_DLL_CONTROL
Select EventlParam()
Case #HTCAPTION
hWnd = EventwParam()
ShowWindow_(hWnd, #SW_MINIMIZE)
Beep_(800,50)
EndSelect
EndSelect
Until event = #PB_Event_CloseWindow
If NLH_DLL
UnhookWindowsHookEx_(NLH_DLL)
EndIf
If IsLibrary(#NLH_DLL)
CloseLibrary(#NLH_DLL)
EndIf
Reminds me to rewrite [ nlh ] with PB5.21
cheers, chi
Re: Writing a DLL
Posted: Sat Feb 22, 2014 10:59 am
by srod
That is a nice example. That should get you up and running nblackburn.