Skip to content

Instantly share code, notes, and snippets.

@freeonterminate
Last active November 30, 2017 03:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save freeonterminate/fa73eecb474726a08cfc6f3c951cbbc8 to your computer and use it in GitHub Desktop.
Save freeonterminate/fa73eecb474726a08cfc6f3c951cbbc8 to your computer and use it in GitHub Desktop.
Fix bug RSP-17322
unit FixTaskbarIconClick;
(*
* Fix RSP-17322
*
* USAGE:
* Just add FixTaskbarIconClick to the uses section.
*
* RSP-17322:
* Window minimize-restore via taskbar icon click is broken in
* all Windows flavours
* https://quality.embarcadero.com/browse/RSP-17322
*
* CONTACT:
* freeonterminate@gmail.com
* http://twitter.com/pik
*
* LICENSE:
* Copyright (c) 2017 HOSOKAWA Jun
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* ncluding commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*)
{$IFNDEF MSWINDOWS}
{$WARNINGS OFF}
interface
implementation
end.
{$ENDIF}
interface
implementation
uses
Winapi.Windows,
Winapi.Messages,
System.Classes,
System.Generics.Collections,
System.Rtti,
FMX.Types,
FMX.Forms,
FMX.Platform.Win;
var
GHook: HHOOK;
GSubclassed: TDictionary<hWnd, Pointer>;
function WndProc(
hWnd: HWND;
uMsg: DWORD;
wParam: WPARAM;
lParam: LPARAM): LRESULT; stdcall;
var
Form: TCommonCustomForm;
Handle: TWinWindowHandle;
OrgWndProc: Pointer;
RttiType: TRttiType;
RttiField: TRttiField;
OK: Boolean;
procedure CallOrg;
begin
Result := CallWindowProc(OrgWndProc, hWnd, uMsg, wParam, lParam);
end;
begin
OrgWndProc := nil;
if (not GSubclassed.TryGetValue(hWnd, OrgWndProc)) then
Exit(DefWindowProc(hWnd, uMsg, wParam, lParam));
case uMsg of
WM_SHOWWINDOW:
begin
CallOrg;
if (BOOL(wParam)) and (FormToHWND(Screen.ActiveForm) = hWnd) then
TThread.ForceQueue(TThread.Current, procedure begin SetFocus(hWnd) end);
end;
WM_ACTIVATE:
begin
Result := 0;
Form := FindWindow(hWnd);
if
(Form <> nil) and
not (
(TFmxFormState.Recreating in Form.FormState)
or (Form.FormStyle = TFormStyle.Popup)
)
then
begin
OK := True;
RttiType := SharedContext.GetType(TWinWindowHandle);
if (RttiType <> nil) then
begin
RttiField := RttiType.GetField('FDisableDeactivate');
if (RttiField <> nil) then
begin
Handle := WindowHandleToPlatform(Form.Handle);
if (RttiField.GetValue(Handle).AsBoolean) then
OK := False;
end;
end;
if (OK) then
begin
if LoWord(wParam) = WA_INACTIVE then
begin
if Form.FormStyle = TFormStyle.Popup then
Screen.PrepareClosePopups(Form)
else
Screen.PrepareClosePopups(nil);
Screen.ClosePopupForms;
end
else
begin
if HiWord(wParam) = 0 then
Form.Activate;
end;
end;
end;
end;
else
CallOrg;
end;
end;
function HookProc(
Code: Integer;
wParam: WPARAM;
lParam: LPARAM): LRESULT; stdcall;
var
OrgWndProc: Pointer;
begin
if (Code > -1) then
with PCWPSTRUCT(lParam)^ do
case message of
WM_ACTIVATE:
begin
if
(FindWindow(hWnd) <> nil) and (not GSubclassed.ContainsKey(hWnd))
then
begin
OrgWndProc :=
Pointer(SetWindowLong(hWnd, GWL_WNDPROC, Integer(@WndProc)));
if (OrgWndProc <> nil) then
GSubclassed.Add(hWnd, OrgWndProc);
end;
end;
WM_CLOSE:
begin
if (hWnd = ApplicationHWND) then
TThread.ForceQueue(
TThread.Current,
procedure
begin
if (Application.Terminated) then
DestroyWindow(hWnd);
end
);
end;
end;
Result := CallNextHookEx(GHook, Code, wParam, lParam);
end;
initialization
begin
GSubclassed := TDictionary<hWnd, Pointer>.Create;
GHook := SetWindowsHookEx(WH_CALLWNDPROC, @HookProc, 0, GetCurrentThreadID);
end;
finalization
begin
UnhookWindowsHookEx(GHook);
GSubclassed.DisposeOf;
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment