www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - WindowProc in a class - function and pointer problem

reply "D-sturbed" <someone somewhere.com> writes:
Hello, is there a way to wrap a WindowProc (so "LRESULT 
WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
nothrow") in a class and to link it to a WindowClass without 
puting it as "static" ?

Because defacto every datum used in the WindowProc must also be 
static.
The problem technically is that if "static" is not specified, the 
compiler won't allow this: "MyWinClass.lpfnWndProc = 
&TheWindowProcInMyClass".

I've also tried this: "MyWinClass.lpfnWndProc = 
(&TheWindowProcInMyClass).funcptr" but, while it compiles, it 
drastically fails at the run-time...
May 22 2013
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-05-22, 21:30, D-sturbed wrote:

 Hello, is there a way to wrap a WindowProc (so "LRESULT WindowProc(HWND  
 hWnd, UINT message, WPARAM wParam, LPARAM lParam) nothrow") in a class  
 and to link it to a WindowClass without puting it as "static" ?

 Because defacto every datum used in the WindowProc must also be static.
 The problem technically is that if "static" is not specified, the  
 compiler won't allow this: "MyWinClass.lpfnWndProc =  
 &TheWindowProcInMyClass".

 I've also tried this: "MyWinClass.lpfnWndProc =  
 (&TheWindowProcInMyClass).funcptr" but, while it compiles, it  
 drastically fails at the run-time...
Not possible, no. What you *can* do is have some way to translate from hwnd to class instance, and fetch the right instance inside the static wndProc to call a member function on that. -- Simen
May 22 2013
parent reply "Diggory" <diggsey googlemail.com> writes:
On Wednesday, 22 May 2013 at 20:25:40 UTC, Simen Kjaeraas wrote:
 On 2013-05-22, 21:30, D-sturbed wrote:

 Hello, is there a way to wrap a WindowProc (so "LRESULT 
 WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM 
 lParam) nothrow") in a class and to link it to a WindowClass 
 without puting it as "static" ?

 Because defacto every datum used in the WindowProc must also 
 be static.
 The problem technically is that if "static" is not specified, 
 the compiler won't allow this: "MyWinClass.lpfnWndProc = 
 &TheWindowProcInMyClass".

 I've also tried this: "MyWinClass.lpfnWndProc = 
 (&TheWindowProcInMyClass).funcptr" but, while it compiles, it 
 drastically fails at the run-time...
Not possible, no. What you *can* do is have some way to translate from hwnd to class instance, and fetch the right instance inside the static wndProc to call a member function on that.
If you are only going to have one window you can store the "this" pointer in a global variable. If you want to have multiple windows each with messages going to an instance of a class, you need to do the following: - Specify the "this" pointer as the lpParam argument to CreateWindow - Hook up a static WndProc function - Have the static function handle a WM_NCCREATE message as follows: - Cast the "lParam" parameter to a CREATESTRUCT* and retrieve the "this" pointer from the "lpCreateParams" member. - Use "SetWindowLongPtr" to set the GWLP_USERDATA property of the window "hwnd" to the "this" pointer - Have the static function handle all messages as follows: - Use "GetWindowLongPtr" to get the GWLP_USERDATA property of the window "hwnd" to get the "this" pointer - Pass the message on to a non-static WndProc in the class using the discovered "this" pointer You also need to make sure that there is a separate reference to the class instance for as long as the window exists, because the garbage collector will not scan the window properties and so may think the object is garbage otherwise.
May 22 2013
parent reply "D-sturbed" <someone somewhere.com> writes:
On Wednesday, 22 May 2013 at 21:22:52 UTC, Diggory wrote:
 On Wednesday, 22 May 2013 at 20:25:40 UTC, Simen Kjaeraas wrote:
 On 2013-05-22, 21:30, D-sturbed wrote:

 Hello, is there a way to wrap a WindowProc (so "LRESULT 
 WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM 
 lParam) nothrow") in a class and to link it to a WindowClass 
 without puting it as "static" ?

 Because defacto every datum used in the WindowProc must also 
 be static.
 The problem technically is that if "static" is not specified, 
 the compiler won't allow this: "MyWinClass.lpfnWndProc = 
 &TheWindowProcInMyClass".

 I've also tried this: "MyWinClass.lpfnWndProc = 
 (&TheWindowProcInMyClass).funcptr" but, while it compiles, it 
 drastically fails at the run-time...
Not possible, no. What you *can* do is have some way to translate from hwnd to class instance, and fetch the right instance inside the static wndProc to call a member function on that.
If you are only going to have one window you can store the "this" pointer in a global variable. If you want to have multiple windows each with messages going to an instance of a class, you need to do the following: - Specify the "this" pointer as the lpParam argument to CreateWindow - Hook up a static WndProc function - Have the static function handle a WM_NCCREATE message as follows: - Cast the "lParam" parameter to a CREATESTRUCT* and retrieve the "this" pointer from the "lpCreateParams" member. - Use "SetWindowLongPtr" to set the GWLP_USERDATA property of the window "hwnd" to the "this" pointer - Have the static function handle all messages as follows: - Use "GetWindowLongPtr" to get the GWLP_USERDATA property of the window "hwnd" to get the "this" pointer - Pass the message on to a non-static WndProc in the class using the discovered "this" pointer You also need to make sure that there is a separate reference to the class instance for as long as the window exists, because the garbage collector will not scan the window properties and so may think the object is garbage otherwise.
Yes I'm in the "multiple Window case", every window is wraped in a class and has its own message handler. I know that Win, in its callback system, often lets you retrieve a pointer to something, and I haven't get it was possible in this case...(which is you seem to describe). I will try this tomorrow.
May 22 2013
parent reply "evilrat" <evilrat666 gmail.com> writes:
On Wednesday, 22 May 2013 at 21:42:32 UTC, D-sturbed wrote:
 Yes I'm in the "multiple Window case", every window is wraped 
 in a class and has its own message handler. I know that Win, in 
 its callback system, often lets you retrieve a pointer to 
 something, and I haven't get it was possible in this 
 case...(which is you seem to describe). I will try this 
 tomorrow.
you can't really make it without static wndproc. if you don't know how to do it just go google some wndproc in a class tutors for c++, i can even recommend you one(i had used my own port of this in D before i switched to crossplatform lib for my needs) - http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx
May 22 2013
parent reply Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
On 5/22/2013 8:49 PM, evilrat wrote:
 On Wednesday, 22 May 2013 at 21:42:32 UTC, D-sturbed wrote:
 Yes I'm in the "multiple Window case", every window is wraped in a
 class and has its own message handler. I know that Win, in its
 callback system, often lets you retrieve a pointer to something, and I
 haven't get it was possible in this case...(which is you seem to
 describe). I will try this tomorrow.
