Setting the window callback for a window outside of PB?

Just starting out? Need help? Post your questions and find answers here.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Setting the window callback for a window outside of PB?

Post by Mistrel »

Is there a way to do something similar to SetWindowCallback(function_ptr,#window) but to a window handle outside of PB?

I program in DarkBasic and would like to wrap something like this into a plugin so that I can capture window events from the DBP window and send them to a function.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Use SetWindowLong_() with #GWL_WNDPROC. Make sure you use CallWindowProc_() to call the old window procedure if you want default events to be handled. (Get the address of the old procedure with GetWindowLong_() and #GWL_WNDPROC.)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

I'm not sure you can do this in a cross-process manner Trond. Well, I've just tried it and it didn't work, and using GetLastError_() returned an access denied error.

I think the only way to do this if the Window in question is from another process is to use a global hook.
I may look like a mule, but I'm not a complete ass.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

No, you can't do it in other processes, but it works on windows created in the same process but by a different programming language. If you can load a dll into the process you can do it.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

Am I doing something wrong? I can't make it work in this test program.

Code: Select all

Global ptr

Procedure EnumProc(hwnd, lParam)
  *hwnd.LONG = lParam
  *hwnd\l = hwnd
  ProcedureReturn 0
EndProcedure

Procedure GetCallingHwnd()
  *hwnd.LONG = AllocateMemory(SizeOf(LONG))
  EnumThreadWindows_(GetCurrentThreadId_(), @EnumProc(), *hwnd)
  ProcedureReturn *hwnd\l
EndProcedure 

Procedure WinCallback(hWnd,uMsg,wParam,lParam)
	Select uMsg
		Case #WM_SIZE
			; do nothing
		Case #WM_LBUTTONUP
			MessageRequester("","Hello!")
	EndSelect
	If ptr
		CallFunctionFast(ptr,hWnd,uMsg,wParam,lParam)
	EndIf
	ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure

ProcedureCDLL _SetWindowCallback()
	hwnd=GetCallingHwnd()
	ptr=GetWindowLong_(hwnd,#GWL_WNDPROC) ; capture the old callback ptr
	SetWindowLong_(hwnd,#GWL_WNDPROC,@WinCallback()) ; set the new callback ptr
EndProcedure

OpenWindow(0,100,200,320,240,"Window",#PB_Window_SystemMenu)

OpenLibrary(0,"windowcallback.dll")
CallFunction(0,"_SetWindowCallback")

Repeat
Until WaitWindowEvent()=#PB_Event_CloseWindow
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Well first you need to separate this into 2 programs; one for the dll and one a separate program to open the window and call the dll etc. At the moment you are combining it all into one which is a big no-no!

Secondly, you're mixing calling conventions. Change the ProcedureCDLL for just ProcedureDLL.
I may look like a mule, but I'm not a complete ass.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

Nevermind. I forgot to forward the return value from DarkBasic's old callback. That's what was causing the problem. :)

That and my example was just bad. :roll:
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

I'm being told on the Dark Basic Professional board that there is a problem with the method I came up with for using an alternative callback. I don't understand what the problem is because I only see it working. Would someone explain to me what's wrong?

http://forum.thegamecreators.com/?m=for ... 60&b=1&p=0

This is the source for my callback.dll.

Code: Select all

Define old_wndproc.l

Procedure EnumProc(hwnd, lParam)
  *hwnd.LONG = lParam
  *hwnd\l = hwnd
  ProcedureReturn 0
EndProcedure

Procedure GetCallingHwnd()
  *hwnd.LONG = AllocateMemory(SizeOf(LONG))
  EnumThreadWindows_(GetCurrentThreadId_(), @EnumProc(), *hwnd)
  ProcedureReturn *hwnd\l
EndProcedure 

ProcedureCDLL _SetWindowCallback(wndproc)
	Shared old_wndproc ; the old callback ptr to be used for passing on the old events
	; hWnd, handle of the window to register the callback to
	; wndproc, the pointer for the procedure to be used for this callback
	dbp_hwnd=GetCallingHwnd()
	old_wndproc=GetWindowLong_(dbp_hwnd,#GWL_WNDPROC) ; capture the old callback ptr
	SetWindowLong_(dbp_hwnd,#GWL_WNDPROC,wndproc) ; pet the new callback ptr
	ProcedureReturn old_wndproc ; return the old callback ptr to pass-through the old events
EndProcedure

ProcedureCDLL CallOldWndProc(hWnd,uMsg,wParam,lParam)
	Shared old_wndproc ; the old callback ptr to be used for passing on the old events
	result=CallFunctionFast(old_wndproc,hWnd,uMsg,wParam,lParam)
	ProcedureReturn result
EndProcedure
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Well, putting aside the fact that the very idea of what you are doing strikes me as a little odd, the code looks okay.

Just remember that because you have used ProcedureCDLL() that you have declared your two exported procedures as using the CDECL calling convention.

Thus if you are calling these dll procedures from PB, then use either CallCFunction() or CallCFunctionFast() or ImportC etc. Do not use CallFunction() or CallfunctionFast() or Import etc. If calling from another language then ensure that language is setup to use the CDECL convention.
I may look like a mule, but I'm not a complete ass.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Post by Mistrel »

Well, putting aside the fact that the very idea of what you are doing strikes me as a little odd, the code looks okay.
This dll allows me to register my own wincallback function natively within DBP. This is really useful for trapping critical system messages and acting upon them while the game is in a critical loop.

It's basically the same as SetWinCallback() for PB but this one preserves the original callback and is specificall written for DBP.

Now I can work with the wincallback just like any other function.

Code: Select all

function WinCallback(hWnd,uMsg,wParam,lParam)
	Select uMsg
		Case WM_SIZE
			` do nothing
		EndCase
		Case WM_LBUTTONUP
			print "lbutton up"
		EndCase
	EndSelect
	result=CallOldWndProc(hWnd,uMsg,wParam,lParam)
endfunction result
PurePWNRER
User
User
Posts: 45
Joined: Mon Mar 27, 2006 5:44 am

Post by PurePWNRER »

LOL, talk about limited languages.
Why would anyone use that language when it doesn't even support this...
:/ My kingdom for a snippet!
I might bash, But I provide.
Post Reply