Writing a DLL

Just starting out? Need help? Post your questions and find answers here.
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Writing a DLL

Post 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.
Image
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post 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.
I may look like a mule, but I'm not a complete ass.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post 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) ?
I may look like a mule, but I'm not a complete ass.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post 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! :)
I may look like a mule, but I'm not a complete ass.
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Re: Writing a DLL

Post 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.
Image
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post 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.
I may look like a mule, but I'm not a complete ass.
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Re: Writing a DLL

Post 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.
Image
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post by srod »

Hang on, you said you were getting an invalid machine type error before? What error are you getting now?
I may look like a mule, but I'm not a complete ass.
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Re: Writing a DLL

Post 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...
Image
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post 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
I may look like a mule, but I'm not a complete ass.
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Re: Writing a DLL

Post 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.
Image
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post 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.
I may look like a mule, but I'm not a complete ass.
User avatar
nblackburn
User
User
Posts: 67
Joined: Mon Aug 19, 2013 1:22 am
Location: United Kingdom
Contact:

Re: Writing a DLL

Post 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.
Image
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: Writing a DLL

Post 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 8)

cheers, chi
Et cetera is my worst enemy
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Writing a DLL

Post by srod »

That is a nice example. That should get you up and running nblackburn.
I may look like a mule, but I'm not a complete ass.
Post Reply