www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - amazing function behavior

reply Zarathustra <adam.chrapkowski gmail.com> writes:
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
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
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
parent Zarathustra <adam.chrapkowski gmail.com> writes:
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
prev sibling next sibling parent reply Zarathustra <adam.chrapkowski gmail.com> writes:
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
parent reply Zarathustra <adam.chrapkowski gmail.com> writes:
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
parent reply Kagamin <spam here.lot> writes:
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
parent reply Don <nospam nospam.com> writes:
Kagamin wrote:
 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
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.
Oct 20 2009
parent reply Zarathustra <adam.chrapkowski gmail.com> writes:
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
parent Don <nospam nospam.com> writes:
Zarathustra wrote:
 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!
Ah, I misread it.
 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
prev sibling parent reply "Phil Deets" <pjdeets2 gmail.com> writes:
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
parent reply Zarathustra <adam.chrapkowski gmail.com> writes:
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
parent Zarathustra <adam.chrapkowski gmail.com> writes:
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