WPF Application not launching after Windows startup - c#

My Application will not launch after Windows startup, the application is registered in the register editor with the right path to my application exe.
Register Editor ScreenShot
here is my code to register my application to the register editor
private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
RegistryKey reg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RUN", true);
if (e.PropertyName == nameof(isStartOnStartup))
{
if (isStartOnStartup)
{
reg.SetValue("CommunicationHub", Process.GetCurrentProcess().MainModule.FileName);
Settings.Default.Startup = true;
Settings.Default.Save();
}
else
{
reg.DeleteValue("CommunicationHub");
Settings.Default.Startup = false;
Settings.Default.Save();
}
}
}
I have checked EventViewer for crashes and have aswell added logging to the application root, both gave me nothing.
I have disabled UAC, to check if it was the administrator right that was hindering the application from running, still no result.
i feel lost, i hope someone can help me with the problem..

Found another way to do this, instead of having my application in the register editor, but in Task Schedular, it will launch the application on windows startup with the admin rights. BUT! Only if I tell task scheduler to launch it as "at log on" trigger and not on "at system startup". But if I combine td.Triggers.AddNew(TaskTriggerType.Boot); and td.Principal.UserId = "SYSTEM";
it will give me the status running but the UI is not showing. Why?.. How do I fix this?
Here is my updated code, and I found a library to do the schedular thing.
library: https://github.com/dahall/TaskScheduler
{
TaskService ts = new TaskService();
string program_path = Process.GetCurrentProcess().MainModule.FileName;
if (e.PropertyName == nameof(isStartOnStartup))
{
if (isStartOnStartup)
{
TaskDefinition td = ts.NewTask();
td.Principal.RunLevel = TaskRunLevel.Highest;
td.Triggers.AddNew(TaskTriggerType.Boot); // Not working
td.Principal.UserId = "SYSTEM"; // Run whether user is logged on or not. combined with line 132 runs the program but the ui is invicible
//td.Triggers.AddNew(TaskTriggerType.Logon); // Runs and shows the UI perfectly fine
td.Actions.Add(new ExecAction(program_path, null));
ts.RootFolder.RegisterTaskDefinition("CommunicationHub", td);
Settings.Default.Startup = true;
Settings.Default.Save();
}
else
{
ts.RootFolder.DeleteTask("CommunicationHub", false);
Settings.Default.Startup = false;
Settings.Default.Save();
}
}
}

Related

Service works on debug but now when i Install it

I'm creating a little stupid service as a joke, is supposed to create an "invincible" txt on the desktop which gets recreated if deleted.
It works when debugged but when I install the service it doesn't create the txt.
I have :
execute the service with admin rights adding this line of code:
<PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
to the app.manifest).
I checked the "the authorize to interact whit desktop" checkmark on the service proprieties.
the code is working when I debug (i use Topshelf) but when I install the service it does not work.
the code which creates the txt(and the constructor):
public Invincible()
{
_timer = new Timer(3000) { AutoReset = true };
_timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
string[] frase = new string[] {"NON PUOI RIMUOVERE QUESTA MALEDIZIONE <3"};
string curFile = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+"/Invincible_Curse.txt";
string curFile2 = "C:/temp/Demos/Invincible_Curse.txt";
if (!File.Exists(curFile))
{
File.AppendAllLines(curFile, frase);
}
}
the Main:
static void Main(string[] args)
{
var exitCode = HostFactory.Run(x =>
{
x.Service<Invincible>(s =>
{
s.ConstructUsing(Invincible => new Invincible());
s.WhenStarted(Invincible => Invincible.Start());
s.WhenStopped(Invincible => Invincible.Stop());
x.SetServiceName("InvincibleService");
x.SetDisplayName("Invincible Service");
x.SetDescription("Cerca di sopravvivere");
});
});
int exitCodeValue = (int)Convert.ChangeType(exitCode, exitCode.GetTypeCode());
Environment.ExitCode = exitCodeValue;
}
thanks for the help.
Your code seems okay, even though you could do with a bit of a refactoring.
For example move around this part like this:
var exitCode = HostFactory.Run(x =>
{
x.Service<Invincible>(s =>
{
s.ConstructUsing(Invincible => new Invincible());
s.WhenStarted(Invincible => Invincible.Start());
s.WhenStopped(Invincible => Invincible.Stop());
});
x.SetServiceName("InvincibleService");
x.SetDisplayName("Invincible Service");
x.SetDescription("Cerca di sopravvivere");
});
Your issue is that, the windows service that you are running is using a different Windows user account, it's not the Windows user account which you use for logging in and using your PC. So their desktop paths are different. Every user account on Windows has a different desktop path.
To fix it, simply make the service log on using the account which you want the txt file to appear to.

