Jump to content
Ian Branch

Send a message to App users??

Recommended Posts

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

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

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
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

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

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

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.

  • Like 1

Share this post


Link to post

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

 

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
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

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'])

  • Like 1

Share this post


Link to post
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

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 by Ian Branch

Share this post


Link to post
Guest

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×