-2

In Delphi, is it possible to detect when the user clicks on Windows' Start button (the button on the bottom left that brings up the menu)?

I try to create my own Start menu, so when the Start button is clicked, it will show my menu rather then Windows' menu.

My concept is my app will run automatically in the systray when Windows starts, and detect when the user clicks on the Start button then shown my menu.

I see a similar question, but in C#: How to detect when the Windows start menu / start screen opens?, but how to do that in Delphi?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
NettixCode
  • 25
  • 1
  • 4
  • 2
    The solution provided in your [linked question](https://stackoverflow.com/questions/22085746/) is written in C++, not C#. C++ is much easier to translate to Delphi than C# is. The solution provided is one of the most complicated codes I've seen in awhile, but it ultimately just comes down to simply creating an instance of Windows' `CLSID_AppVisibility` COM object, getting its `IAppVisibility` interface, and calling its `IsLauncherVisible()` method in a loop for the lifetime of your app. That is very easy to do in Delphi. The rest of the code is just complex fluff that you can ignore... – Remy Lebeau May 24 '23 at 17:11
  • 1
    ... But, that approach just tells you when the native Start menu is already visible. *Replacing* the native menu with your own menu is a complete different task, and that solution is not the way to approach it, not even close. The only way to do that is to actually hook the Start button itself and dismiss clicks from being sent to the button's default handler, but how you do that is going to differ wildly from one Windows version to another, since Microsoft likes to re-engineer the Taskbar in major releases. – Remy Lebeau May 24 '23 at 17:12
  • 1
    @RemyLebeau you could also just create your own window on top of the Start button so it would get the click. Wouldn't help if someone opened it via the keyboard though. – Mark Ransom May 24 '23 at 17:31
  • 1
    @MarkRansom You could do that, though just determining where the Start button is located on-screen can be tricky since the Taskbar can be moved around, so the Start button could be at any corner of the screen. – Remy Lebeau May 24 '23 at 17:36
  • @RemyLebeau I never said it would be easy. Maybe if there's something unique about the button window you can do a search for it and get the coordinates? – Mark Ransom May 24 '23 at 17:40
  • i already have solution to show my menu at start position even user use `bottom` , `top` , `right` or `left` taskbar position .. also found a way to disable default windows menu .. even i click start button it will not show windows menu .. that why i need to detect when start button is clicked then i can show my menu.. – NettixCode May 24 '23 at 18:23
  • If you want to edit Windows start menu. You could try to [Customize and export Start layout](https://learn.microsoft.com/en-us/windows/configuration//customize-and-export-start-layout),and then use [Import-StartLayout](https://learn.microsoft.com/en-us/powershell/module/startlayout/import-startlayout?view=windowsserver2022-ps) to import the layout of the Start into a mounted Windows image. – Jeaninez - MSFT May 25 '23 at 02:09
  • 1
    This is failing basic groundwork in logical reasoning: [What if two programs did this?](https://devblogs.microsoft.com/oldnewthing/20050607-00/?p=35413) – IInspectable May 25 '23 at 11:08
  • "You now have two programs both of which want to be first/last. But you can’t have two first or two last things. One of them must lose." .. that wouldnt be like that .. i was disabled default windows start menu ,, so when i click on orb button or press windows it wont show default start menu .. now what i need is how to hook the click event trigger on start button and show my custom start menu . – NettixCode May 25 '23 at 15:50
  • *"and show my custom start menu"* - What if two programs want to do this? – IInspectable May 25 '23 at 16:02
  • what do you mean with two program ? like i said before .. program which response with clicked start button is default start menu and my custom start menu .. i was disable default start menu then only 1 will show .. why i need to put another program to show when clicked start button .. – NettixCode May 25 '23 at 16:37

1 Answers1

0

found solution use mousehook .. 1st get the start button size and position

_handle := FindWindow('Shell_TrayWnd', nil);
_Start.Handle := FindWindowEx(_handle, 0, 'Start', nil);
GetWindowRect(_Start.Handle, _Start.Rect);

then use mousehook to check mouse pointer clicked on start button or not :

if (ms.X >= Start.Rect.Left)
and (ms.X <= Start.Rect.Right)
and (ms.Y >= Start.Rect.Top)
and (ms.Y <= Start.Rect.Bottom) then dowhatiwant ......

no matter where is TASKBAR POSITION in left bottom right or top it will always found the start button position ..

UPDATE : i found another solutions from github .. thanks to Remy for the clue answer and vhanla for the powerfull taskbar component which has a code to implement remy answer,, i share it here if someone need it .. :

type
// *********************************************************************//
// Interface: IAppVisibilityEvents
// Flags:     (0)
// GUID:      {6584CE6B-7D82-49C2-89C9-C6BC02BA8C38}
// *********************************************************************//
  IAppVisibilityEvents = interface(IUnknown)
    ['{6584CE6B-7D82-49C2-89C9-C6BC02BA8C38}']
    function AppVisibilityOnMonitorChanged(hMonitor: HMONITOR;
              previousMode: MONITOR_APP_VISIBILITY;
              currentMode: MONITOR_APP_VISIBILITY):HRESULT; stdcall;
    function LauncherVisibilityChange(currentVisibleState: BOOL): HRESULT; stdcall;
  end;
// *********************************************************************//
// Interface: IAppVisibility
// Flags:     (0)
// GUID:      {2246EA2D-CAEA-4444-A3C4-6DE827E44313}
// *********************************************************************//
  IAppVisibility = interface(IUnknown)
    ['{2246EA2D-CAEA-4444-A3C4-6DE827E44313}']
    function GetAppVisibilityOnMonitor(monitor: HMONITOR; out pMode: MONITOR_APP_VISIBILITY): HRESULT; stdcall;
    function IsLauncherVisible(out pfVisible: BOOL): HRESULT; stdcall;
    function Advise(pCallBack: IAppVisibilityEvents; out pdwCookie: DWORD): HRESULT; stdcall;
    function Unadvise(dwCookie: DWORD): HRESULT; stdcall;
  end;



function IsStartMenuVisible: Boolean;
var
  acc: IAppVisibility;
  res: HRESULT;
  isLauncherVisible: BOOL;
begin
  Result := False;
  // Initialization of COM is required to use the AppVisibility (CLSID_AppVisibility) object
  res := CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  if Succeeded(res) then
  begin
    // Create the App Visibility component
    res := CoCreateInstance(CLSID_AppVisibility, nil, CLSCTX_ALL, IID_AppVisibility, acc);
    if Succeeded(res) then
    begin
      res := acc.IsLauncherVisible(isLauncherVisible);
      if Succeeded(res) then
        Result := Boolean(isLauncherVisible);
    end;

  end;
  CoUninitialize;
end;

and call the function to detect start menu is opened or not .

NettixCode
  • 25
  • 1
  • 4