Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2010-01

How to use a window message queue in a call?

6 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Daniel Gilbert

Hi there,
this is my first posting to the fpc-mailinglist, so please don't slap me if I do anything wrong. :)

I'm currently re-writing a program I've written in Delphi some months ago. Due to the now missing free version, I've decided to switch over to Freepascal. But now, I'm somehow stuck.

The application is Windows-only, and I'm using WindowsAPI-calls to create the main window. But I would like to program in an object-oriented way, so I decided to create a class, TstMainWindow.

To get Messages from your Window, you need a Callback. Unfortunately, a pointer to a method is a pointer to a function.

So i tried this workaround, I've posted it at the german lazarus forum:

http://www.lazarusforum.de/viewtopic.php?f=15&t=3438&start=0

( You could use Google Translate, but I guess the code should be pretty obvious. )

I reused the code from this Delphi-PRAXiS.net posting: http://www.delphipraxis.net/topic72146.html

( In case you would like to take a look at the whole project, please feel free to download this archive: http://smalltune.net/smalltune_fpc.zip )

When I run the code in the IDE, I get an error message called "EXTERNAL: SIGSEV" and an empty assembler window pops up, with adresses starting at 00000000.
If I run the program "normally", it closes immediately and I get no error message or anything else.
So I've tried to debug the code, but the debugger crashes after the first run in the TstMainWindow.FWndProc(...) function.

Does anyone have an idea, how i can get this to work?

Greetings,
Daniel

Reply by email

Michael Van Canneyt
to Daniel Gilbert
Daniel Gilbert wrote 18 lines
Hi there, this is my first posting to the fpc-mailinglist, so please don't slap me if I do anything wrong. :) I'm currently re-writing a program I've written in Delphi some months ago. Due to the now missing free version, I've decided to switch over to Freepascal. But now, I'm somehow stuck. The application is Windows-only, and I'm using WindowsAPI-calls to create the main window. But I would like to program in an object-oriented way, so I decided to create a class, TstMainWindow. To get Messages from your Window, you need a Callback. Unfortunately, a pointer to a method is a pointer to a function. So i tried this workaround, I've posted it at the german lazarus forum: http://www.lazarusforum.de/viewtopic.php?f=15&t=3438&start=0

You cannot use a method as a window message handler.

You must use a plain function for this. You can see in the lazarus file win32callback.inc, function CallDefaultWindowProc or WindowProc how to do this and how to transfer the code to your objects.

I'm surprised the code at Delphipraxis because
the delphi compiler uses a different calling convention.

Michael.

Reply by email

Anthony Walter
to Daniel Gilbert: this is my first posting to the fpc-mailinglist, so please don't slap me if I do anything…

As Michael Van Canneyt says, you cannot use a method as a window message handler. This assumed implicit Self variable will most likely break the return pointer on the stack.

Here is my code for a user defined window class. Note, window messages are processed through TObject.Dispatch

threadvar
  CreationWindow: TBaseWindow;
function BaseWindowProc(Wnd: HWND; uMsg: Cardinal; wParam: LongInt; lParam:
LongInt): Integer; stdcall;
var
  BaseWindow: TBaseWindow;
  Msg: TMessage;
begin
  if CreationWindow  nil then
  begin
    BaseWindow := CreationWindow;
    BaseWindow.FHandle := Wnd;
    SetWindowLong(Wnd, GWL_USERDATA, Integer(BaseWindow));
    CreationWindow := nil;
  end
  else
    BaseWindow := TBaseWindow(GetWindowLong(Wnd, GWL_USERDATA));
  Result := -1;
  if BaseWindow  nil then
  try
    Msg.Msg := uMsg;
    Msg.wParam := wParam;
    Msg.lParam := lParam;
    Msg.Result := -1;
        BaseWindow.Dispatch(Msg);
    Result := Msg.Result;
    if Msg.Msg = WM_DESTROY then
      BaseWindow.FHandle := 0;
  except
    on E: Exception do
      MessageBox(0, PChar(E.ClassName + ': ' + E.Message), 'Error',
        MB_ICONERROR or MB_OK or MB_TASKMODAL);
  end
  else
    Result := DefWindowProc(Wnd, uMsg, wParam, lParam);
end;
constructor TBaseWindow.Create(Parent: HWND = 0; Style: Cardinal = 0;
ExStyle: Cardinal = 0);
var
  WindowClass: string;
  WindowName: string;
  Info: TCreateInfo;
begin
  inherited Create;
  WindowClass := ClassName + IntToStr(HInstance);
    FillChar(Info, SizeOf(Info), #0);
  Info.Parent := Parent;
  Info.Style := Style;
  Info.ExStyle := ExStyle;
  CreateInfo(Info);
  if not GetClassInfo(SysInit.HInstance, PChar(WindowClass), Info.WndClass)
then
  begin
    with Info.WndClass do
    begin
      lpfnWndProc := @BaseWindowProc;
      lpszClassName := PChar(WindowClass);
      hInstance := SysInit.HInstance;
      Windows.RegisterClass(Info.WndClass);
    end;
  end;
  CreationWindow := Self;
  try
      with Info do
        CreateWindowEx(ExStyle, PChar(WindowClass), PChar(WindowName),
Style,
          X, Y, W, H, Parent, 0, 0, nil);
  except
    CreationWindow := nil;
  end;
  if FHandle = 0 then
    RaiseLastWin32Error;
end;

Reply by email

Marco van de Voort
to Anthony Walter

In our previous episode, Anthony Walter said:

BaseWindow := CreationWindow; BaseWindow.FHandle := Wnd; SetWindowLong(Wnd, GWL_USERDATA, Integer(BaseWindow));

Not 64-bits safe. An integer is not a long. Ptruint probably.

Reply by email

Anthony Walter
to Marco van de Voort
>     SetWindowLong(Wnd, GWL_USERDATA, Integer(BaseWindow)); Not 64-bits safe. An integer is not a long.  Ptruint probably.

Ah well, there is a new API to fix this in 64 bit Windows. Use SetWindowLongPtr/GetWindowLongPtr instead.

Reply by email