Ian Branch 128 Posted July 19, 2019 Hi Team, I want to give the User of an App the ability to click on a button or a menu selection that will cause the app to close and restart. Can this be done? Thoughts/suggestions appreciated. Regards & TIA, Ian Share this post Link to post
David Heffernan 2353 Posted July 19, 2019 Easy 1. Create the new process passing in the pid of the previous process. 2. Close the previous process. 3. When the new process starts, have it wait until the previous process has terminated before it shows UI. Share this post Link to post
Ian Branch 128 Posted July 19, 2019 Hi David, "Easy" Says he who knows how to do it. ;-) I have no idea how to do what you described. Ian 1 Share this post Link to post
David Heffernan 2353 Posted July 19, 2019 Which part don't you know how to do? On Windows at least it's a call to CreateProcess, then close the app, and then a wait function call. Do you know how to close your app? If so all that is left is CreateProcess and a wait call. Share this post Link to post
limelect 48 Posted July 19, 2019 @David Heffernan sorry that not an answer when a guy needs help coding. Give him a piece of code, this is his need. Share this post Link to post
Dalija Prasnikar 1404 Posted July 19, 2019 1 hour ago, Ian Branch said: Hi David, "Easy" Says he who knows how to do it. 😉 I have no idea how to do what you described. 1. Google create process 2 Google process pid 3. Google close process 4. Google wait for process David gave all necessary steps... you (or anyone) just need to go through that list one by one finding out how to do each particular thing if you already don't know how to do that. Share this post Link to post
Dalija Prasnikar 1404 Posted July 19, 2019 22 minutes ago, limelect said: @David Heffernan sorry that not an answer when a guy needs help coding. Give him a piece of code, this is his need. Knowing what needs to be done is quite different than having that particular piece of code at hand for sharing. Share this post Link to post
Sherlock 663 Posted July 19, 2019 @Dalija Prasnikar I would always add Delphi to the search query. But other than that, Ian should now be good to go. 1 Share this post Link to post
Dalija Prasnikar 1404 Posted July 19, 2019 6 minutes ago, Sherlock said: @Dalija Prasnikar I would always add Delphi to the search query. But other than that, Ian should now be good to go. Indeed. I just always like to read MS documentation first. So those would be my first steps. After I collect all necessary API calls, I would search Delphi RTL/VCL source to see if anything is already implemented somewhere... and yes, then Google again for specific Delphi implementation if needed (I can generally manage using Windows API calls without additional searching, but that knowledge depends on how often one has to interact with Windows API directly - Delphi does good job at hiding and wrapping those parts so many developers don't have the need to do low level interactions) 1 Share this post Link to post
Ian Branch 128 Posted July 19, 2019 Hi All, Thank you all for your pointers and consideration. I have now amassed the following routines which I think will get me there with some massaging. ExecuteAndWait. TerminateProcessByID. GetPIDByProgramName. ExecuteProcess. I will let you know how I go, or not. ;-) Regards & Tks again, Ian 1 Share this post Link to post
Remy Lebeau 1436 Posted July 19, 2019 (edited) 13 hours ago, Ian Branch said: I have now amassed the following routines which I think will get me there with some massaging. ExecuteAndWait. TerminateProcessByID. You definitely don't want to use those kind of functions in this situation. Quote GetPIDByProgramName. You don't need that. A process knows its own ID, you can query it directly. You need something like this: uses ..., Windows; function RestartApp: Boolean; var si: STARTUPINFO; pi: PROCESS_INFORMATION; CmdLine: string; begin CmdLine := Format('"%s" /pid:%d', [ParamStr(0), GetCurrentProcessID()]); ZeroMemory(@si, sizeof(si)); GetStartupInfo(@si); Result := CreateProcess(nil, PChar(CmdLine), nil, nil, False, 0, nil, nil, si, pi); if Result then begin CloseHandle(pi.hThread); CloseHandle(pi.hProcess); Application.Terminate; end; end; Then in your app's startup code, such as in your main DPR file, you can do this before initializing your UI or anything else: uses ..., Windows; var pid: string; h: THandle; begin if FindCmdLineSwitch('pid', pid) then begin h := OpenProcess(SYNCHRONIZE, FALSE, StrToInt(pid)); if h <> 0 then begin WaitForSingleObject(h, INFINITE); CloseHandle(h); end; end; ... continue starting up normally ... end; Edited July 19, 2019 by Remy Lebeau 4 Share this post Link to post
Ian Branch 128 Posted July 19, 2019 Hi Remy, Thanks for that. I will give it a go. While trying to get the other routines I found going, I discovered the need to change Winapi.Windows to just Windows in the Uses area. I note your indication of just Windows in the uses area. What's the difference? It would seem they both can't be in the uses. Regards & Tks again, Ian Share this post Link to post
Ian Branch 128 Posted July 19, 2019 Tks Remy, Works exactly as desired/needed. I had to change.. GetStartupInfo(@si); GetStartupInfo(si); No biggie. :-) Regards & Tks again. And to the others for your interest/support. Ian Share this post Link to post
Remy Lebeau 1436 Posted July 23, 2019 On 7/19/2019 at 3:52 PM, Ian Branch said: While trying to get the other routines I found going, I discovered the need to change Winapi.Windows to just Windows in the Uses area. That would only be needed if you are using Delphi Xe or earlier. In XE2 and later, you should use "Winapi.Windows". Though, you can omit the "Winapi" prefix if you have "Winapi" included in your project's "Unit scope names" list. On 7/19/2019 at 3:52 PM, Ian Branch said: I note your indication of just Windows in the uses area. Because I wasn't targeting any specific Delphi version. The code I suggested should work in older versions, too. Well, XE and later anyway, since 2010 and earlier did not have a version of FindCmdLineSwitch() that returns a string value, but that is not hard to write a manual replacement for if needed. On 7/19/2019 at 3:52 PM, Ian Branch said: What's the difference? It would seem they both can't be in the uses. "Windows" and "Winapi.Windows" are the same unit, so you can't "use" it twice in the same unit. The latter simply has a "Unit scope name" applied to it in XE2 and later. Share this post Link to post
Remy Lebeau 1436 Posted July 23, 2019 On 7/19/2019 at 4:22 PM, Ian Branch said: I had to change.. GetStartupInfo(@si); GetStartupInfo(si); That is what I get for not checking Delphi's pascal declarations before posting code examples. 1 Share this post Link to post
Ian Branch 128 Posted July 23, 2019 Hi Remy, Thank you for the clarifications and the assist. Much appreciated. Regards, Ian Share this post Link to post
Tommi Prami 131 Posted July 24, 2019 If this works well would be nice if final code would be published in Github etc. I think many would need it and if there would be ready to run code, it would help community. -Tee- Share this post Link to post
Ian Branch 128 Posted July 24, 2019 Hi Tee, It does work well and I have integrated it into 3 Apps. I haven't checked it for memory leaks or anything under the hood. It does what I needed. As for publishing to GitHub, I'm afraid that's not in my knowledge base. :-( Regards, Ian 1 Share this post Link to post
Sherlock 663 Posted July 24, 2019 @Ian Branch Just drop it here https://en.delphipraxis.net/forum/16-i-made-this/ and maybe reference this thread and add some words of clarification. 1 Share this post Link to post
Tommi Prami 131 Posted July 24, 2019 3 minutes ago, Sherlock said: @Ian Branch Just drop it here https://en.delphipraxis.net/forum/16-i-made-this/ and maybe reference this thread and add some words of clarification. That works also. -Tee- Share this post Link to post
Lars Fosdal 1793 Posted July 31, 2019 Some old code of mine. Awaiting ridicule for the use of ShellExecute 😛 FDCRelauncherhttps://pastebin.com/YCiqiNAq CustomDebugOuthttps://pastebin.com/GM7DE18L Share this post Link to post
David Heffernan 2353 Posted July 31, 2019 (edited) 18 minutes ago, Lars Fosdal said: Awaiting ridicule for the use of ShellExecute Why do you think ShellExecute throws exceptions? It doesn't. If you want proper error handling use ShellExecuteEx, and check the return value. Even ShellExecuteEx would be wrong here though. Use CreateProcess. As for services, why use cmd.exe to run net.exe? Why not run it directly? Of course, the API is the right way to start a service. Edited July 31, 2019 by David Heffernan Share this post Link to post
Lars Fosdal 1793 Posted July 31, 2019 @David Heffernan I found restarting a service from itself to be troublesome since you still are in the context of the running service. Issuing a net start just at the time that you exit the service works well. The exception handling is probably a cargo cult remnant. I'd rewrite for CreateProcess for the application, but it works, so I won't fix it. Share this post Link to post
David Heffernan 2353 Posted July 31, 2019 (edited) 4 minutes ago, Lars Fosdal said: but it works, so I won't fix it. Except that it doesn't work. Doesn't handle errors at all. Also, it's fine that you don't want to disturb your code. But if you are going to offer up code as an example, it should be exemplary. Edited July 31, 2019 by David Heffernan Share this post Link to post
Lars Fosdal 1793 Posted July 31, 2019 Academically you may be correct, but empirically it simply works. I have several hundred installations that have worked for many years and keep on working, and zero complaints that it ever failed. The apps/services check the file version against a repository and if it finds a change, - deletes any *.old.* copies that it finds - copies the new file to a .new temp file, - renames itself to *.old.<handle> - renames the new temp file to the ordinary name - Calls Restart...OnExit and exits. Voila: App / Service is running the new version. Share this post Link to post