Ian Branch 127 Posted September 10, 2021 Hi Team, I would like to embed something in my Delphi D10.4.2 32 bit Apps that would monitor something such that I could send a text message to them. e.g. Send a message, "Please log out of your application asap!", to 5 Users on 5 different workstations connected via LAN & RDP. The Apps would detect this message and pop up a message dialog to the User. Obviously it would need a sending mechanism as well. Thoughts, suggestions, examples, recommendations appreciated. Regards & TIA, Ian Share this post Link to post
David Schwartz 426 Posted September 10, 2021 Applications that I've worked on solved that by having their main module poll a central folder or message queue in a DB for new messages every minute or two. When something showed up, it would be displayed to the user. That works as long as it's YOUR OWN APP they're running. But if it's a portal and you need to reset/reboot regardless of what apps they're running, then you'd need something else. Windows 10 has a way to send alerts; I know b/c I get them all the time from different places. You could always write a very small listener app that sits in the task bar and watches for a message, or is connected via a socket listener to a broadcast source. Lots of possibilities! Share this post Link to post
Ian Branch 127 Posted September 10, 2021 Hi David, Thank you for your thoughts. Yes, they are all my Apps. Rebooting is not the issue, it is getting the message to them to exit the Apps so I can. ;-) They are on a LAN with Win 7 PCs and RDP into a Win 2012 Server R2. Regards, Ian Share this post Link to post
David Schwartz 426 Posted September 10, 2021 3 hours ago, Ian Branch said: Hi David, Thank you for your thoughts. Yes, they are all my Apps. <-- this is what's most important in this case Rebooting is not the issue, At my last job, we'd get these periodically from IT saying they needed to restart a server to let people using it know to get off it is getting the message to them to exit the Apps so I can. 😉 They are on a LAN with Win 7 PCs and RDP into a Win 2012 Server R2. Not particularly relevant You have two main channels you're going to focus on using: 1) Your app 2) The OS If you know everybody is using your app, and that's who is going to be affected, then have the app poll for messages periodically and alert them when one shows up. If it's anybody using the server, then use the OS and broadast to everybody logged-in. Share this post Link to post
Ian Branch 127 Posted September 11, 2021 Hi David, I ended up writing a little App to write a 'message.txt' file to the Apps root directory. It deletes it when I exit the App. I then added the following code in a TTimer event.. procedure TMainForm.MessageTimerTimer(Sender: TObject); var sPath, sMessage: string; fMessageFile: TextFile; begin // sPath := ExtractFileDir(ParamStr(0)) + '\Message.txt'; // if FileExists(sPath) then begin AssignFile(fMessageFile, sPath); Reset(fMessageFile); ReadLn(fMessageFile, sMessage); CloseFile(fMessageFile); // with TTaskDialog.Create(self) do try Caption := 'Operations Alert!'; Title := 'Urgent Action Notice!'; Text := sMessage; CommonButtons := [tcbOk]; Execute; finally Free; end; // end; // end; It fires every 60 seconds. I will see on Monday how it does or doesn't affect performance from the User's perspective. They are generally pretty quick to let me know. ;-) Regards, Ian Share this post Link to post
Mr. E 6 Posted September 12, 2021 Although I like your solution better. Perhaps something could be programmed to make use of "msg": Msg: Sends a message to a user on a Remote Desktop Session Host (RD Session Host) server. Quote Syntax msg {<UserName> | <SessionName> | <SessionID>| @<FileName> | *} [/server:<ServerName>] [/time:<Seconds>] [/v] [/w] [<Message>] Examples To send the message entitled "Let's meet at 1PM today" to all sessions for User1, type: msg User1 Let's meet at 1PM today To send the same message to session MODEM02, type: msg modem02 Let's meet at 1PM today To send the message to session 12, type: msg 12 Let's meet at 1PM today To send the message to all sessions contained in the file USERLIST, type: msg @userlist Let's meet at 1PM today To send the message to all users who are logged on, type: msg * Let's meet at 1PM today To send the message to all users, with an acknowledgment time-out (for example, 10 seconds), type: msg * /TIME:10 Let's meet at 1PM today Although it seems that there are problems in windows server 2016 or 2019. Share this post Link to post
David Schwartz 426 Posted September 13, 2021 The above is fine except: (1) people who are not using the app will get the message; (2) people who are not affected by rebooting a server they're not using will get the message. If you want to notify people using your app that the server it's connected to (that may not have any other connections to it) is going to be restarted, then have a mechanism that lets you notify the users of that app based on something as simple as what's shown above, reading a file and displaying it. I've seen this approach in several large apps over time, and nobody complains about performance. Indeed, calling FileExists every 60 seconds is hardly anything anybody would notice. 1 Share this post Link to post
Ian Branch 127 Posted September 13, 2021 Hi Team, My solution has been running all day, multiple Apps, multiple Users, no issues seen or reported. :-) I did a test message this morning and got a response from everybody. :-) Thank you all for your input. Regards, Ian Share this post Link to post
aehimself 396 Posted September 13, 2021 On 9/12/2021 at 12:43 AM, Ian Branch said: Hi David, I ended up writing a little App to write a 'message.txt' file to the Apps root directory. It deletes it when I exit the App. I then added the following code in a TTimer event.. This code is completely missing error handling and does not consider access sharing and will read only the first line of the message. As an extra if the file is not deleted it will pop back up every 60 seconds. If {$I-}, use ERRORLEVEL to determine if the Reset was successful, if {$I+} swallow (or just politely indicate) the error. Wrap the Reset...ReadLn...Close to a Try-Finally bloc to ensure the file will be closed no matter what. As for access sharing you might want to use TFileStream instead with fmShareDenyNone. Share this post Link to post
Ian Branch 127 Posted September 13, 2021 1 minute ago, aehimself said: This code is completely missing error handling and does not consider access sharing and will read only the first line of the message. As an extra if the file is not deleted it will pop back up every 60 seconds. If {$I-}, use ERRORLEVEL to determine if the Reset was successful, if {$I+} swallow (or just politely indicate) the error. Wrap the Reset...ReadLn...Close to a Try-Finally bloc to ensure the file will be closed no matter what. As for access sharing you might want to use TFileStream instead with fmShareDenyNone. Error Handling - Not worth it in this case. This may get used once a month, if that. It is intended to repeat every 60 secs as long as the message.txt lives. Exiting the message.txt creating App deletes the file. Try-Finally bloc - Yup, will do that. TFileStream - Will look at. Thank you for your input/suggestions. Ian Share this post Link to post
Fr0sT.Brutal 900 Posted September 13, 2021 So you have 2 apps and intermediate file when you already have network server all app instances interact with. Why multiply matters? OnTimer: resp := HTTPReq('server/maintenance') if resp.Code = 200 then MsgBox('Server shutdown scheduled at ' + resp.Headers['X-MaintTime']) 1 Share this post Link to post
aehimself 396 Posted September 13, 2021 1 hour ago, Ian Branch said: Error Handling - Not worth it in this case. This may get used once a month, if that. It is intended to repeat every 60 secs as long as the message.txt lives. Exiting the message.txt creating App deletes the file. Try-Finally bloc - Yup, will do that. TFileStream - Will look at. Thank you for your input/suggestions. Ian Sorry for my previous post being so blunt - I just had different matters to attend to and wanted to leave my comments. With the reappearance the issue is that if the user leaves his PC for half an hour, 30 dialogs will be shown as not even a modal window "blocks" processing further WM_TIMER messages. In these cases I'm usually wrapping the whole OnTimer event in a Timer.Enabled := False; Try [...] Finally Timer.Enabled := True; End; to make sure I'm not rendering my app in an unwanted state. As for the error handling even if this functionality is being used once in a lifetime it worths to add those extra 2-3 lines. Anything is more beautiful than the standard application error dialog 🙂 Just my 2 cents. Share this post Link to post
Ian Branch 127 Posted September 13, 2021 (edited) Appreciate the concern. The usage model is that the originator will probably want one or more Users to exit their App(s). As the Apps check every 60 secs and the Originator's Generate App checks every 120 secs, then shortly after the generator App shows the message the Originator would exit, deleting the message file. Yes, if the User(s) are away from their PC there will be messages waiting for them when they get back. The practicality is that if they haven't exited in a timely manner their Boss will be on the Phone to them. 🙂 In general this has nothing to do with any Server action. It is purely for if/when an App update needs to be loaded. Ian Edited September 13, 2021 by Ian Branch Share this post Link to post
Guest Posted September 13, 2021 Well, a timer-based code chunk that creates and display an app modal window. Of course, i do not know your app, but that sounds a bit dangerous to me. Will it display properly if another modal is active? Share this post Link to post