I have created a windows service which gets soem info from database and I want to notify user based on the info retreived from the DB. How can I notify user from a windows service using system tray notification? Can you please show me some sample (using IPC mechanism) to get the return value of a method used in a windows service in a system tray notification?
Thanks in advance.
There are several options such as these:
Sockets: (Not too difficult to write, has firewall problems) You can find samples for it almost everywhere.
External WinForm: (The easiest method, has security problems and might blocked by
some antivirus apps) Just create a winForm with the ability to go into
the windows notification area and then tell the service to run its
exe file.
Named Pipes: (Probably the most difficult, but it's the recommended
solution) Here is a Code Project sample.
Other tricks like: Create a hidden winform project (ShowInTask=false) and put it in StartUp. provide it with a FileSystemWatcher object and make it watch for a certain file which the service creates or deletes it to signal the winform.
Related
This question already has answers here:
how to identify logon event in window service
(3 answers)
Closed 9 years ago.
I want to know how to receive windows logon and logoff events inside a delphi windows service.
The service itself is already built, now I want to show a systray icon that opens a settings/logs window. To show that icon I need to know if a user has logged in...
I have seen some info regarding "System Event Notification Service" for c#, but there is very little info on delphi.
Since user sessions are based on RDS (Remote Desktop Services - former Terminal Services) technology you can try WTSRegisterSessionNotification/WTSRegisterSessionNotificationEx APIs. They give you information about various events like:
WTS_SESSION_LOGON
WTS_SESSION_LOGOFF
WTS_REMOTE_CONNECT
WTS_REMOTE_DISCONNECT
WTS_CONSOLE_CONNECT
WTS_CONSOLE_DISCONNECT etc.
Based on the event you can find user's session ID. Then you can start a process in this specific session (i.e. inject a program to a specific RDS session). For example you can start a process in user's session that shows your icon(s). This process can communicate with your service via named pipes, memory mapped files etc.
Personally I use these events to stop GUI intensive work when a user disconnects from a session (i.e. stop updating labels, listboxes, memos etc.)
** These APIs require to have a window that receives notifications. In a service you need to create a hidden one with a message loop (another topic)
I have an xmpp/ejabberdb app that uses an external service to provide eventing features, but when this service becomes unavailable, I want to disconnect/logout all of my clients. Is this possible? How?
I got it working the way I needed. In fact, I didn't find any simple way to make my own server logout all connected users given some kind of situation, so I dug into ejabberd's code and figured out a way to do it myself.
In ejabberd_c2s.erl module, when a client logs out or it's socket is dropped for some reason, the FSM is terminated, doing all necessary clean up to maintain ejabberd's consistency.
What I had to do was just create an exported function shutdown/1 in this module that calls gen_fsm:send_all_state_event/2 sending a signal for it to terminate.
As for each connection there's one c2s process, I need to call this function for each user.
---UPDATING---
Actually there's no need to create this shutdown function, as ejabber_c2s already has the ability to process 'closed' signal, which does the same thing. So, instead of creating the shutdown function, simply doing ge_fsm:send_event(C2SPid, closed) might be enough.
---UPDATING---
To discover the user's c2s process PID I just use ejabberd_sm:get_session_pid/1 or ejabberd_sm:dirty_get_sessions_list/0 (for all sessions).
This worked fine for me, but if anyone has a better idea, please add here.
Thanks
I don't know the ejabberd specifics, but you could write a custom XMPP component which polls the external service (or listens for presence events, if it's another XMPP component), then logs out users when the service becomes unavailable.
I have created a WCF service using the NetMsmq binding for which i created a private queue on my machine and executed the project. This works fine as such and my WCF service is started and accesses the message using the queue in the debugging environment. Now, I wanted to host the service using the windows service and for the same I created a new project and windows installer as well (This service runs under Local System Account). Then I tried installing this windows service using the InstallUtil command through the command prompt. When installation is happening and during the service host opening, I get an exception saying:
There was an error opening the queue. Ensure that MSMQ is installed and running, the queue exists and has proper authorization to be read from. The inner exception may contain additional information.
Inner Exception System.ServiceModel.MsmqException: An error occurred while opening the queue:Access is denied. (-1072824283, 0xc00e0025). The message cannot be sent or received from the queue. Ensure that MSMQ is installed and running. Also ensure that the queue is available to open with the required access mode and authorization.
at System.ServiceModel.Channels.MsmqQueue.OpenQueue()
at System.ServiceModel.Channels.MsmqQueue.GetHandle()
at System.ServiceModel.Channels.MsmqQueue.SupportsAccessMode(String formatName, Int32 accessType, MsmqException& msmqException)
Could anyone suggest the possible solution for the above issue? Am I missing any permissions to be set for the queue as well as the windows service, if so could you suggest where should these permissions be added?
Tom Hollander had a great three-part blog series on using MSMQ from WCF - well worth checking out!
MSMQ, WCF and IIS: Getting them to play nice (Part 1)
MSMQ, WCF and IIS: Getting them to play nice (Part 2)
MSMQ, WCF and IIS: Getting them to play nice (Part 3)
Maybe you'll find the solution to your problem mentioned somewhere!
Yes, it looks like a permissions issue.
Right click on your private queue from the Server Manager, and select Properties. Proceed to the Security tab, and make sure you have the right permissions in there for your Local System Account.
This is also confirmed in Nicholas Allen's article: Diagnosing Common Queue Errors, where the author defines the error code 0xC00E0025 as a permissions problem.
I ran into same problem, here is the solution.
Right click "My Computer" --> Manage. In Computer Management window go to "Services and Applications --> Message Queueing --> ur queue", select ur queue and access properties. Add the user running ur WCF application and give full access. This should solve the issue.
Can simple be that the service can't find the it's queue.
The queue name must exact match the endpoint address.
Example:
net.msmq://localhost/private/wf.listener_srv/service.svc
points to local queue
private$\wf.listener_srv\service.svc
If queue name and endpoint are according to each other, then is most like that the credentials defined on the IIS pool don't grant access to the queue.
I am to build a web application which will accept different events from external sources and present them quickly to the user for further actions. I want to use Ruby on Rails for the web application. This project is a internal development project. I would prefer simple and easy to use solutions for rapid development over high reliable and complex systems.
What it should do
The user has the web application opened in his browser. Now an phone call comes is. The phone call is registered by a PBX monitoring daemon. In this case via the Asterisk Manager Interface. The daemon sends the available information (remote extension, local extension, call direction, channel status, start time, end time) somehow to the web application. Next the user receives a notified about the phone call event. The user now can work with this. For example by entering a summary or by matching the call to a customer profile.
The duration from the first event on the PBX (e.g. the creation of a new channel) to the popup notification in the browser should be short. Given a fast network I would like to be within two seconds. The single pieces of information about an event are created asynchronously. The local extension may be supplied separate from the remote extension. The user can enter a summary before the call has ended. The end time, new status etc. will show up on the interface as soon as one party has hung up.
The PBX monitor is just one data source. There will be more monitors like email or a request via a web form. The monitoring daemons will not necessarily run on the same host as the database or web server. I do not image the application will serve thousands of logged in users or concurrent requests soon. But from the design 200 users with maybe about the same number of events per minute should not be a scalability issue.
How should I do?
I am interested to know how you would design such an application. What technologies would you suggest? How do the daemons communicate their information? When and by whom is the data about an event stored into the main database? How does the user get notified? Should the browser receive a complete dataset on behalf of a daemon or just a short note that new data is available? Which JS library to use and how to create the necessary code on the server side?
On my research I came across a lot of possibilities: Message brokers, queue services, some rails background task solutions, HTTP Push services, XMPP and so on. Some products I am going to look into: ActiveMQ, Starling and Workling, Juggernaut and Bosh.
Maybe I am aiming too hight? If there is a simpler or easier way, like just using the XML or JSON interface of Rails, I would like to read this even more.
I hope the text is not too long :)
Thanks.
If you want to skip Java and Flash, perhaps it makes sense to use a technology in the Comet family to do the push from the server to the browser?
http://en.wikipedia.org/wiki/Comet_%28programming%29
For the sake of simplicity, for notifications from daemons to the Web browser, I'd leave Rails in the middle, create a RESTful interface to that Rails application, and have all of the daemons report to it. Then in your daemons you can do something as simple as use curl or libcurl to post the notifications. The Rails app would then be responsible for collecting the incoming notifications from the various sources and reporting them to the browser, either via JavaScript using a Comet solution or via some kind of fatter client implemented using Flash or Java.
You could approach this a number of ways but my only comment would be: Push, don't pull. For low latency it's not only quicker it's more efficient, as your server now doesn't have to handle n*clients once a second polling the db/queue. ActiveMQ is OK, but Starling will probably serve you better if you're not looking for insane levels of persistence.
You'll almost certainly end up using Flash on the client side (Juggernaut uses it last time I checked) or Java. This may be an issue for your clients (if they don't have Flash/Java installed) but for most people it's not an issue; still, a fallback mechanism onto a pull notification system might be prudent to implement.
Perhaps http://goldfishserver.com might be of some use to you. It provides a simple API to allow push notifications to your web pages. In short, when your data updates, send it (some payload data) to the Goldfish servers and your client browsers will be notified, with the same data.
Disclaimer: I am a developer working on goldfish.
The problem
There is an event - either external (or perhaps internally within your app).
Users should be notified.
One solution
I am myself facing this problem. I haven't solved it yet, but this is how I intend to do it. It may help you too:
(A) The app must learn about the event (via an exposed end point)
Expose an end point by which you app can be notified about external events.
When the end point is hit (and after authentication then users need to be notified).
(B) Notification
You can notify the user directly by changing the DOM on the current web page they are on.
You can notify users by using the Push API (but you need to make sure your browsers can target that).
All of these notification features should be able to be handled via Action Cable: (i) either by updating the DOM to notify you when a phone call comes in, or (ii) via a push notification that pops up in your browser.
Summary: use Action Cable.
(Also: why use an external service like Pusher, when you have ActionCable at your disposal? Some people say scalability, and infrastructure management. But I do not know enough to comment on these issues. )
We use stateful DataSnap servers for some business logic tasks and also to provide clientdataset data.
If we have to update the server to modify a business rule, we copy the new version into a new empty folder and register it (depending on the Delphi version, just by launching or by running the TRegSvr utility).
We can do this even while the old server instance is running. However, after registering the new version, all new client connections will still use the currently running (old) server instance. All clients have to disconnect first, then the new server will be used for the next clients.
Is there a way to direct all new client connections to the new server, immediately after registering?
(I know that new or changed method signatures will also require a change and restart of the clients but this question is about internal modifications which do not affect the interface)
We are using Socket connections, and all clients share the same server application (only one application window is open). In the early days we have used a different configuration of the remote datamodule which resulted in one app window per client. Maybe this could be a solution? (because every new client will launch the currently registered executable)
Update: does Delphi XE offer some support for 'hot deployment' (of updated servers)? We use Delphi 2009 at the moment but would upgrade to XE if it offers easier implementation of 'hot deployment'.
you could separate your appserver into 2 new servers, one being a simple proxy object redirecting all methods (and optionally containing state info if any) to the second one actually implementing your business logic. you also need to implement "silent reconnect" feature within your proxy server in order not to disturb connected clients if you decide to replace business appserver any time you want. never did such design myself before but hope the idea is clear
Have you tried renaming the current server and placing the new in the same location with the correct name (versus changing the registry location). I have done this for COM libraries before with success. I am not sure if it would apply to remote launch rules through as it may look for an existing instance to attach to instead of a completely fresh server.
It may be a bit hackish but you would have the client call a method on the server indicating that a newer version is available. This would allow it to perform any necessary cleanup so it doesn't end up talking to both the existing server instance and new server instance at the same time.
There is probably not a simple answer to this question, and I suspect that you will have to modify the client. The simplest solution I can think of is to have a flag (a property or an out parameter on some commonly called method) on the server that the client checks periodically that tells the client to disconnect and reconnect (called something like ImBeingRetired).
It's also possible to write callbacks under certain circumstances for datasnap (although I've never done this). This would allow the server to inform the client that it should restart or reconnect.
The last option I can think of (that hasn't already been mentioned) would be to make the client/server stateless, so that every time the client wants something it connects, gets what it wants then disconnects.
Unfortunately none of these options are the answer you want to your question, but might give you some ideas.
(optional) set up vmware vSphere, ESX, or find a hosting service that already has one.
Store the session variables in db.
Prepare 2 web boxes with 2 distinct IP address and deploy your stuff.
Set up DNS, firewall, load balancer, or BSD vm so name "example.com" resolves to web box 1.
Deploy new version to web box 2.
Switch over to web box 2 using whatever routing method you chose.
Deploy new version to web box 1 if things look ok.
Using DNS is probably easiest, but it takes time for the mapping to propagate to the client (if the client is outside your LAN) and also two clients may see different results. Some firewalls have IP address mapping feature that you can map public IP address and internal IP address. The ideal way is to use load balancer and configure it to 50:50 and change it to 100:0 when you want to do upgrade, but it costs money. A cheaper alternative is to run software load balancer on BSD vm, but it probably requires some work.
Edit: What I meant to say is session variables, not session. You said the server is stateful. If it contains some business logic that uses session variable, it needs to get stored externally to be preserved across reconnection during switch over. Actual DataSnap session will be lost, so when you shutdown web box 1 during upgrade, the client will get "Session {some-uuid} is not found" error by web box 1, and it will reconnect to web box 2.
Also you could use 3 IP addresses (1 public and 2 private) so the client always sees 1 address , which is better method.
I have done something similar by having a specific table which held my "data version". Each time I would update the server or change a system wide global setting, I would increment this field. When a client starts it always checks this value, and will check again before any transactions/queries. If the value was ever different from when I first started, then I needed to go through my re-initialization logic, which could easily include a re-login to an updated server.
I was using IIS to publish my app servers, so the data that would change would be the path to the app server. I kept the old ones available, to respond to any existing transactions that were in play. Eventually these would be removed once I knew there were no more client connections to that version.
You could easily handle knowing what versions to keep around if you log what server the client last connected too (and therefore would know about).
For newer versions (Delphi 2010 and up), there is an interesting solution
for systems using the HTTP transport:
Implementing Failover and Load Balancing in DataSnap 2010 by Andreano Lanusse
and a related question for the TCP/IP transport:
How to direct DataSnap client connections to various DS Servers?