2

I'm trying to do a very simple task... Detect when my form has been minimized. But it seems Firemonkey has absolutely no way of handling this. I've tried to use AllocateHWnd to intercept WM_SYSCOMMAND messages, but all I get is WM_ACTIVATEAPP messages and nothing else.

CreateForm:

AllocateHWnd(WndProcHandler);

WndProcHandler:

procedure TfrmMain.WndProcHandler(var Message: TMessage);
begin
  if Message.msg = WM_SYSCOMMAND then
    OutputDebugStringA('got command');
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Sierra C
  • 305
  • 1
  • 11
  • Messages aren't sent to that window that you allocated. They are sent to the window behind the form. So far as I can tell, you are going to need to hook that window's window procedure. I've re-tagged the question since you are clearly only targeting Windows. – David Heffernan Jan 26 '16 at 13:59
  • @DavidHeffernan I'm able to get the messages if I do `SetWindowLongPtr(WindowHandleToPlatform(Handle).Wnd, GWL_WNDPROC, IntPtr(MakeObjectInstance(WndProcHandler)));` but then the form doesn't update because the original WndProc doesn't get called... Not sure what to do – Sierra C Jan 26 '16 at 14:30
  • 1
    What to do is to hook the window procedure. Use a `WH_CALLWNDPROCRET` hook. – David Heffernan Jan 26 '16 at 14:36
  • I belive that this was already answered here: http://stackoverflow.com/questions/20195547/detect-all-situations-where-form-is-minimized – Vepir Jan 26 '16 at 14:38
  • @DavidHeffernan Tried `SetWindowsHookEx(WH_CALLWNDPROCRET, @HookProc, ApplicationHwnd,0);` with the form Hwnd and Application Hwnd, HookProc never gets called... I'm working on a solution involving `WM_WINDOWPOSCHANGING`. @Matta that is for VCL – Sierra C Jan 26 '16 at 15:23
  • Why are you using `ApplicationHWnd`? Don't you want to hook the window procedure for your form? Anyway, window hooking does work. But you do have to pass the right parameters! Why did you pass a window handle to a parameter expecting a module handle? This isn't the easiest of subjects to work with, but trying stuff without a solid understanding, and without reading the documentation carefully, is a recipe for failure. – David Heffernan Jan 26 '16 at 15:32
  • @DavidHeffernan I understand your intentions of being as vague as possible in every answer. But I got it working by using `GetWindowLong` and `CallWindowProc` to call the original proc. – Sierra C Jan 26 '16 at 16:11
  • That will work unless the window gets re-created. Which can happen. A hook would be better, but has a bit of a learning curve. I'm not trying to be vague. I just don't have the time to write a full answer. I don't much appreciate your insult. – David Heffernan Jan 26 '16 at 16:18
  • @DavidHeffernan I didn't intend it as such. You're right a hook would be better, and I did get it working eventually, but stuck on converting the `TCWPRetStruct` to a `TWMWindowPosChanging` for `WM_WINDOWPOSCHANGING`. All this low-level typecasting stuff is difficult to Google research. – Sierra C Jan 26 '16 at 16:36
  • Well, I'll leave you to it, considering the conversation we have had so far – David Heffernan Jan 26 '16 at 16:39

1 Answers1

1

Got it working with the following code. Looks for the WM_SIZE command and SIZE_MINIMIZED parameter to detect all minimising events.

uses
  Winapi.Windows, Winapi.Messages;

var
  WndProcHook: THandle;

function WndProc(Code: integer; WParam, LParam: LongInt): LRESULT; stdcall;
var
  msg: TCWPRetStruct;
begin;
  if (Code >= HC_ACTION) and (LParam > 0) then begin
    msg := PCWPRetStruct(LParam)^;
    if (msg.Message = WM_SIZE) and (msg.WParam = SIZE_MINIMIZED) then begin
      // Application has been minimized
      // Check msg.wnd = WindowHandleToPlatform(Form1.Handle).wnd if necessary
    end;
  end;
  result := CallNextHookEx(WndProcHook, Code, WParam, LParam)
end;

initialization
  WndProcHook := SetWindowsHookEx(WH_CALLWNDPROCRET, @WndProc, 0, GetCurrentThreadId);

finalization
  UnhookWindowsHookEx(WndProcHook);
Sierra C
  • 305
  • 1
  • 11