[SOLVED] windows API WNDPROC lazarus / 34-Windows ---------------------------------------------------------------------- KemBill · 2017-12-03 16:31 I like to reinvent the wheel  I am building a window from scratch with only api. WNDPROC is defined like this (so you cannot bind a window proc of an object instance) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i WNDPROC = function (_para1:HWND; _para2:UINT; _para3:WPARAM; _para4:LPARAM):LRESULT;stdcall;  how would you do if you wanted to use some objects variables and/or functions in the WNDPROC (since you are not in the same namespace) without having global variables (a kind of depency injection) ? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  type  THello = class(TObject)    procedure Something;  end; function WNDPROC(hWnd:HWND; Msg:UINT; WPARAM:WPARAM; LPARAM:LPARAM):LRESULT;stdcall;begin  case (Msg) of    //THello does not exist here !!    // cannot bind THello.WNDPROC because of wndproc definition  end;end; ---------------------------------------------------------------------- marcov · 2017-12-03 17:07 Usually one of the params of the wndproc is a parameter that you can register earlier. Usually you pass SELF there. ---------------------------------------------------------------------- balazsszekely · 2017-12-03 17:29 Class function combined with static should work, like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  THello = class(TObject)  private    class function WNDPROC(hWnd:HWND; Msg:UINT; WPARAM:WPARAM; LPARAM:LPARAM):LRESULT; stdcall; static;    procedure Something;  end; implementation class function THello.WNDPROC(hWnd: HWND; Msg: UINT; WPARAM: WPARAM;  LPARAM: LPARAM): LRESULT; stdcall;begin end; ---------------------------------------------------------------------- KemBill · 2017-12-03 17:46 Quote from: GetMem on December 03, 2017, 06:29:39 pmClass function combined with static should work, like this: I tried, doesn't compile, because it's still a procedure of object Since it's static, it doesn't allow me to share variables with the object instance? ---------------------------------------------------------------------- taazz · 2017-12-03 18:38 Quote from: KemBill on December 03, 2017, 05:31:29 pmI like to reinvent the wheel  doubt it. Quote from: KemBill on December 03, 2017, 05:31:29 pmI am building a window from scratch with only api. WNDPROC is defined like this (so you cannot bind a window proc of an object instance) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i WNDPROC = function (_para1:HWND; _para2:UINT; _para3:WPARAM; _para4:LPARAM):LRESULT;stdcall;  how would you do if you wanted to use some objects variables and/or functions in the WNDPROC (since you are not in the same namespace) without having global variables (a kind of depency injection) ? to put it as simple as possible you have a generic wndproc that does nothing more than calling the the method for you eg. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function WNDPROC(hWnd:HWND; Msg:UINT; WPARAM:WPARAM; LPARAM:LPARAM):LRESULT;stdcall;var  vData:Pointer;begin   vData := Pointer(GetWindowLongPtr(hWnd, GWLP_USERDATA));   result := TWinControl(VData).WindowPorc(hWnd, Msg, WPARAM,LPARAM);end; Just make sure when you create the window to SetWindowlongPtr(hwnd, GWLP_USERDATA, self) or something along those lines. ---------------------------------------------------------------------- balazsszekely · 2017-12-03 19:01 QuoteI tried, doesn't compile, because it's still a procedure of objectIt compiles fine both with Lazarus 18RC5/Trunk. Please see attached project. PS: I have to admit, I'm not sure anymore what are you after. ---------------------------------------------------------------------- KemBill · 2017-12-03 19:10 Quote from: GetMem on December 03, 2017, 08:01:03 pmQuoteI tried, doesn't compile, because it's still a procedure of objectIt compiles fine both with Lazarus 18RC5/Trunk. Please see attached project. PS: I have to admit, I'm not sure anymore what are you after. you are using forms... mode Delphi, will do the test Quote from: taazz on December 03, 2017, 07:38:20 pm Just make sure when you create the window to SetWindowlongPtr(hwnd, GWLP_USERDATA, self) or something along those lines. Thank you all, I'm back on the rails ---------------------------------------------------------------------- KemBill · 2017-12-03 21:24 Here it is : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit hello; {$mode objfpc}{$H+} interface uses  Windows, Classes, SysUtils; type   { THello }   THello = class(TObject)  private    someText: string;    function WindowProc(hWnd: HWND; Msg: UINT; WPARAM: WPARAM;      LPARAM: LPARAM): LRESULT; stdcall;  public    constructor Create;    destructor Destroy; override;    procedure Run;  end; implementation function dummy(hWnd: HWND; Msg: UINT; WPARAM: WPARAM; LPARAM: LPARAM): LRESULT; stdcall;var  vData: Pointer;begin  vData := Pointer(GetWindowLongPtr(hWnd, GWLP_USERDATA));  Result := THello(VData).WindowProc(hWnd, Msg, WPARAM, LPARAM);end; { THello } function THello.WindowProc(hWnd: HWND; Msg: UINT; WPARAM: WPARAM;  LPARAM: LPARAM): LRESULT; stdcall;begin  case (Msg) of    WM_CREATE:    begin      MessageBox(0, 'Hello world!', PChar(someText), MB_OK or MB_USERICON);    end;    WM_CLOSE:    begin      PostQuitMessage(0);      Result := 0;    end;    else    Result := DefWindowProc(hWnd, Msg, WParam, LParam);  end; end; constructor THello.Create;var  WindowClass: WndClass;  hWindow: HWnd;begin  someText := 'Hello';  WindowClass.Style := cs_hRedraw or cs_vRedraw;  WindowClass.lpfnWndProc := @dummy;  WindowClass.cbClsExtra := 0;  WindowClass.cbWndExtra := 0;  WindowClass.hInstance := system.MainInstance;  WindowClass.hIcon := LoadIcon(0, idi_Application);  WindowClass.hCursor := LoadCursor(0, idc_Arrow);  WindowClass.hbrBackground := GetStockObject(WHITE_BRUSH);  WindowClass.lpszMenuName := nil;  WindowClass.lpszClassName := PChar(someText);   if Windows.RegisterClass(WindowClass) = 0 then  begin    halt(1);  end;   hWindow := CreateWindow(PChar(someText), 'Hello world program',    ws_OverlappedWindow, cw_UseDefault, cw_UseDefault, cw_UseDefault,    cw_UseDefault, 0, 0, system.MainInstance, nil);   if hWindow = 0 then  begin    halt(1);  end;  SetWindowlongPtr(hWindow, GWLP_USERDATA, LONG_PTR(self));  ShowWindow(hWindow, CmdShow);  ShowWindow(hWindow, SW_SHOW);  UpdateWindow(hWindow);end; destructor THello.Destroy;begin  inherited Destroy;end; procedure THello.Run;var  AMessage: Msg;begin  while GetMessage(@AMessage, 0, 0, 0) do  begin    TranslateMessage(AMessage);    DispatchMessage(AMessage);  end;  Halt(AMessage.wParam);end; end.  the THello.WindowProc is running, but I can't access the variable sometext inside ---------------------------------------------------------------------- taazz · 2017-12-03 22:10 Quote from: KemBill on December 03, 2017, 10:24:15 pmthe THello.WindowProc is running, but I can't access the variable sometext inside 1) please define can't access, it raises an exception or it doesn't show the string assigned? 2) are you sure that the SetWindowLongPtr has been executed when you first receive the WM_CREATE message? As far as I can see you do not check if the userdata is 0 or not. QuoteBefore returning, CreateWindow sends a WM_CREATE message to the window procedure. from https://msdn.microsoft.com/en- us/library/windows/desktop/ms632679(v=vs.85).aspx in which case you have to change the dummy procedure to something along the lines of. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function dummy(hWnd: HWND; Msg: UINT; WPARAM: WPARAM; LPARAM: LPARAM): LRESULT; stdcall;var  vData: Pointer;begin  if msg = wm_create then begin    vData := LPARAM;    if Assigned(vData) and (vData is THello) then Result := THello(VData).WindowProc(hWnd, Msg, WPARAM, LPARAM)  end else begin    vData := Pointer(GetWindowLongPtr(hWnd, GWLP_USERDATA));    if assigned(vData) then Result := THello(VData).WindowProc(hWnd, Msg, WPARAM, LPARAM)    else Result := -1;????  end;end;  And ofcourse change the call to createwindow to something along the lines of Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ....  hWindow := CreateWindow(PChar(someText), 'Hello world program',    ws_OverlappedWindow, cw_UseDefault, cw_UseDefault, cw_UseDefault,    cw_UseDefault, 0, 0, system.MainInstance, self);....  Make sure you read the complete createwindow documentation before handling the wm_Create message. It is a bit of a special case. ---------------------------------------------------------------------- KemBill · 2017-12-03 22:24 Quote from: taazz on December 03, 2017, 11:10:23 pmMake sure you read the complete createwindow documentation before handling the wm_Create message. It is a bit of a special case. you're right, I made a small test by replacing WM_CREATE with WM_KEYUP and it works as expected ---------------------------------------------------------------------- Cyrax · 2017-12-04 07:08 I think that creating proper trampoline WNDPROC would catch all messages, e.g. the WM_CREATE etc. ---------------------------------------------------------------------- KemBill · 2017-12-04 08:29 here is the link explaining what taazz was saying : https://msdn.microsoft.com/en- us/library/windows/desktop/ff381400(v=vs.85).aspx the only strange thing, is , in C you are allowed to write Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  wc.lpfnWndProc   = DERIVED_TYPE::WindowProc; In pascal due to strong typing, I am not allowed because "function of object" <> "function" ---------------------------------------------------------------------- KemBill · 2017-12-04 09:50 According to MSDN, the "right way" is to handle WM_NCCREATE messages first add "self"  to CreateWindow Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   hWindow := CreateWindow(PChar(someText), 'Hello world program',    ws_OverlappedWindow, cw_UseDefault, cw_UseDefault, cw_UseDefault,    cw_UseDefault, 0, 0, system.MainInstance, self); the dummy proc becomes Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function dummy(hWnd: HWND; Msg: UINT; WPARAM: WPARAM; LPARAM: LPARAM): LRESULT; stdcall;var  hello: THello;  pCreate: PCREATESTRUCT;begin  if msg = WM_NCCREATE then  begin    pCreate := PCREATESTRUCT(LPARAM);    hello :=THello(pCreate^.lpCreateParams);    SetWindowlongPtr(hWnd, GWLP_USERDATA, LONG_PTR(hello));  end  else  begin    hello := THello(LONG_PTR(GetWindowLongPtr(hWnd, GWLP_USERDATA)));  end;  if hello <> nil then    Result := THello(hello).WindowProc(hWnd, Msg, WPARAM, LPARAM)  else    Result := DefWindowProc(hWnd, Msg, WParam, LParam);end;  and after THello.WindowProc can handle wm_create messages Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  function THello.WindowProc(hWnd: HWND; Msg: UINT; WPARAM: WPARAM;  LPARAM: LPARAM): LRESULT; stdcall; begin   case (Msg) of    WM_CREATE:    begin      MessageBox(0, 'Hello world!', PChar(sometext), MB_OK or MB_USERICON);    end;    WM_KEYUP:    begin      MessageBox(0, 'Hello world!', PChar(sometext), MB_OK or MB_USERICON);    end;    WM_CLOSE:    begin      PostQuitMessage(0);      Result := 0;    end;    else    Result := DefWindowProc(hWnd, Msg, WParam, LParam);  end; end;