ab8186ef75
Decisive observation: the taskbar button is already up before FormCreate is entered. Everything I had tried lived inside the form, so all of it ran after the button was drawn — the watcher included, which is why moving it around never helped. StartTrayProxyHider is now exported from UMainForm and called from the .dpr right after Application.Initialize, before CreateForm. It polls every 5 ms and hides our TFMAppClass proxy unconditionally (the button can be up before WS_VISIBLE reads as set, which the previous IsWindowVisible check would have skipped), stopping as soon as the tray startup completes so a user restoring from the tray is never fought. Raw Win32 only — FindWindowEx + ShowWindow, no FMX object touched at that point, which is what made the earlier .dpr attempt crash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
2.3 KiB
ObjectPascal
57 lines
2.3 KiB
ObjectPascal
program PMServer;
|
|
|
|
uses
|
|
System.SysUtils, // FindCmdLineSwitch
|
|
System.StartUpCopy,
|
|
FMX.Forms,
|
|
PM.SingleInstance in 'Source\PM.SingleInstance.pas',
|
|
UMainForm in 'UMainForm.pas' {MainForm},
|
|
PM.JSON in 'Source\PM.JSON.pas',
|
|
PM.Database in 'Source\PM.Database.pas',
|
|
PM.Router in 'Source\PM.Router.pas',
|
|
PM.StaticFiles in 'Source\PM.StaticFiles.pas',
|
|
PM.EmbeddedAssets in 'Source\PM.EmbeddedAssets.pas',
|
|
PM.Crypto in 'Source\PM.Crypto.pas',
|
|
PM.RateLimit in 'Source\PM.RateLimit.pas',
|
|
PM.Audit in 'Source\PM.Audit.pas',
|
|
PM.Session in 'Source\PM.Session.pas',
|
|
PM.HTTPServer in 'Source\PM.HTTPServer.pas',
|
|
PM.Bridge in 'Source\PM.Bridge.pas',
|
|
PM.QuickUnlock in 'Source\PM.QuickUnlock.pas',
|
|
PM.PinUnlock in 'Source\PM.PinUnlock.pas',
|
|
PM.UserPrefs in 'Source\PM.UserPrefs.pas',
|
|
PM.AutoStart in 'Source\PM.AutoStart.pas',
|
|
PM.Favicon in 'Source\PM.Favicon.pas',
|
|
PM.ProcessLockdown in 'Source\PM.ProcessLockdown.pas',
|
|
PM.Handler.Ping in 'Handlers\PM.Handler.Ping.pas',
|
|
PM.Handler.Auth in 'Handlers\PM.Handler.Auth.pas',
|
|
PM.Handler.Folders in 'Handlers\PM.Handler.Folders.pas',
|
|
PM.Handler.Entries in 'Handlers\PM.Handler.Entries.pas',
|
|
PM.Handler.Passkey in 'Handlers\PM.Handler.Passkey.pas',
|
|
PM.Handler.Recovery in 'Handlers\PM.Handler.Recovery.pas',
|
|
PM.Handler.Audit in 'Handlers\PM.Handler.Audit.pas',
|
|
PM.Handler.Settings in 'Handlers\PM.Handler.Settings.pas',
|
|
PM.Handler.Attachments in 'Handlers\PM.Handler.Attachments.pas';
|
|
|
|
{$R *.res}
|
|
{$R assets\assets.res}
|
|
|
|
begin
|
|
// Single-instance: if another PMServer is running, bring it to front
|
|
// (it'll handle WM_PMSHOW on its message-only window) and exit. Avoids
|
|
// two icons in the tray and two HTTP servers fighting for the port.
|
|
if not PM.SingleInstance.AcquireOrSignal then
|
|
Exit;
|
|
|
|
Application.Initialize;
|
|
// --tray ("Start with Windows"): FMX puts its taskbar proxy on screen before
|
|
// FormCreate is ever reached — measured — so the watcher has to start here,
|
|
// before the form is built. It only touches raw Win32 (FindWindowEx +
|
|
// ShowWindow), never an FMX object: an earlier attempt that poked
|
|
// MainForm.Visible/Handle at this point died with an access violation.
|
|
if FindCmdLineSwitch('tray', True) then
|
|
StartTrayProxyHider;
|
|
Application.CreateForm(TMainForm, MainForm);
|
|
Application.Run;
|
|
end.
|