you can't really make it without static wndproc. if you don't know how to do it just go google some wndproc in a class tutors for c++, i can even recommend you one(i had used my own port of this in D before i switched to crossplatform lib for my needs) - http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx
I had a partial port of WTL over to D which worked well enough for what I needed, the core of the WndProc handling is down below. Each HWND is owned by the thread it was created on, so assigning it into D associative array (which is thread local) can do the trick. It involved a hack, before any call to the Win32 CreateWindow/CreateWindowEx APIs, to capture the association with the new HWND and to remove them when they get cleaned up. There is probably a better way but this worked enough to get started, and should work with multiple windows reasonably well. CWindowInterface g_CreatingWindow; CWindowInterface[HWND] g_HWNDtoObject; extern (Windows) int CWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { int WindowProcReturnValue = 0; /* auto EventMsg = appender!string(); formattedWrite(EventMsg, "EventMsg (hWnd=%1$s) (uMsg=%2$s) (wParam=%3$s) (lParam=%4$s)\n", cast(DWORD)hWnd, cast(DWORD)uMsg, cast(DWORD)wParam, cast(DWORD)lParam); OutputDebugString(toUTFz!(const(wchar)*)(EventMsg.data)); */ if (g_CreatingWindow) { g_HWNDtoObject[hWnd] = g_CreatingWindow; g_CreatingWindow = null; } auto Window = g_HWNDtoObject[cast(HANDLE)hWnd]; if (Window is null) { WindowProcReturnValue = DefWindowProc(hWnd, uMsg, wParam, lParam); } else { WindowProcReturnValue = Window.WindowProc(hWnd, uMsg, wParam, lParam); } if (uMsg == WM_NCDESTROY) { g_HWNDtoObject.remove(hWnd); } return WindowProcReturnValue; }
May 22 2013
parent "evilrat" <evilrat666 gmail.com> writes:
On Thursday, 23 May 2013 at 06:31:02 UTC, Sean Cavanaugh wrote:
 I had a partial port of WTL over to D which worked well enough 
 for what I needed, the core of the WndProc handling is down 
 below.   Each HWND is owned by the thread it was created on, so 
 assigning it into D associative array (which is thread local) 
 can do the trick.  It involved a hack, before any call to the 
 Win32 CreateWindow/CreateWindowEx APIs, to capture the 
 association with the new HWND and to remove them when they get 
 cleaned up.  There is probably a better way but this worked 
 enough to get started, and should work with multiple windows 
 reasonably well.
sure this is doable but it breaks the entire idea of oop. this is also can be put as static member, still it would break oop. that link i put here is show what is really needed, and it's clean and simple. simply there is only 2 required methods, one for creating(and binding) hwnd with class instance and another to retrieve that instance and do its own message handling, no other code necessary and everything incapsulated. but i don't remember if it works without gc messed up that instance while not falling to such tricks like arrays(because it is may be possible that gc collect instance while window is alive).
May 23 2013