I wrote this code that works perfectly, but I fear that ping every 2 seconds consumes too many resources or can create some problems with internet connection.
new Thread(() =>
{
if (CheckInternetConnection() == false)
{
Dispatcher.Invoke(new Action(delegate
{
//internet access lost
}));
}
else
{
Dispatcher.Invoke(new Action(delegate
{
//internet access
}));
}
Thread.Sleep(2000);
}).Start();
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
public static bool CheckInternetConnection()
{
int output = 0;
return InternetGetConnectedState(out output, 0);
}
These are two events that don't work in all occasions (only when IP or network card changes)
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
Can someone help me ?
Note : In regaurds to your original solution
NetworkChange.NetworkAvailabilityChanged works fine, but
there are a couple of caveats: 1) it doesn't tell you if you have
Internet access, it just tells you whether there's at least one
non-loopback network adapter working, and 2) there are often extra
network adapters installed for various reasons that leave the system
in a "network is available" state, even when your main
Internet-connected adapter is disabled/unavailable - thanks to Peter Duniho
Since networking is more than just your routers or network card, and is really every hop to where ever it is you are trying to connect to at any time. The easiest and most reliable way is just ping a well known source like google, or use some sort of heart beat to one of your internet services.
The reasons this is the only reliable way is that any number of connectivity issues can occur in between you and the outside world. Even major service providers can go down.
So an IMCP ping to a known server like Google, or calling OpenRead on a WebClient are 2 valid approaches. These calls are not expensive comparatively and can be put into a light weight timer or continual task.
As for your comments you can probably signal a custom event to denote the loss of network after a certain amount of fails to be safe
To answer your question
But I fear that ping every 2 seconds consumes too many resources or
can create some problems with internet connection.
Both methods are very inexpensive in regards to CPU and network traffic, any resources used should be very minimal
Note : Just make sure you are pinging or connecting to a server with high availability, this will
allow such shenanigans and not just block you
Ping Example
using System.Net.NetworkInformation;
// Implementation
using (var ping = new Ping())
{
var reply = ping.Send("www.google.com");
if (reply != null && reply.Status != IPStatus.Success)
{
// Raise an event
// you might want to check for consistent failures
// before signalling a the Internet is down
}
}
// Or if you wanted to get fancy ping multiple sources
private async Task<List<PingReply>> PingAsync(List<string> listOfIPs)
{
Ping pingSender = new Ping();
var tasks = listOfIPs.Select(ip => pingSender.SendPingAsync(ip, 2000));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
Connection Example
using System.Net;
// Implementation
try
{
using (WebClient client = new WebClient())
{
using (client.OpenRead("http://www.google.com/"))
{
// success
}
}
}
catch
{
// Raise an event
// you might want to check for consistent failures
// before signalling the Internet is down
}
Note : Both these methods have an async variant that will return a
Task and can be awaited for an Asynchronous programming pattern better suited for IO bound tasks
Resources
Ping.Send Method
Ping.SendAsync Method
WebClient.OpenRead Method
WebClient.OpenReadAsync Method
NetworkInterface.GetIsNetworkAvailable() is unreliable... since it would return true even if all the networks are not connected to internet. The best approach to check for connectivity, in my opinion, is to ping a well known and fast online resource. For example:
public static Boolean InternetAvailable()
{
try
{
using (WebClient client = new WebClient())
{
using (client.OpenRead("http://www.google.com/"))
{
return true;
}
}
}
catch
{
return false;
}
}
Anyway, those two events you are subscribing don't work the way you think... actually they check for the hardware status of your network adapters... not whether they are connected to internet or not. They have the same drawback as NetworkInterface.GetIsNetworkAvailable(). Keep on checking for connectivity into a separate thread that pings a safe source and act accordingly. Your Interop solution is excellent too.
Doing ping to public resources brings extra calls to your app and adds a dependency on that website or whatever you would use in the loop.
What if you use this method: NetworkInterface.GetIsNetworkAvailable() ?
Would it be enough for your app's purposes?
I found it here https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface.getisnetworkavailable?view=netframework-4.7.1#System_Net_NetworkInformation_NetworkInterface_GetIsNetworkAvailable
Related
I've been searching quite a bit on this topic, but I think I'm not using the right words for searching any of this stuff, because I've not found an answer yet.
I'm looking for a way to make a process wait for a (specific) response of an external source.
In more detail, in a standard socket connection, I ask my remote endpoint for a certain value via a socket.send, how can I "catch" their reply? The idea that I already had was to send some sort of identifier along to determine what request this belongs to.
Is there a way to efficiently achieve this? (Performance is rather important). I'm currently using .NET2.0 if that's relevant information.
Some example code:
public void AskForReply()
{
//Send to connected endpoint
}
public void ReceiveReply(IAsyncResult response)
{
//Do stuff with the response
}
I've been working out several ideas in my head. But they all feel really messy and not very efficient. Is there a design pattern for this? Are there standards for this behavior?
And help is greatly appreciated!
For anyone who runs into a similar problem, I have found a way to make an asynchronous call synchronous (which is essentially what you are trying to achieve).
EventWaitHandle waitHandler;
string replyMessage;
void string AskForReply()
{
//Already requesting something...
if(waitHandler != null) { return; }
waitHandler = new EventWaitHandle(false, EventResetMode.AutoReset);
//Send a request to a remote service
waitHandler.WaitOne(timeout);
//Will reply null (or the default value) if the timeout passes.
return replyMessage;
}
void ReceiveReply(string message)
{
//We never asked for a reply? (Optional)
if (waitHandler != null) { return; }
replyMessage = message;
//Process your reply
waitHandler.Set();
waitHandler = null;
}
It's probably a good idea to put the EventWaitHandle and the reply message in a class for better and cleaner management. You can then even put this object in a dictionary along with a key that you can use handle multiple requests at once (do keep in mind they are synchronous and will block your thread until the timeout or the waithandle is set).
I currently check the availability of Azure ServiceBus with following code:
using Microsoft.ServiceBus.Messaging;
public static bool IsOnline(string queueName = null)
{
try
{
QueueClient queueClient = QueueClient.CreateFromConnectionString(ConnectionString);
queueClient.Peek(); //works, but will explode on Receive()
return true;
}
catch
{
return false;
}
}
However, when ASB queue is disabled, Peek() still works but Receive() will throw an error.
Microsoft.ServiceBus.Messaging.MessagingEntityDisabledException: Messaging entity 'servicebus01:Queue:myqueue' is currently disabled. fc088ddd-0592-460e-a8b1-9587f708a6a1_G30 ---> System.ServiceModel.FaultException1[System.ServiceModel.ExceptionDetail]:...
Is there a reliable way to check whether ServiceBus is available ? (online, not disabled, and ready to queue/dequeue)
Monitoring entity (queue) shouldn't be performed. If an entity is disabled, it has to have a good reason for that. If an entity is disabled, it would be done deliberately, knowing the consequences. Only if that's the case, I'd go with an agreed upon protocol how to communicate it, rather than pinging an enntity.
Service availability is a different thing. If you want to make sure that the service is up, is it a one time check or for each operation? If for each operation, you better rely on the built in retry strategy and if needed, add your own back off strategy. If you need to have to action whenever the service is down, you might want to look into the Azure Monitor service.
So far I have the following solution to detect availability:
Create a dedicated testqueue
Receive message from that queue
Although it works, it feels like a hacky way to reliably detect AzureServiceBus availability. Looking forward to a more elegant solution from you.
public static bool IsOnline(string queueName = null)
{
try
{
QueueClient queueClient = QueueClient.CreateFromConnectionString(ConnectionString, "testqueue", ReceiveMode.ReceiveAndDelete);
queueClient.Receive(TimeSpan.Zero);
queueClient.Close();
return true;
}
catch
{
return false;
}
}
I have a metro app talking to a device over wifi using UDP. However, when I disconnect the device from the network or start the app with the device disconnected, nothing happens. ConnectAsync doesn't throw an exception, the app doesn't throw an exception, the app runs like nothing's wrong.
I can't ping the other end but If I give it a formatted string it will respond. The device is currently connected to a router which has internet access but I'm eventually planning to use a router without internet access. I've never done anything with UDP so I'm at a loss here.
Here is an implementation of a UDP listener/writer(taken from Pete Bright at 10rem.net)
class Network
{
private DatagramSocket _socket;
public bool IsConnected { get; set; }
public bool recieved;
public string ret;
public Network()
{
IsConnected = false;
_socket = new DatagramSocket();
_socket.MessageReceived += OnSocketMessageReceived;
}
public async void Connect(HostName remoteHostName, string remoteServiceNameOrPort)
{
try
{
await _socket.ConnectAsync(remoteHostName, remoteServiceNameOrPort);
}
catch (Exception e)
{
var msg = new MessageDialog(e.ToString());
msg.ShowAsync();
}
IsConnected = true;
}
private void OnSocketMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
var reader = args.GetDataReader();
var count = reader.UnconsumedBufferLength;
var data = reader.ReadString(count);
ret = data.Trim();
recieved = true;
}
DataWriter _writer =null;
public async void SendMessage(string message)
{
if (String.IsNullOrEmpty(message)) return;
if (_writer == null)
{
var stream = _socket.OutputStream;
_writer = new DataWriter(stream);
}
_writer.WriteString(message);
await _writer.StoreAsync();
}
}
UDP Sockets are "connection-less", so the protocol does not know anything about whether or not the server and client are connected. To know if a a connection is still "active" you will have to implement your own connection detection.
I might recommend reading beej's guide to sockets. It's a good read and pretty funny:
http://beej.us/guide/bgnet/
As it was said, there is no concept like there is in tcp/ip with sync/ack, etc to communicate back and forth and ensure something is there.
Clients are neither connected nor disconnected, only listening or sending really.
So with that said you need to implement a receive timeout from the client.
There are some funny jokes with UDP, since you send data and just essentially fling it out into space. The order the packets are received can't matter either or you are stuck implementing your own scheme here as well.
What you'll need to do here is actually try to reach the device. If you care, then you can do this every X seconds.
As it is stated here: How to test a remote UDP Port
(keep with me, a better approach below this but wanted to provide multiple means)
You can use UdpClient, set a receive timeout on the underlying socket,
make a connection to that remote server/port, Send some small message
(byte[] !) and call Receive.
IF the port is closed you get an exception saying that the connection
was forcibly closed (SocketException with
ErrorCode 10054 = WSAECONNRESET)... which means the port is NOT open.
However- I think a better approach is to actually agree upon a protocol id or some specific data that the clients send every X seconds. If received, then update your 'client connected' table, otherwise consider them disconnected until the client sends a packet with a protocol id over.
A great series on this that you can probably easily adapt to c# is at:
http://gafferongames.com/networking-for-game-programmers/virtual-connection-over-udp/
I believe your code above can be refactored as well to only Send() to an address rather than connect, since there really is no true connect.
To help out people that stumble upon this:Apparently my google-fu is pretty weak. This shows how to set timeouts for TCP and UDP sockets. Default behavior is to never time out(which is consistent with what I saw).
Edit: It doesn't work. Even with a timeout of 500ms I'm still seeing the same behavior of "no exception thrown".
I am currently working on a WinForm app to stream videos from IP camera using the RTSP protocol in C#. Everything worked fine. Part of the requirement for the app includes a function to check whether the IP camera is online or not.
So I did a ping function using the System.Net.NetworkInformation.Ping class to ping the IP camera. Say if the RTSP url of the camera is as follows rtsp://[CAMERA IP]:554/Master0-RTSP/1.0, I would only need to extract the [CAMERA IP] part and use the Ping class to see if the camera is online or not by using its IP.
Initially, it works until an issue came, say if one to enter an IP which may not be the intended IP Camera (say an IP of a computer) the ping function would still work if the entered IP of the entered device is online.
I tried to search for something like a RTSP ping but could not find one. Was hoping for any advices or opinions on this matter. Any example in C# are greatly appreciated. Thank you for your kind attention.
OPTIONS can possibly work but the standard specifies the correct way is through using theGET_PARAMETER.
RFC2326 outlines that clearly
http://www.ietf.org/rfc/rfc2326.txt
10.8 GET_PARAMETER
The GET_PARAMETER request retrieves the value of a parameter of a
presentation or stream specified in the URI. The content of the reply
and response is left to the implementation. GET_PARAMETER with no
entity body may be used to test client or server liveness ("ping").
While GET_PARAMETER may not be supported by the server there is no way to tell how that server will react to the OPTIONS request which does not even require a sessionID. Therefor it cannot be guaranteed it will keep your existing session alive.
This is clear from reading the same RFC about the OPTIONS request
10.1 OPTIONS
The behavior is equivalent to that described in [H9.2]. An OPTIONS
request may be issued at any time, e.g., if the client is about to
try a nonstandard request. It does not influence server state.
Example:
C->S: OPTIONS * RTSP/1.0
CSeq: 1
Require: implicit-play
Proxy-Require: gzipped-messages
S->C: RTSP/1.0 200 OK
CSeq: 1
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
Note that these are necessarily fictional features (one would hope
that we would not purposefully overlook a truly useful feature just
so that we could have a strong example in this section).
If GET_PARAMETER is not supported then you would issue a PLAY request with the SessionId of the session you want to keep alive.
This should work even if OPTIONS doesn't as PLAY honors the Session ID and if you are already playing there is no adverse effect.
For the C# RtspClient see my project # https://net7mma.codeplex.com/
And the article on CodeProject # http://www.codeproject.com/Articles/507218/Managed-Media-Aggregation-using-Rtsp-and-Rtp
Regarding RTSP in C# see this thread Using RTMP or RTSP protocol in C#
Regarding Ping ... you can implement is as DESCRIBE operation ... but pay attention do not make it too frequently, the device should be affected.
http://www.ietf.org/rfc/rfc2326.txt
Instead of ICMP ping, you might want to keep a helper RTSP session without video/audio RTP streams, checking good standing of socket connection and sending OPTIONS or DESCRIBE command on a regular basis, e.g. once a minute, in order to see if the device is responsive.
Some suggest using GET_PARAMETER instead of options, however this is inferior method. OPTIONS is mandatory, GET_PARAMETER is not. Both serve different purpose. Both have small server side execution expense. OPTIONS is clearly the better of the two.
Some servers may not support setting stream parameters and thus not support GET_PARAMETER and SET_PARAMETER.
You can use RTSPClientSharp and do something like this:
public static async Task TestRTSPConnection(string rtspAddress, string user, string password)
{
var serverUri = new Uri(rtspAddress);
var credentials = new NetworkCredential(user, password);
var connectionParameters = new ConnectionParameters(serverUri, credentials);
var cancellationTokenSource = new CancellationTokenSource();
var connectTask = ConnectAsync(connectionParameters, cancellationTokenSource.Token);
if (await Task.WhenAny(connectTask, Task.Delay(15000 /*timeout*/)) == connectTask)
{
if (!connectTask.Result)
{
logger.Warn("Connection refused - check username and password");
}
logger.Info("Connection test completed");
}
else
{
logger.Warn("Connection timed out - check username and password");
}
}
private static async Task<bool> ConnectAsync(ConnectionParameters connectionParameters, CancellationToken token)
{
try
{
using (var rtspClient = new RtspClient(connectionParameters))
{
rtspClient.FrameReceived +=
(sender, frame) => logger.Info($"New frame {frame.Timestamp}: {frame.GetType().Name}");
while (true)
{
logger.Info("Connecting...");
try
{
await rtspClient.ConnectAsync(token);
}
catch (OperationCanceledException)
{
logger.Info("Finishing test before connection could be established. Check credentials");
return false;
}
catch (RtspClientException e)
{
logger.Error($"{e.Message}: {e.InnerException?.Message}");
return false;
}
logger.Info("Connected - camera is online");
return true;
}
}
}
catch (OperationCanceledException)
{
return false;
}
}
It works for me pretty well if you just care about pinging and if the camera is online or not. Also timeout happens when credentials are incorrect. You get direct failure if port is not exposed or connection is refused.
I currently have a single application that needs to be started from a windows service that i am coding in .net 3.5. This application is currently running as the user who ran the service, in my case the SYSTEM user. If running as the SYSTEM user it does not show the application to the users desktop. Thoughts? advice?
//constructor
private Process ETCHNotify = new Process();
//StartService()
ETCHNotify.StartInfo.FileName = baseDir + "\\EtchNotify.exe";
ETCHNotify.StartInfo.UseShellExecute = false;
//BackgroundWorkerThread_DoWork()
if (!systemData.GetUserName().Equals(""))
{
// start ETCHNotify
try {
ETCHNotify.Start();
}
catch (Exception ex)
{
systemData.Run("ERR: Notify can't start: " + ex.Message);
}
}
I only execute the try/catch if the function i have written GetUserName() (which determines the username of the user running explorer.exe) is not null
again to reiterate: desired functionality is that this starts ETCHNotify in a state that allows it to interact with the currently logged in user as determined by GetUserName()
Collage of some post found around (this and this)
Note that as of Windows Vista, services are strictly forbidden from interacting directly with a user:
Important: Services cannot directly interact with a user as of Windows
Vista. Therefore, the techniques mentioned in the section titled Using
an Interactive Service should not be used in new code.
This "feature" is broken, and conventional wisdom dictates that you shouldn't have been relying on it anyway. Services are not meant to provide a UI or allow any type of direct user interaction. Microsoft has been cautioning that this feature be avoided since the early days of Windows NT because of the possible security risks.
There are some possible workarounds, however, if you absolutely must have this functionality. But I strongly urge you to consider its necessity carefully and explore alternative designs for your service.
Use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
However, I would strongly recommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
Ultimately in order to solve this i took the advice of #marco and the posts he mentioned. I have created the service to be entirely independent of the tray application that interacts with the user. I did however install the Tray application via registry 'start up' methods with the service. The Service installer will now install the application which interacts with the user as well... This was the safest and most complete method.
thanks for your help everyone.
I wasn't going to answer this since you already answered it, (and it's oh, what? going on 2.5 years OLD now!?) But there are ALWAYS those people who are searching for this same topic, and reading the answers...
In order to get my service to Interact with the Desktop, no matter WHAT desktop, nor, how MANY desktops, nor if the service was even running on the SAME COMPUTER as the desktop app!! None of that matters with what I got here... I won't bore you with the details, I'll just give you the meat and potatoes, and you and let me know if you want to see more...
Ok. First thing I did was create an Advertisement Service. This is a thread that the service runs, opens up a UDP socket to listen for broadcasts on the network. Then, using the same piece of code, I shared it with the client app, but it calls up Advertise.CLIENT, rather than Advertise.SERVER... The CLIENT opens the port I expect the service to be on, and broadcasts a message, "Hello... Is there anybody out there??", asking if they're there ANY servers listening, and if so, reply back to THIS IP address with your computer name, IP Address and port # where I can find the .NET remoting Services..." Then it waits a small amount of time-out time, gathers up the responses it gets, and if it's more than one, it presents the user with a dialog box and a list of services that responded... The Client then selects one, or, if only ONE responded, it will call Connect((TServerResponse) res); on that, to get connected up. At this point, the server is using Remoting Services with the WellKnownClientType, and WellKnownServerType to put itself out there...
I don't think you are too interested in my "Auto-Service locater", because a lot of people frown on UDP, even more so when your app start broadcasting on large networks. So, I'm assuming you'd be more interested in my RemotingHelper, that gets the client connected up to the server. It looks like this:
public static Object GetObject(Type type)
{
try {
if(_wellKnownTypes == null) {
InitTypeCache();
}
WellKnownClientTypeEntry entr = (WellKnownClientTypeEntry)_wellKnownTypes[type];
if(entr == null) {
throw new RemotingException("Type not found!");
}
return System.Activator.GetObject(entr.ObjectType, entr.ObjectUrl);
} catch(System.Net.Sockets.SocketException sex) {
DebugHelper.Debug.OutputDebugString("SocketException occured in RemotingHelper::GetObject(). Error: {0}.", sex.Message);
Disconnect();
if(Connect()) {
return GetObject(type);
}
}
return null;
}
private static void InitTypeCache()
{
if(m_AdvertiseServer == null) {
throw new RemotingException("AdvertisementServer cannot be null when connecting to a server.");
}
_wellKnownTypes = new Dictionary<Type, WellKnownClientTypeEntry>();
Dictionary<string, object> channelProperties = new Dictionary<string, object>();
channelProperties["port"] = 0;
channelProperties["name"] = m_AdvertiseServer.ChannelName;
Dictionary<string, object> binFormatterProperties = new Dictionary<string, object>();
binFormatterProperties["typeFilterLevel"] = "Full";
if(Environment.UserInteractive) {
BinaryServerFormatterSinkProvider binFormatterProvider = new BinaryServerFormatterSinkProvider(binFormatterProperties, null);
_serverChannel = new TcpServerChannel(channelProperties, binFormatterProvider);
// LEF: Only if we are coming form OUTSIDE the SERVICE do we want to register the channel, since the SERVICE already has this
// channel registered in this AppDomain.
ChannelServices.RegisterChannel(_serverChannel, false);
}
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IPawnStatServiceStatus)));
RegisterType(typeof(IPawnStatServiceStatus),m_AdvertiseServer.RunningStatusURL.ToString());
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IPawnStatService)));
RegisterType(typeof(IPawnStatService), m_AdvertiseServer.RunningServerURL.ToString());
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IServiceConfiguration)));
RegisterType(typeof(IServiceConfiguration), m_AdvertiseServer.RunningConfigURL.ToString());
}
[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration, RemotingConfiguration=true)]
public static void RegisterType(Type type, string serviceUrl)
{
WellKnownClientTypeEntry clientType = new WellKnownClientTypeEntry(type, serviceUrl);
if(clientType != RemotingConfiguration.IsWellKnownClientType(type)) {
RemotingConfiguration.RegisterWellKnownClientType(clientType);
}
_wellKnownTypes[type] = clientType;
}
public static bool Connect()
{
// Init the Advertisement Service, and Locate any listening services out there...
m_AdvertiseServer.InitClient();
if(m_AdvertiseServer.LocateServices(iTimeout)) {
if(!Connected) {
bConnected = true;
}
} else {
bConnected = false;
}
return Connected;
}
public static void Disconnect()
{
if(_wellKnownTypes != null) {
_wellKnownTypes.Clear();
}
_wellKnownTypes = null;
if(_serverChannel != null) {
if(Environment.UserInteractive) {
// LEF: Don't unregister the channel, because we are running from the service, and we don't want to unregister the channel...
ChannelServices.UnregisterChannel(_serverChannel);
// LEF: If we are coming from the SERVICE, we do *NOT* want to unregister the channel, since it is already registered!
_serverChannel = null;
}
}
bConnected = false;
}
}
So, THAT is meat of my remoting code, and allowed me to write a client that didn't have to be aware of where the services was installed, or how many services were running on the network. This allowed me to communicate with it over the network, or on the local machine. And it wasn't a problem to have two or more people running the app, however, yours might. Now, I have some complicated callback code in mine, where I register events to go across the remoting channel, so I have to have code that checks to see if the client is even still connected before I send the notification to the client that something happened. Plus, if you are running for more than one user, you might not want to use Singleton objects. It was fine for me, because the server OWNS the objects, and they are whatever the server SAYS they are. So, my STATS object, for example, is a Singleton. No reason to create an instance of it for EVERY connection, when everyone is going to see the same data, right?
I can provide more chunks of code if necessary. This is, of course, one TINY bit of the overall picture of what makes this work... Not to mention the subscription providers, and all that.
For the sake of completeness, I'm including the code chunk to keep your service connected for the life of the process.
public override object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if(lease.CurrentState == LeaseState.Initial) {
lease.InitialLeaseTime = TimeSpan.FromHours(24);
lease.SponsorshipTimeout = TimeSpan.FromSeconds(30);
lease.RenewOnCallTime = TimeSpan.FromHours(1);
}
return lease;
}
#region ISponsor Members
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
public TimeSpan Renewal(ILease lease)
{
return TimeSpan.FromHours(12);
}
#endregion
If you include the ISponsor interface as part of your server object, you can implement the above code.
Hope SOME of this is useful.
When you register your service, you can tell it to allow interactions with the desktop. You can read this oldie link http://www.codeproject.com/KB/install/cswindowsservicedesktop.aspx
Also, don't forget that you can have multiple users logged in at the same time.
Apparently on Windows Vista and newer interacting with the desktop has been made more difficult. Read this for a potential solution: http://www.codeproject.com/KB/cs/ServiceDesktopInteraction.aspx