C# SessionSwitchReason.SessionLock NOT triggering when machine is locked via Group Policy

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.

Start an offline ClickOnce Application and wait for Exit

I have deployed a ClickOnce Windows Forms application (App A)
Another application (App B) starts App A with a filename as parameter.
I do this with this Code
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var location = String.Format(#"{0}\{1}\{2}\{3}",
basePath, "MyCompany", "MyProduct", "MyApp.appref-ms");
var fileName = #"c:\temp\somefile.ext";
var uri = new Uri(fileName).ToString();
Process.Start(location, uri);
App A grabs the file name from AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0] and show the content.
This works like a charm. However, now I want App B to wait for App A to exit.
But a call to Process.WaitForExit() returns instantly.
Is there a way to open a ClickOnce App and wait for it to exit? I can, if necessary, change the way the app is opend but the requirement is that I need to run the app as a ClickOnce app (I know that somewhere in my user profile AppData\Local\Apps\2.0\ folder the exe exists and can be started directly but If I do that ApplicationDeployment.IsNetworkDeployed is false and ApplicationDeployment.CurrentDeployment is null. In that I loose the ClickOnce Update Capabilities).
my suggestion would be to use Mutex in App A, and let App B check and wait for it. This is the cleanest way from my point of view.
App A does this when starts:
private static Mutex mutex;
public static void Main()
{
// if you want your app to be limited to a single instance
// across ALL SESSIONS (multiple users & terminal services), then use the following line instead:
// string mutexName = string.Format("Global\\{0}", ProgramInfo.AssemblyGuid);
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(true, mutexName, out singleInstance);
if (singleInstance == false)
{
// that means your app has more than one instance running
// you need to decide what to do here.
}
// rest of initialization code
Application.Run();
// release the mutex so App B can continue
mutex.ReleaseMutex();
}
and App B just waits for the mutex to be released:
Process.Start(location, uri);
Thread.Sleep(5000); // give it 5 seconds or so to check for updates and start
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(false, mutexName);
mutex.WaitOne();
The problem is that starting the appref-ms process does not actually start the application it starts the deployment manifest, which then launches the application itself, so the process you are starting exits straight away.
You can add a check to see when you application has started if you know the name (which I assume you do) like this:
string myAppName = "YourAppName";
DateTime startTime = DateTime.Now;
int newProcessId = 0;
List<int> runningProcessIds = new List<int>();
//find all the running processes and record their Ids
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
proc = proc_loopVariable;
runningProcessIds.Add(proc.Id);
}
//start the new process
Process.Start(location);
//wait for the new application to be started
while (!(Process.GetProcessesByName(myAppName).Count != runningProcessIds.Count)) {
//timeout if we have not seen the application start
if ((DateTime.Now - startTime).TotalSeconds > 30)
break;
}
//loop through all the running processes again to find the id of the one that has just started
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
proc = proc_loopVariable;
if (!runningProcessIds.Contains(proc.Id)) {
newProcessId = proc.Id;
break;
}
}
//wait for the application to finish
Process.GetProcessById(newProcessId).WaitForExit();
Debug.WriteLine("Finished");

Why does Visual Studio run code after my breakpoint during a debug session?

I am working on a project in c# that using threading to initialize multiple calls to xcopy to copy user directories from one workstation to a network location.
When I run the program in debug mode, sometimes if I have a break-point BEFORE the program hits the calls to XCopy, and I stop the debugging with the stop button (in VS 2010), the program will then proceed to call the XCopy function, even though I stopped it from reaching the calls in the code. If I stop inside the foreach loop does the debugger continue to do the other foreach instances?
I know it sounds crazy, but has anyone else ever experienced this, or might you offer some suggestions that would correct this from happening?
A second issue with this is that when I run it from my Win7 machine accessing an XP machine in Firefox, the osInfo is correct, but when my boss runs it on his Win7 machine in IE, it doesn't work. It makes sense to me that the lines:
System.OperatingSystem osInfo = System.Environment.OSVersion;
if (dir_base.Exists && (osInfo.Platform == System.PlatformID.Win32NT)) //XP
Should be pulling the system that is running the code, not the network location's operating system type, but the if statement results in true when I run it and false when he does...
Here is my code:
public static void BuildSources_Targets(string Source, string str_Target )
{
//XP:
string str_basePath = Path.Combine(Source, "Documents and Settings");
var dir_base = new DirectoryInfo(str_basePath);
System.OperatingSystem osInfo = System.Environment.OSVersion;
if (dir_base.Exists && (osInfo.Platform == System.PlatformID.Win32NT)) //XP
{
foreach (var dir in dir_base.GetFileSystemInfos())
{
switch (dir.ToString())
{
case "administrator":
case "Administrator":
case "Default User":
case "All Users":
//Do nothing
break;
default:
string str_dir = dir.ToString();
//Handle XP App Data
//str_baseAndDirsPath = Path.Combine(dir_base.ToString(), str_dir, Environment.SpecialFolder.ApplicationData.ToString());
string str_baseAndDirsPath = Path.Combine(dir_base.ToString(), str_dir, "Application Data");
DirectoryInfo dir_baseAndDirs = new DirectoryInfo(str_baseAndDirsPath);
if (dir_baseAndDirs.Exists)
{
string str_Destination = Path.Combine(str_Target, str_dir, "Application Data");
ProcessXcopy(str_baseAndDirsPath, str_Destination);
}
//Handle XP Documents
str_baseAndDirsPath = Path.Combine(dir_base.ToString(), str_dir, "My Documents");
dir_baseAndDirs = new DirectoryInfo(str_baseAndDirsPath);
if (dir_baseAndDirs.Exists)
{
string str_Destination = Path.Combine(str_Target, str_dir, str_dir + " Documents");
ProcessXcopy(str_baseAndDirsPath, str_Destination);
}
break;
} //end of switch
} //end of foreach
} //end of dir_base.exists
//it continues from here...but that's enough to illustrate my problem...

BackgroundTaskBuilder Register() issue

I was developing application with Geofencing, when stuck at issue:
ArgumentException (Value does not fall within the expected range)
when I am trying to register background task for geofencing.
Sample from MSDN has the same problem. I will show code from sample for clarity (link to sample: http://code.msdn.microsoft.com/windowsapps/Geolocation-2483de66#content
use scenario 5,
http://msdn.microsoft.com/en-us/library/windows/apps/dn440583.aspx - instruction how to test).
All what I have done:
Build my app in Visual Studio.
Deploy the app locally first and add the app to the lock screen in Settings.
Close your app that is running locally.
Launch your app in the Visual Studio simulator.
Call RegisterBackgroundTask(..) (simply pressed button register in scenario 5)
There is code from MSDN sample that I have commented for successful app deploying in Simulator - tagged with ////// [my changes] ////////
async private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
try
{
// Get permission for a background task from the user. If the user has already answered once,
// this does nothing and the user must manually update their preference via PC Settings.
//BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync(); ////// [my changes] ////////
// Regardless of the answer, register the background task. If the user later adds this application
// to the lock screen, the background task will be ready to run.
// Create a new background task builder
BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();
geofenceTaskBuilder.Name = SampleBackgroundTaskName;
geofenceTaskBuilder.TaskEntryPoint = SampleBackgroundTaskEntryPoint;
// Create a new location trigger
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
// Associate the locationi trigger with the background task builder
geofenceTaskBuilder.SetTrigger(trigger);
// If it is important that there is user presence and/or
// internet connection when OnCompleted is called
// the following could be called before calling Register()
// SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
// geofenceTaskBuilder.AddCondition(condition);
// Register the background task
geofenceTask = geofenceTaskBuilder.Register();
// Associate an event handler with the new background task
geofenceTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
UpdateButtonStates(/*registered:*/ true);
////// [my changes] ////////
//switch (backgroundAccessStatus)
//{
// case BackgroundAccessStatus.Unspecified:
// case BackgroundAccessStatus.Denied:
// rootPage.NotifyUser("This application must be added to the lock screen before the background task will run.", NotifyType.ErrorMessage);
// break;
// default:
// // Ensure we have presented the location consent prompt (by asynchronously getting the current
// // position). This must be done here because the background task cannot display UI.
// GetGeopositionAsync();
// break;
//}
////// [my changes] ////////
}
catch (Exception ex)
{
// HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == 0x80070032
const int RequestNotSupportedHResult = unchecked((int)0x80070032);
if (ex.HResult == RequestNotSupportedHResult)
{
rootPage.NotifyUser("Location Simulator not supported. Could not get permission to add application to the lock screen, this application must be added to the lock screen before the background task will run.", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser(ex.ToString(), NotifyType.ErrorMessage);
}
UpdateButtonStates(/*registered:*/ false);
}
}
Exception falls on string:
geofenceTask = geofenceTaskBuilder.Register();
Can anybody help me?
P.S. Same question thread on msdn - http://social.msdn.microsoft.com/Forums/en-US/3d69f2f9-93e0-401b-8a13-598dc671fa4f/backgroundtask-register?forum=winappswithcsharp
This is a known "bug" see Windows Store 8.1 Location background tasks do not work in simulator. I have yet to get an answer other than
Your issue has been routed to the appropriate VS development team for investigation
Please upvote it!

Categories