-
Content Count
2803 -
Joined
-
Last visited
-
Days Won
123
Everything posted by Remy Lebeau
-
Since February 2025, the creation of an 'ini' file with Delphi is much slower than in the past.
Remy Lebeau replied to Jean_D's topic in Windows API
I use AVG. You might consider adding an exception to it for your data folder. -
Since February 2025, the creation of an 'ini' file with Delphi is much slower than in the past.
Remy Lebeau replied to Jean_D's topic in Windows API
Must be something specific on your PC. Using Delphi 12.2 Patch 2 on Windows 10 64-bit, when I create an INI file with the specifications you have described, it takes only 150ms with TIniFile. Switch to TMemIniFile and that drops to under 5ms. -
A TTimer HWND shouldn't change, but any VCL UI control can recreate for any number of reasons. Can't rule anything out at this point. So do it manually. Create a temporary button or something that you can trigger at will to log the current HWNDs, then invoke a standby+wakeup, then trigger the log again and compare the results.
-
According to MSDN: TTimer is based on a window-based WM_TIMER message. TTimer has an internal HWND that it receives WM_TIMER messages with. And TMemo is another window-based UI control. Are you ABSOLUTELY SURE that your app's message queue is not generating WM_TIMER messages? Never mind whether they are being DELIVERED to TTimer or TMemo - are they being GENERATED at all? The TApplication[Events].OnMessage event should be able to very that, since it sees all messages coming out of the main thread's message queue. Or even a tool like Spy++ or Winsight. For all we know, your windows got recreated and that is why messages are being lost. Who knows. Did you try verifying that the TTimer's HWND and the TMemo's HWND are still the same before the Standby and after the Wakeup? You are looking at multiple things at one time which are acting on top of each other, and not verifying the behavior at the ROOT of the chain of actions.
-
That is highly unlikely. If that were true, then all applications would be dead upon wakeup. I think you are misdiagnosing the problem. But, as I don't have an S0-enabled computer, I can't help you diagnose that better. Have you tried using the TApplication[Events].OnMessage event, and TApplication.HookMainWindow() and overriding the TForm.WndProc() method, to actually check that window messages are really no longer being processed? In any case, an application can detect support for Modern Standby by checking the AoAc field returned by GetPwrCapabilities(). And register for notification of Modern Standby/Resume using RegisterSuspendResumeNotification().
-
Looking for containskey when processing data
Remy Lebeau replied to JIMSMITH's topic in Network, Cloud and Web
True, though it is inherited from TJSONValue and not specific to TJSONObject, it has a little more overhead as it performs path processing on the input string and type validation on the output value, and it requires the caller to declare a variable to receive the output value whether the caller actually wants it or not. -
Looking for containskey when processing data
Remy Lebeau replied to JIMSMITH's topic in Network, Cloud and Web
TJSONObject does not have a ContainsKey() method, in any version of Delphi. If you want that, you can use a class helper, eg: type TJSONObjectHelper = class helper for TJSONObject function ContainsKey(const AKeyName: String): Boolean; end; function TJSONObjectHelper.ContainsKey(const AKeyName: String): Boolean; begin Result := Self.GetValue(AKeyName) <> nil; end; ... if JSONObject.ContainsKey('keyvalue') then As you can see above, you can use the TJSONObject.GetValue() method, which returns nil if the specified key is not found, eg: if (JSONObject.GetValue('keyvalue') <> nil) then -
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
The coordinates in a mouse event are relative to the client area of the window that is being clicked on. On the other hand, WindowFromPoint() expects screen coordinates instead. Are you accounting for that? But, I don't see how getting the HWND of the preview window is going to help you, since you need the HWND of a particular Form instead. Which goes back to my earlier suggestion to register the preview window's toolbar buttons in such a way that when you receive WM_COMMAND from it you can determine the Form that the event represents. Now you are just delving into OS internals and making this task vastly more complicated on yourself. -
No. Even the feature matrix says it should be enabled for CE. No. You have completely separate major releases, so they should coexist fine.
-
What version of Delphi are you using? Delphi has had a built-in JSON framework for a long time, have you tried it yet? For example: uses ..., System.JSON; var JSON = '...'; var obj = TJSONObject.ParseJSONValue(JSON) as TJSONObject; try for var element in (obj.GetValue('MAILCONFIGS') as TJSONArray) do begin for var pair in (element as TJSONObject) do begin var email := pair.JsonString.Value; var config := pair.JsonValue as TJSONObject; var clientId := config.GetValue('client_id').Value; var appToken := config.GetValue('apptoken').Value; var tempToken := config.GetValue('temptoken').Value; ... end; end; finally obj.Free; end; If your version doesn't have it, there are plenty of 3rd party JSON libraries available.
-
What is the EXACT error message? What is the class type of the exception that is being raised? Is it EFOpenError (error on the local machine) or EIdReplyRFCError (error on the remote server)? I see several possibilities, you are getting a permission error trying to access the AnyDesk.exe file before the upload begins. the user account you are logging into does not have write permissions on the server the remote directory you are uploading to does not have write permissions.
-
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
Then why are you fighting it? Why do you insist on giving each Form window its own Taskbar button? That is not the customary UI experience for Windows apps. It doesn't matter what you set the Owner to. FMX simply iterates the Screen.Forms list to discover which Forms it wants to minimize/restore. It doesn't care about the owner relationships between windows. VCL is a more strategic about those relationships. If you minimize the whole app, it remembers the order of windows, and tries to restore that order when the app is restored. You can't change a window's Owner using SetParent(). Normally, you would specify the Owner when calling the Win32 CreateWindow/Ex() API, and VCL allows you to do that by overriding CreateParams(), but FMX does not. The only way to change a window's Owner after creation is with the Win32 SetWindowLongPtr(GWL_HWNDPARENT) API. It sounds like a lot of extra work and headache for little gain. FMX does not have any equivalent to VCL's TApplication.ShowMainForm property. It forces the MainForm to be initially visible, there is no option to change that. Yes. For instance, in FMX.Forms.pas, TApplication.CreateMainForm() forces FMainForm.Visible=True. Are you referring to the ITaskbarList.AddTab() API? If you are going to go this route, then using ITaskbarList3.RegisterTab() instead may make more sense. Rather than giving each sub Form its own Taskbar button, you could instead attach all of the sub Forms to the Taskbar button of the MainForm. The user will still be able to see all of the sub Forms, but they won't clutter up the Taskbar. I see no such feature in the ITaskbarList... APIs for the main Taskbar buttons. Are you looking at the ITaskbarList3.ThumbBarAddButtons() API? That is meant for embedded a Thumbnail preview with buttons onto a single Taskbar button. I suppose you could have a separate Toolbar item for each sub Form. If you have a subclass on each sub Form then you wouldn't need to resort to this, as each subclass would already know which Wnd it calling it. Unless, are you referring to having only 1 subclass on the "main" Form, and then have the Taskbar toolbar buttons all send messages to that Form's Wnd? I suppose something like that could work. Correct. You would assign a unique ID to each toolbar item, and then the registered Wnd will receive a WM_COMMAND message containing the id of the clicked item. Button IDs cannot hold Window handles, so you will have to use something else. For example, each sub Form's index in the Screen.Forms list. Or, put the sub Forms in your own list, and then use those indexes instead. -
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
That is to be expected. FMX has code in its default WndProc which handles messages like WM_SYSCOMMAND and WM_WINDOWPOSCHANGED to minimize the whole app when the MainForm is minimized, and restore the whole app when the MainForm is restored. If you don't want this behavior, then you will have to subclass the MainForm after all and handle those messages yourself to skip FMX's logic. I think that is a side effect of removing the WS_EX_APPWINDOW style from the hidden ApplicationHWND window, so it can't appear on the Taskbar anymore. Also, TPlatformWin.MinimizeApp() forces the ApplicationHWND window to be visible while hiding all of the Form windows (to ensure the default Taskbar button stays visible while the MainForm is hidden). All the more reason you will have to block the default minimize code if you want different behavior. Frankly, I think you should stop trying to force your own Taskbar behavior, and just let the default behavior do its job normally. -
Documentation links on indyproject.org not working
Remy Lebeau replied to alan finiti's topic in Indy
Thanks, I have updated the file on Indy's repo. -
How to know when TIdHTTPServer threads are done
Remy Lebeau replied to narag's topic in Network, Cloud and Web
Oh, OK. Setting Active=False does stop listening for new connections, but it ALSO immediately closes any existing client connections, too. Then it waits for everything to finish cleaning up before it exits back to your code. If you want existing clients to continue their work uninterrupted, then yes. Try something like this: ShuttingDown := True; IdHTTPServer1.StopListening; Timer1.Enabed := True; ... procedure TMyForm.Timer1Timer(Sender: TObject); begin with IdHTTPServer1.Contexts.LockList do try if Count > 0 then Exit; finally IdHTTPServer1.Contexts.UnlockList; end; Timer1.Enabled := False; IdHTTPServer1.Active := False; Application.Terminate; end; ... procedure TMyForm.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); begin if ShuttingDown then begin AResponseInfo.ResponseNo := 503; AResponse.CustomHeaders.Values['Retry-After'] := '5'; AResponseInfo.CloseConnection := True; Exit; end; // process normally ... if ShuttingDown then AResponseInfo.CloseConnection := True; end; -
Documentation links on indyproject.org not working
Remy Lebeau replied to alan finiti's topic in Indy
You can try emailing it to me at "remy at lebeausoftware dot org". Or upload to DropBox or Google Drive or somewhere and I'll download it. -
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
Nevermind. I must not have been remembering things correctly, because I double-checked and while Form2 was working as expected, Form1 was fighting with FMX. So I simply disabled FMX's default taskbar button and forced a new Taskbar button on Form1, and then removed the subclasses from both windows, and now the focus shifting between the windows works correctly. Main Form unit MultiFormUnit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); {$IFDEF MSWINDOWS} protected procedure CreateHandle; override; {$ENDIF} private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses MultiFormUnit2 {$IFDEF MSWINDOWS} , Winapi.Windows , FMX.Platform.Win {$ENDIF} ; {$R *.fmx} procedure TForm1.Button1Click(Sender: TObject); begin TForm2.Create(Self).Show; end; {$IFDEF MSWINDOWS} procedure TForm1.CreateHandle; var Wnd: HWND; ExStyle: LONG_PTR; begin inherited; Wnd := FormToHWND(Self); ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE); SetWindowLongPtr(Wnd, GWL_EXSTYLE, ExStyle or WS_EX_APPWINDOW); end; {$ENDIF} procedure TForm1.FormCreate(Sender: TObject); {$IFDEF MSWINDOWS} var Wnd: HWND; ExStyle: LONG_PTR; {$ENDIF} begin {$IFDEF MSWINDOWS} Wnd := ApplicationHWND; ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE); SetWindowLongPtr(Wnd, GWL_EXSTYLE, (ExStyle and (not WS_EX_APPWINDOW)) or WS_EX_TOOLWINDOW); {$ENDIF} end; end. Child Form unit MultiFormUnit2; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs; type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); private {$IFDEF MSWINDOWS} protected procedure CreateHandle; override; {$ENDIF} { Private declarations } public { Public declarations } end; var Form2: TForm2; implementation {$R *.fmx} {$IFDEF MSWINDOWS} uses Winapi.Windows, FMX.Platform.Win; procedure TForm2.CreateHandle; var Wnd: HWND; ExStyle: LONG_PTR; begin inherited; Wnd := FormToHWND(Self); ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE); SetWindowLongPtr(Wnd, GWL_EXSTYLE, ExStyle or WS_EX_APPWINDOW); end; {$ENDIF} procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := TCloseAction.caFree; end; end. -
How to know when TIdHTTPServer threads are done
Remy Lebeau replied to narag's topic in Network, Cloud and Web
How are you "updating code" for a running instance? You can StopListening() to let existing clients finish their work, but then you will have to manually monitor the client threads to detect when they have all terminated. Such as by monitoring the TIdHTTPServer.Contexts.Count until it falls to 0. Also, if you have KeepAlives enabled on the server, a client thread will not terminate until the client disconnects after their own KeepAlive timeout has elapsed. TIdHTTPServer does not implement KeepAlive timeouts on its end yet (work in progress), but you can use a ReadTimeout to fake it. Also, with KeepAlives enabled, clients could continue to send new requests as long as the KeepAlive doesn't elapse. If you want to prevent further requests, you would have to set a flag during shutdown and then check that flag in your OnCommand... events so you can close connections gracefully (ie, AResponseInfo.CloseConnection = True). -
How to know when TIdHTTPServer threads are done
Remy Lebeau replied to narag's topic in Network, Cloud and Web
Unless the connection is closed while the server is in the middle of exchanging an HTTP message, that is. Then the client will likely get a transmission error, and have to retry the request that aborted. -
How to know when TIdHTTPServer threads are done
Remy Lebeau replied to narag's topic in Network, Cloud and Web
Setting the Active property to False does a full server shutdown. It blocks the calling thread until all clients are fully disconnected and all threads have fully terminated. Yes. Why? The whole point of setting the Active property to False is to shut down the server completely. Meaning what, exactly? What are you actually trying to accomplish? StopListening() merely closes the listening sockets and their threads. It does not close any clients or stop their threads. Closing a listening socket does not close any clients that connected to it, as those are independent sockets once they have been accepted. StopListening() will stop accepting new clients without shutting down the server completely. But you can't transfer the existing clients to another server, if that is your goal. -
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
Then you are doing something different than me. When I run my test app, it does not behave the way you describe. That's fine, since the subclass proc is registered per-window, and uses the window it is called on. That is not what happens for me. Form1 becomes active. You have explained yourself just fine. That is not what happens for me. That is what happens for me. -
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
That does not happen in my test project. Here is the full code I used: Main Form: unit MultiFormUnit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); {$IFDEF MSWINDOWS} protected procedure CreateHandle; override; {$ENDIF} private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses MultiFormUnit2 {$IFDEF MSWINDOWS} , Winapi.Windows , Winapi.Messages , Winapi.CommCtrl , FMX.Platform.Win {$ENDIF} ; {$R *.fmx} procedure TForm1.Button1Click(Sender: TObject); begin TForm2.Create(Self).Show; end; {$IFDEF MSWINDOWS} function SubclassProc(Wnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; begin case uMsg of WM_NCDESTROY: begin RemoveWindowSubclass(Wnd, SubclassProc, uIdSubclass); end; WM_ACTIVATE: begin if wParam in [WA_ACTIVE, WA_CLICKACTIVE] then begin SetFocus(Wnd); //SetForeGroundWindow(Wnd); //BringWindowToTop(Wnd); end; end; end; Result := DefSubclassProc(Wnd, uMsg, wParam, lParam); end; procedure TForm1.CreateHandle; var Wnd: HWND; ExStyle: LONG_PTR; begin inherited; Wnd := FormToHWND(Self); // a Taskbar button is already handled for the MainForm by FMX, don't force it here... //ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE); //SetWindowLong(Wnd, GWL_EXSTYLE, ExStyle or WS_EX_APPWINDOW); SetWindowSubclass(Wnd, SubclassProc, 1, DWORD_PTR(Self)); end; {$ENDIF} end. Child Form: unit MultiFormUnit2; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs; type TForm2 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); private {$IFDEF MSWINDOWS} protected procedure CreateHandle; override; {$ENDIF} { Private declarations } public { Public declarations } end; var Form2: TForm2; implementation {$R *.fmx} {$IFDEF MSWINDOWS} uses Winapi.Windows, Winapi.Messages, Winapi.CommCtrl, FMX.Platform.Win; function SubclassProc(Wnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall; begin case uMsg of WM_NCDESTROY: begin RemoveWindowSubclass(Wnd, SubclassProc, uIdSubclass); end; WM_ACTIVATE: begin if wParam in [WA_ACTIVE, WA_CLICKACTIVE] then begin SetFocus(Wnd); //SetForeGroundWindow(Wnd); //BringWindowToTop(Wnd); end; end; end; Result := DefSubclassProc(Wnd, uMsg, wParam, lParam); end; procedure TForm2.CreateHandle; var Wnd: HWND; ExStyle: LONG_PTR; begin inherited; Wnd := FormToHWND(Self); ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE); SetWindowLong(Wnd, GWL_EXSTYLE, ExStyle or WS_EX_APPWINDOW); SetWindowSubclass(Wnd, SubclassProc, 1, DWORD_PTR(Self)); end; {$ENDIF} procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := TCloseAction.caFree; end; end. Then you must be doing something wrong in how you setup your subclassing. A subclass is per-window. The only way the child form subclass would be called for the main form is if you registered the child form subclass for the main form window by mistake. That is not how it works. The MainFormOnTaskbar property controls whether the Taskbar button belongs to the hidden TApplication window or the TApplication.MainForm window. If TApplication owns the button, then it delegates various actions to the MainForm. That is not necessary. -
FMX with multi taskbar buttons, switch forms by clicking taskbar buttons and bring the clicked form to front?
Remy Lebeau replied to wqmeng's topic in FMX
I assure you that it does. I tested the code before I posted it. That will not work in this situation, as HandleMessage() can see only messages that are posted to the main message queue, it will not see messages that are sent directly to the Form window. FMX does not dispatch non-queued messages in any way that the app's code can override. Which is why I suggest using a manual window subclass instead. Correct, because those messages do not go through the message queue. WM_KEY... messages go through the message queue. FMX does handle a few non-queued messages, such as WM_ACTIVATE. But clearly not in a way that behaves as you want. SetWindowSubclass() does not use GetLastError() for reporting errors. The only reason I can think of for SetWindowSubclass() to fail is if you are not using ComCtrl32.dll v6, or it has not been loaded yet. Does your project have an app manifest that enables ComCtl32.dll v6? It should be enabled by default. Also, you may need to call Winapi.CommCtrl.InitCommonControlsEx() at app startup, as the Winapi.CommCtrl unit loads SetWindowSubclass() dynamically and only if ComCtrl32.dll has already already loaded by a previous Winapi.CommCtrl call (specifically, it is loaded only by InitCommonControlsEx(), TaskDialogIndirect(), or TaskDialog()). -
Documentation links on indyproject.org not working
Remy Lebeau replied to alan finiti's topic in Indy
I didn't create the zip file, so I can't help with that error. If someone wants to fix the zip, I'll replace it. The only link that is not working for me right now is the 10.1.5 doc archive. I have no control over other people's sites. -
Documentation links on indyproject.org not working
Remy Lebeau replied to alan finiti's topic in Indy
That link work fine for me.