How to use a window message queue in a call?

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

How to use a window message queue in a call?

Daniel Gilbert-5
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
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: How to use a window message queue in a call?

Michael Van Canneyt


On Wed, 27 Jan 2010, Daniel Gilbert wrote:

> 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 works at all. Probably because
the delphi compiler uses a different calling convention.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: How to use a window message queue in a call?

Anthony Walter-3
In reply to this post by Daniel Gilbert-5
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;


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: How to use a window message queue in a call?

Marco van de Voort
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.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: How to use a window message queue in a call?

Anthony Walter-3
>>     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.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: How to use a window message queue in a call?

Daniel Gilbert-5
In reply to this post by Daniel Gilbert-5
Uff,

first, I made a typo. I meant "class" instead of "call".. *g*

Thanks for the hint with the 64bit-thingy. :)

Second, I finally got it to work with some "assembler magic".
(Well, honestly, there is no magic after all. ;) )

=> http://www.lazarusforum.de/viewtopic.php?p=35280#p35280

Thanks for helping... :)
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal