digitalmars.D.learn - amazing function behavior
- Zarathustra (108/108) Oct 19 2009 Function is never called but why?
- Daniel Keep (6/7) Oct 19 2009 It shouldn't even COMPILE.
- Zarathustra (10/17) Oct 19 2009 My callback wndProc IS static, global function.
- Zarathustra (1/1) Oct 19 2009 In addition I tested the code in DMD1.050 and DMD2.035. In DMD 1 It work...
- Zarathustra (8/8) Oct 19 2009 Oh, I just find out cause of this behaviour in other module I had:
- Kagamin (2/10) Oct 20 2009 looks like a bug
- Don (4/16) Oct 20 2009 It isn't. Tfunc2 is a function pointer, which is typically the same as
- Zarathustra (8/11) Oct 20 2009 Never mind what is stored inside func2. 0x00 is only to simplify the cod...
- Don (3/15) Oct 21 2009 Clearly a bug. Please put it into Bugzilla.
- Phil Deets (10/121) Oct 20 2009 I don't know what the problem is, but I would try checking to see if the...
- Zarathustra (18/26) Oct 20 2009 Ok I will try to explain:
- Zarathustra (14/14) Oct 21 2009 I resolved my access violation problem by including at the begin of wndP...
Function is never called but why? look at: window.Window.wndProc : case WM.LBUTTONDOWN //______________________________________________ module window; private import base; private import structs; private static import user32; private static import kernel32; private static import gdi32; private: extern (Windows) static dword wndProc(ptr o_hwnd, dword o_msg, dword o_wparam, dword o_lparam){ alias user32.EWindowMessage WM; auto l_wnd = cast(Window*)user32.getWindowLong(o_hwnd, 0x00); if(o_msg == WM.NCCREATE){ user32.setWindowLong(o_hwnd, 0x00, *(cast(dword*)o_lparam)); } else if(l_wnd is null){ return 0x00; } return (cast(Window*)user32.getWindowLong(o_hwnd, 0x00)).wndProc(o_hwnd, o_msg, o_wparam, o_lparam); } public: class Window{ private const ptr handle; void onMouseDown(MouseEventArgs o_mea){ user32.messageBox(null, cast(wstr)"Window", cast(wstr)"msg", 0x00); } this(){ WINWndClassEx wndClass; wndClass.size = 0x00000030; wndClass.style = 0x00000003; wndClass.wndProc = cast(ptr)&.wndProc; wndClass.clsExtraBytes = 0x00000000; wndClass.wndExtraBytes = 0x00000004; wndClass.hInstance = kernel32.getModuleHandle(null); wndClass.hIcon = user32.loadIcon(null, 0x00007F00); wndClass.hCursor = user32.loadCursor(null, 0x00007F00); wndClass.hbrBackground = gdi32.getStockObject(0x00000000); wndClass.menuName = null; wndClass.className = cast(wstr)"clsname"; wndClass.hIconSm = user32.loadIcon(null, 0x00007F00); if(!user32.registerClassEx(cast(ptr)&wndClass)){ if(kernel32.getLastError() != 0x0582){ user32.messageBox(null, user32.translateErrorCode(kernel32.getLastError()), cast(wstr)"error", 0x00000000); assert(false, "window class registering failed"); } } handle = user32.createWindowEx( 0, wndClass.className, cast(wstr)"<applicationcaption>", 0x00CF0000, 0x00000000, 0x00000000, 0x00000280, 0x000001E0, null, null, kernel32.getModuleHandle(null), cast(ptr)&this ); if(handle is null){ user32.messageBox(null, user32.translateErrorCode(kernel32.getLastError()), cast(wstr)"error", 0x00000000); assert(false, "window creating failed"); } } public void run(){ WINMsg msg; user32.showWindow(handle, 0x0000000A); user32.updateWindow(handle); while(user32.getMessage(cast(ptr)&msg, null, 0, 0)){ user32.translateMessage(cast(ptr)&msg); user32.dispatchMessage(cast(ptr)&msg); } } private dword wndProc(ptr o_hwnd, dword o_msg, dword o_wparam, dword o_lparam){ alias user32.EWindowMessage WM; alias user32.EMouseKey WK; switch(o_msg){ case WM.DESTROY: user32.postQuitMessage(0x00); break; case WM.LBUTTONDOWN: MouseEventArgs l_mea; l_mea.button = MouseButton.LEFT; l_mea.location.x = loword(o_lparam); l_mea.location.x = hiword(o_lparam); user32.messageBox(null, cast(wstr)"LBUTTONDOWN", cast(wstr)"msg", 0x00); // ok it is displayed this.onMouseDown(l_mea); // !!! it is never called break; default: return user32.defWindowProc(o_hwnd, o_msg, o_wparam, o_lparam); } return 0; } public Rect getBounds(){ WINRect l_rc; user32.getWindowRect(this.handle, cast(ptr)&l_rc); with(l_rc) return Rect(left, top, right - left, bottom - top); } } //________________________________________________________
Oct 19 2009
Zarathustra wrote:Function is never called but why?It shouldn't even COMPILE. You can't use member functions as Windows callbacks. You haven't even used the correct calling convention on it. Callbacks for Win API functions have to be, I believe, extern(Windows), and they have to be free functions or static members.
Oct 19 2009
Daniel Keep Wrote:It shouldn't even COMPILE. You can't use member functions as Windows callbacks. You haven't even used the correct calling convention on it. Callbacks for Win API functions have to be, I believe, extern(Windows), and they have to be free functions or static members.My callback wndProc IS static, global function. .wndProc = window.wndProc which is static, and non-member wndClass.wndProc = cast(ptr)&.wndProc; // .wndProc not wndProc pointer to Window object is pass to window.wndProc in additional bytes. My question relates to something completely different. this.onButtonDown(l_mea) // problematic call not return (cast(Window*)user32.getWindowLong(o_hwnd, 0x00)).wndProc(o_hwnd, o_msg, o_wparam, o_lparam);// which works correctly
Oct 19 2009
In addition I tested the code in DMD1.050 and DMD2.035. In DMD 1 It works correctly, but in DMD2 line: 'this.onMouseDown(l_mea);' works like 'break' (no exceptions, neither compilation nor linking warnings, just like break). Is it DMD2 bug?
Oct 19 2009
Oh, I just find out cause of this behaviour in other module I had: extern (Windows) alias dword function() Tfunc1; extern (Windows) alias dword function(wstr) Tfunc2; const Tfunc2 func2; static this(){ func2 = cast(Tfunc1)0x0; // for DMD2 It is not error!!! // but it doesn't has a sens!!! }
Oct 19 2009
Zarathustra Wrote:Oh, I just find out cause of this behaviour in other module I had: extern (Windows) alias dword function() Tfunc1; extern (Windows) alias dword function(wstr) Tfunc2; const Tfunc2 func2; static this(){ func2 = cast(Tfunc1)0x0; // for DMD2 It is not error!!! // but it doesn't has a sens!!! }looks like a bug
Oct 20 2009
Kagamin wrote:Zarathustra Wrote:It isn't. Tfunc2 is a function pointer, which is typically the same as size_t. So any int can be stored inside it. It's generally a very bad idea to do so, of course.Oh, I just find out cause of this behaviour in other module I had: extern (Windows) alias dword function() Tfunc1; extern (Windows) alias dword function(wstr) Tfunc2; const Tfunc2 func2; static this(){ func2 = cast(Tfunc1)0x0; // for DMD2 It is not error!!! // but it doesn't has a sens!!! }looks like a bug
Oct 20 2009
Don Wrote:It isn't. Tfunc2 is a function pointer, which is typically the same as size_t. So any int can be stored inside it. It's generally a very bad idea to do so, of course.Never mind what is stored inside func2. 0x00 is only to simplify the code. Tfunc1 - pointer to function without args Tfunc2 - pointer to function with 1 arg so: func2 = cast(Tfunc1)something; doesn't have a sense, because type of func2 is Tfunc2 type not Tfunc1! In D1 this causes compilation error, but DMD2.035 doesn't generate any compilation message, even warning.
Oct 20 2009
Zarathustra wrote:Don Wrote:Ah, I misread it.It isn't. Tfunc2 is a function pointer, which is typically the same as size_t. So any int can be stored inside it. It's generally a very bad idea to do so, of course.Never mind what is stored inside func2. 0x00 is only to simplify the code. Tfunc1 - pointer to function without args Tfunc2 - pointer to function with 1 arg so: func2 = cast(Tfunc1)something; doesn't have a sense, because type of func2 is Tfunc2 type not Tfunc1!In D1 this causes compilation error, but DMD2.035 doesn't generate any compilation message, even warning.Clearly a bug. Please put it into Bugzilla.
Oct 21 2009
On Mon, 19 Oct 2009 02:39:57 -0500, Zarathustra <adam.chrapkowski gmail.com> wrote:Function is never called but why? look at: window.Window.wndProc : case WM.LBUTTONDOWN //______________________________________________ module window; private import base; private import structs; private static import user32; private static import kernel32; private static import gdi32; private: extern (Windows) static dword wndProc(ptr o_hwnd, dword o_msg, dword o_wparam, dword o_lparam){ alias user32.EWindowMessage WM; auto l_wnd = cast(Window*)user32.getWindowLong(o_hwnd, 0x00); if(o_msg == WM.NCCREATE){ user32.setWindowLong(o_hwnd, 0x00, *(cast(dword*)o_lparam)); } else if(l_wnd is null){ return 0x00; } return (cast(Window*)user32.getWindowLong(o_hwnd, 0x00)).wndProc(o_hwnd, o_msg, o_wparam, o_lparam); } public: class Window{ private const ptr handle; void onMouseDown(MouseEventArgs o_mea){ user32.messageBox(null, cast(wstr)"Window", cast(wstr)"msg", 0x00); } this(){ WINWndClassEx wndClass; wndClass.size = 0x00000030; wndClass.style = 0x00000003; wndClass.wndProc = cast(ptr)&.wndProc; wndClass.clsExtraBytes = 0x00000000; wndClass.wndExtraBytes = 0x00000004; wndClass.hInstance = kernel32.getModuleHandle(null); wndClass.hIcon = user32.loadIcon(null, 0x00007F00); wndClass.hCursor = user32.loadCursor(null, 0x00007F00); wndClass.hbrBackground = gdi32.getStockObject(0x00000000); wndClass.menuName = null; wndClass.className = cast(wstr)"clsname"; wndClass.hIconSm = user32.loadIcon(null, 0x00007F00); if(!user32.registerClassEx(cast(ptr)&wndClass)){ if(kernel32.getLastError() != 0x0582){ user32.messageBox(null, user32.translateErrorCode(kernel32.getLastError()), cast(wstr)"error", 0x00000000); assert(false, "window class registering failed"); } } handle = user32.createWindowEx( 0, wndClass.className, cast(wstr)"<applicationcaption>", 0x00CF0000, 0x00000000, 0x00000000, 0x00000280, 0x000001E0, null, null, kernel32.getModuleHandle(null), cast(ptr)&this ); if(handle is null){ user32.messageBox(null, user32.translateErrorCode(kernel32.getLastError()), cast(wstr)"error", 0x00000000); assert(false, "window creating failed"); } } public void run(){ WINMsg msg; user32.showWindow(handle, 0x0000000A); user32.updateWindow(handle); while(user32.getMessage(cast(ptr)&msg, null, 0, 0)){ user32.translateMessage(cast(ptr)&msg); user32.dispatchMessage(cast(ptr)&msg); } } private dword wndProc(ptr o_hwnd, dword o_msg, dword o_wparam, dword o_lparam){ alias user32.EWindowMessage WM; alias user32.EMouseKey WK; switch(o_msg){ case WM.DESTROY: user32.postQuitMessage(0x00); break; case WM.LBUTTONDOWN: MouseEventArgs l_mea; l_mea.button = MouseButton.LEFT; l_mea.location.x = loword(o_lparam); l_mea.location.x = hiword(o_lparam); user32.messageBox(null, cast(wstr)"LBUTTONDOWN", cast(wstr)"msg", 0x00); // ok it is displayed this.onMouseDown(l_mea); // !!! it is never called break; default: return user32.defWindowProc(o_hwnd, o_msg, o_wparam, o_lparam); } return 0; } public Rect getBounds(){ WINRect l_rc; user32.getWindowRect(this.handle, cast(ptr)&l_rc); with(l_rc) return Rect(left, top, right - left, bottom - top); } } //________________________________________________________I don't know what the problem is, but I would try checking to see if the pointer at window construction and the this pointer before calling onMouseDown are the same. Maybe there is a problem with using the result of getWindowLong as a pointer. For example, one value could be 32-bits and the pointer could be 64-bits. I didn't run the code to test anything, I'm just throwing out some ideas which may be way off. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Oct 20 2009
Phil Deets Wrote:I don't know what the problem is, but I would try checking to see if the pointer at window construction and the this pointer before calling onMouseDown are the same. Maybe there is a problem with using the result of getWindowLong as a pointer. For example, one value could be 32-bits and the pointer could be 64-bits. I didn't run the code to test anything, I'm just throwing out some ideas which may be way off. --Ok I will try to explain: In my opinion my code should works. I would like to refer to two places in the code. 1. inside window module: user32.messageBox(null, cast(wstr)"LBUTTONDOWN", cast(wstr)"msg", 0x00); this.onMouseDown(l_mea); 2: inside test module, version 1: Window wnd1 = new Window(); wnd1.run() inside test module, version 2: Window wnd1 = new Window(); Window wnd2 = new Window(); wnd1.run() Both versions should work identically. When the mouse button is clicked inside the window, I expect two messageBoxes: The first one with message "LBUTTONDOWN", and the second "Window". But it is done only with the first version of test module (without wnd2 = new Window()). In the second case (with wnd2 = new Window()) I see message "LBUTTONDOWN" and Access Violation with DMD 1.050 or just nothing! with DMD 2.035 (therefore 'amazing' in the topic). I apologize for my horrible English, but I hope I explained that enough clearly.
Oct 20 2009
I resolved my access violation problem by including at the begin of wndProc inside Window class, the following code: //____________________________________________________ private dword wndProc(ptr o_hwnd, dword o_msg, ... { asm{ push 0x00000000; push [o_hwnd]; call [user32.getWindowLong]; mov [EBP - 0x04], EAX; } switch(o_msg){ ... } //____________________________________________________
Oct 21 2009