the problem I have here might have a quick workaround but I've been stuck for a while.
I am writing a service that starts a process when a user logs in and stops it when the user logs out. In my previous tries I have tried using a loop which checked the presence of explorer.exe but it didn't work very well as the infinite loop meant the service was stuck at "starting". So I have looked into the C# on session change. Here is the code I currently have, creating text files to check if it actually works.
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
CanPauseAndContinue = true;
CanHandleSessionChangeEvent = true;
ServiceName = "Service1";
}
public void onDebug()
{
OnStart(null);
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() +
" - Session change notice received: " +
changeDescription.Reason.ToString() + " Session ID: " +
changeDescription.SessionId.ToString());
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "sessionchange.txt");
switch (changeDescription.Reason)
{
case SessionChangeReason.SessionLogon:
string[] lines = { DateTime.Now.ToShortTimeString() };
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "logged in.txt");
System.IO.File.WriteAllLines(#"C:\Users\Public\test\loggedin.txt", lines);
break;
case SessionChangeReason.SessionLogoff:
string[] lines2 = { DateTime.Now.ToShortTimeString() };
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "logged out.txt");
System.IO.File.WriteAllLines(#"C:\Users\Public\test\loggedout.txt", lines2);
break;
}
}
protected override void OnStart(string[] args)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "onstart.txt");
}
I expected this to work, but apparently not. The on start text file is being created, but out of the 4 logged on/off ones that should appear (somewhere) only loggedout.txt appears in the Public user directory after a log out. No matter how many times I shut down, log in or out the other text files for login are not being created. The time in the only loggedout.txt file create also won't update.
If it helps, I'm running this in a Virtual Machine. I have also read somewhere that SessionChange might only apply to remote log ins but I'm not sure. I'm not sure how to proceed, wether to keep trying or there is another way for services to "listen" to session changes?
Thanks for taking the time to read through.
Related
My problem is the following . I have created android service which is winning even after the application is closed. When the application is active i can scan for the service and i can see it running and i can stop it. When i close the activity completely and start the app I again scan for active services i cannot find it in the list. So how to stop the service after the restart of the program so i can get indication if service is still running in the background. I use the bellow method for checking the service.
public void IsServiceRunning()
{
ActivityManager activityManager = (ActivityManager)GetSystemService(Context.ActivityService);
var list = activityManager.GetRunningServices(int.MaxValue);
foreach(var item in list)
{
Toast.MakeText(ApplicationContext, item.Service.ClassName + " " + item.Started + " " + item.Service.Class, ToastLength.Short).Show();
Log.Debug("++++++++++++++++++++++++++++++++++ ", item.Service.ClassName + " " + item.Started + " " + item.Service.Class);
if ( item.Service.ClassName.Contains("MyService"))
{
MessagingCenter.Send<string>("true", "CheckRunningService");
//Toast.MakeText(ApplicationContext, item.Service.ShortClassName.ToString(), ToastLength.Short).Show();
return;
}
}
MessagingCenter.Send<string>("false", "CheckRunningService");
}
Service Code
class MyService : Service
{
SmsBroadcastRceiver sms;
public override void OnCreate()
{
base.OnCreate();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
//Toast.MakeText(this, "MyService Started", ToastLength.Long).Show();
sms = new SmsBroadcastRceiver();
RegisterReceiver(sms, new IntentFilter("SMS_RECEIVED"));
return StartCommandResult.NotSticky;
}
public override void OnDestroy()
{
UnregisterReceiver(sms);
StopSelf();
//Toast.MakeText(this, "MyService Stopped", ToastLength.Long).Show();
base.OnDestroy();
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
Try to put android:stopWithTask="true" with service,which is declared in manifest file and
In the service class
Override the onTaskRemoved method and check also you can remove updates of location listener here to stop the location updates
Hope it will help for you
I think i found why once my app is stopped i cannot find it. As stated bellow from the documentation :
getRunningServices(int maxNum)
This method was deprecated in API level 26. As of Build.VERSION_CODES.O, this method is no longer available to third party applications. For backwards compatibility, it will still return the caller's own services.
EDIT: The issue here wan't the fact it was locked via GP, it was that it was being run as a service under a service account and it didn't have access to the interactive desktop
I have a C# application that needs to check for when a user's session is locked, I'm using Microsoft.Win32.SystemEvents.SessionSwitch and this works fine when a user manually locks the machine.
The problem is that when the machine is locked via a group policy (User Configuration > Policies > Administrative Templates > Personalization > Screen saver timeout) the application doesn't pick up the switch.
Is there another way to check for a machine being locked? Or is there another way to lock machines via group policy that will be picked up by the application?
N.B. The application is running on windows 7 as a service with full admin rights
Here's my code, Thanks in advance!!! :)
public void OnStart(string[] args)
{
Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch);
}
void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.SessionLock)
{
//DO STUFF
}
}
I managed to resolve this by enabling 'Other Logon/Logoff Events' in Windows Event Viewer and searching for the lock and unlock events.
//Define strings for searching the eventlog.
string lockEvent = "4800";
string unlockEvent = "4801";
//Define the Eventlog source you want (in this case it's Security)
string LogSource = #"Security";
//Add these together to make the full query for Lock and Unlock
string LockQuery = " *[System/EventID=" + lockEvent + "]";
string UnlockQuery = "*[System/EventID=" + unlockEvent + "]";
//Return true if there is any locked events found.
private bool CheckForLock()
{
//Create Eventlog Reader and Query
var elQuery = new EventLogQuery(LogSource, PathType.LogName, LockQuery);
var elReader = new System.Diagnostics.Eventing.Reader.EventLogReader(elQuery);
//Create a list of Eventlog records and add the found records to this
List<EventRecord> eventList = new List<EventRecord>();
for (EventRecord eventInstance = elReader.ReadEvent();
null != eventInstance; eventInstance = elReader.ReadEvent())
{
eventlist.add(eventInstance);
}
if(eventList.count > 0)
{
return true;
}
else
{
return false;
}
}
N.B. This will check all the event log, so you need to put a qualifier on how far into the past you want to bee looking.
If you check for lock/unlock sessions every ten seconds, you only want to deal with an EventRecord if it's from the same time period.
You can access the eventlist.TimeCreated value to do something like...
if (eventInstance.TimeCreated > DateTime.Now - TimeSpan.FromSeconds(10))
{
eventList.Add(eventInstance);
}
Is it elegant? No. Does it work? Yes.
I'm using EWS Managed API and C#.
I want to know if it's possible to detect when an email is moved to another folder.
This is what I have so far:
static void SetPullNotifications(ExchangeService service)
{
PullSubscription subscription = service.SubscribeToPullNotificationsOnAllFolders(
5, null,
EventType.Moved, EventType.Deleted, EventType.Copied, EventType.Modified);
GetEventsResults events = subscription.GetEvents();
foreach (ItemEvent itemEvent in events)
{
switch (itemEvent.EventType)
{
case EventType.Moved:
MessageBox.Show("Item Moved :" + itemEvent.ItemId.UniqueId);
break;
case EventType.Deleted:
MessageBox.Show("Item deleted: " + itemEvent.ItemId.UniqueId);
break;
case EventType.Copied:
MessageBox.Show("Item Copied :" + itemEvent.ItemId.UniqueId);
break;
case EventType.Modified:
MessageBox.Show("Item Modified :" + itemEvent.ItemId.UniqueId);
break;
}
}
}
This works fine if I put a breakpoint on the method GetEvents(), then move an email. But without the breakpoint it does not work. The events contains no results.
Any ideas ?
your on the right way, but your missing something. Your code will only get the events which occour between creating the subscription and getting the Events, that's why it only works with a breakpoint.
To make your code work you should do 2 things.
At first: Create the subscrption when you start your application and keep a refernce on it.
At Second Store the Watermark you get from the Subscription and reload it on application startup. Maybe like this:
static PullSubscription s_Subscription;
static void Main()
{
ExchangeService service = CreateService();
CreateSubsciption(service);
//DoSomething;
GetEvents();
//DoSomething;
StoreWatermark(s_Subscription.Watermark);
}
static void CreateSubscription(ExchangeService Service)
{
string watermarkt = LoadWatermark();
s_Subscription = service.SubscribeToPullNotificationsOnAllFolders(
5, watermark,
EventType.Moved, EventType.Deleted, EventType.Copied, EventType.Modified);
}
static void GetEvents()
{
GetEventsResults events = subscription.GetEvents();
foreach (ItemEvent itemEvent in events)
{
switch (itemEvent.EventType)
{
case EventType.Moved:
MessageBox.Show("Item Moved :" + itemEvent.ItemId.UniqueId);
break;
case EventType.Deleted:
MessageBox.Show("Item deleted: " + itemEvent.ItemId.UniqueId);
break;
case EventType.Copied:
MessageBox.Show("Item Copied :" + itemEvent.ItemId.UniqueId);
break;
case EventType.Modified:
MessageBox.Show("Item Modified :" + itemEvent.ItemId.UniqueId);
break;
}
}
}
You can use Streaming Notifications with EWS to listen for changes to items on the Exchange Server. Here is an example on how to set up Streaming Notifications:
http://blogs.msdn.com/b/exchangedev/archive/2010/12/22/working-with-streaming-notifications-by-using-the-ews-managed-api.aspx
In your case you should handle the EventType.Moved event. When you are handling the events you are given an object of type ItemEvent (as shown in the above example) which has two properties OldParentFolderId and ParentFolderId which identify the folder the item was moved from and to.
The reason, why your code doesnt work, is just simple. there is no time that Events could happen. You create a subcription which will recognize only events from the Moment you create it, 'cause the watermark is null. Only one line later, so let's say a millisecond later you ask the subscription "hey were there any Event in the past millisecond?" and the answer is "no". Create your subscription at program startup and call getevents on a timer, maybe 5 minutes later. And if you had any event in the past five minutes, your messagebox will appear.
I am using ShutdownBlockReasonCreate in my C# application to warn the user if a logoff/shutdown is going to effect a currently running method in my application.
I have two methods that will warn the user: An "Upload" method and a "Download" method.
If the user starts a long Upload, I set the ShutdownBlockReasonCreate with a message like "Upload is currently running".
The problem I am having is that if a user starts a simple download while the long upload is running, ShutdownBlockReasonCreate is also called again with a message like "Download is currently running".
This overwrites the original "Upload is currently running" message. So when my download method is finished, and I call ShutdownBlockReasonDestroy, the user is all of a sudden now able to shutdown and logoff even though the upload is still running.
I want to be able to call ShutdownBlockReasonCreate with an optional parameter that I can call so I can send it multiple strings on why the program will not allow windows to shutdown or logoff.
So when the user goes to logoff, I want it to display:
"Upload is currently running"
"Download is currently running"
if both an upload and download is running.
Can someone please modify my code to show me how to do this? If I can pass something else other than "this.Handle"; maybe I can accomplish this but I am unsure how to do this.
//http://blogs.msdn.com/b/oldnewthing/archive/2012/06/14/10319617.aspx
//http://bartdesmet.net/blogs/bart/archive/2006/10/25/Windows-Vista-_2D00_-ShutdownBlockReasonCreate-in-C_2300_.aspx
[DllImport("user32.dll")]
public extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);
[DllImport("user32.dll")]
public extern static bool ShutdownBlockReasonDestroy(IntPtr hWnd);
private bool isBlocked = false;
protected override void WndProc(ref Message aMessage)
{
const int WM_QUERYENDSESSION = 0x0011;
const int WM_ENDSESSION = 0x0016;
if (isBlocked && (aMessage.Msg == WM_QUERYENDSESSION || aMessage.Msg == WM_ENDSESSION))
return;
base.WndProc(ref aMessage);
}
private void StopShutdown(string strMessage)
{
try
{
//strMessage == Message to display in shutdown/logoff box
if (ShutdownBlockReasonCreate(this.Handle, strMessage))
{
isBlocked = true;
Console.WriteLine("++ StopShutdown successful");
}
else
Console.WriteLine("++ StopShutdown failed");
}
catch (Exception ext)
{
MessageBox.Show("++ StopShutdown Error: " + ext.Message + " " + ext.StackTrace);
}
}
private void ResetShutdown()
{
try
{
if (ShutdownBlockReasonDestroy(this.Handle))
{
isBlocked = false;
Console.WriteLine("++ ResetShutdown successful");
}
else
Console.WriteLine("++ ResetShutdown failed");
}
catch (Exception ext)
{
MessageBox.Show("++ ResetShutdown Error: " + ext.Message + " " + ext.StackTrace);
}
}
private void button1_Click(object sender, EventArgs e)
{
StopShutdown("Upload in Progress");
MessageBox.Show("Upload in Progress");
ResetShutdown();
}
private void button2_Click(object sender, EventArgs e)
{
StopShutdown("Download in Progress");
MessageBox.Show("Download in Progress");
ResetShutdown();
}
In order to ensure that the correct message is displayed, and that the message is always displayed (and shutdown prevented) if a blocking operation is in progress, you need to keep careful track of what is occurring in your system.
For example, suppose you could have any number of uploads and downloads running simultaneously. In that case, your StopShutdown() method needs to determine what operations are currently occurring. If there is at least one upload, but no download, then set the message to "Upload in progress." If there is at least one download, but no upload, set the message to "Download in progress." If there is at least one of each, then set the message to "Upload and download in progress."
In your ResetShutdown() method, you need to again check which operations are still in progress. If there are none, then you should destroy the reason, and set isBlocked back to false. Otherwise, you should adjust the message based on what's currently running, and leave isBlocked as true.
By doing that, you ensure that you both have the correct shutdown method, and then also only allow shutdown if your program is not in the middle of an operation that should block shutdown.
(Also, you should keep in mind that users are free to "Force Shutdown" the system, even if you "block" it, so a safer approach is often to try to suspend what you're doing and then resume at a later point.)
I posted about this a little while ago, but I resolved the other issue and ran into one more. I am about to deploy this program to 28 hosting machines so I want to make sure this is working before I do so.
I wrote a little c# NET application that is basically a wrapper for a Java application, when my app starts, the Java app starts, when my app closes, it closes, and so on.
Everything works properly except that when I close my application, the Java application continues to run. When I create the process, I store the Process var in a variable outside of the methods, and then use that when my application goes to shutdown. For whatever reason though it is not terminating the Java application.
class Program
{
private static Process minecraftProcess;
public static void LaunchMinecraft(String file, String memoryValue)
{
String memParams = "-Xmx" + memoryValue + "M" + " -Xms" + memoryValue + "M ";
String args = memParams + "-jar " + file + " nogui";
ProcessStartInfo processInfo = new ProcessStartInfo("java.exe", args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
try
{
//using (Process minecraftProcess = Process.Start(processInfo))
using (minecraftProcess = Process.Start(processInfo))
{
minecraftProcess.WaitForExit();
}
}
catch
{
// Log Error
}
}
static void Main(string[] args)
{
Arguments CommandLine = new Arguments(args);
// Hook ProcessExit Event
AppDomain.CurrentDomain.ProcessExit += new EventHandler(Current_ProcessExit);
if (CommandLine["file"] != null && CommandLine["memory"] != null)
{
// Launch the Application (Command Line Parameters)
LaunchMinecraft(CommandLine["file"], CommandLine["memory"]);
}
else
{
// Launch the Application (Default Parameters)
LaunchMinecraft("minecraft_server.jar", "1024");
}
}
static void Current_ProcessExit(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(10000);
// If we have an active Minecraft Service, Shut it down
if (minecraftProcess != null)
{
minecraftProcess.Kill();
}
}
}
You can't Sleep in a ProcessExit handler.
The documentation states:
The total execution time of all
ProcessExit event handlers is limited,
just as the total execution time of
all finalizers is limited at process
shutdown. The default is two seconds.
An unmanaged host can change this
execution time by calling the
ICLRPolicyManager::SetTimeout method
with the OPR_ProcessExit enumeration
value.
Nevermind, I just realized the minecraftProcess variable is static.
Don't know if you did not solve this issue by yourself but:
You should be aware that there are Start methods for instances (returning bool) and static (returning a object).
You should not use using with something other than using-local variables!
Just this should work fine:
minecraftProcess = Process.Start(processInfo)
minecraftProcess.WaitForExit();