Count the number of times the Program has been launched - c#

How can I get the number of times a program has previously run in c# without keeping a file and tallying. Is there a Application class or something in c# to check the count.
Please give a detailed explantion as i know nothing about it.This is A windows console application not windows forms.

You can do that my creating an Entry in the Registry. And another way is by using an Application Settings.
But I prefer Application Settings because it has less task to do.
See HERE: Creating an Application Settings.
Tutorial From Youtube

Recent versions of Windows automatically maintain this information in the registry under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist.
The data is obfuscated with ROT13, but that's easy to "decrypt". A free utility (with source code) is available and can serve as your starting point.

You could send a message to a database or webservice every time the program starts up (assuming there's a network connection).
You could keep a count on some form of hardware thet's not a standard storage device (therefore not technically being a file).
You could make a registry entry that you keep the count in (if you ignore the fact that the registry entry is, at some level, persisted into a file somewhere).
You could just have a file somewhere that keeps track of the count. Not sure why you're so opposed to this one in the first place....

If you are running a Winforms application, the you can easily use the Application Settings. Right click on your Solution Name --> Properties --> Settings Tab. More info and tutorial here.
Then, every time your program starts, increment this setting and save it.

Ref: Count the number of times the Program has been launched
In my knowledge Windows does not keep this information for you. You would have to tally the value somewhere (file, database, registry setting).
Better way is Application Settings as:
Create setting in app.config and then use it as:
Properties.Settings.Default.FirstUserSetting = "abc";
then, you usually do this in the Closing event handler of the main form. The following statement to Save settings method.
Properties.Settings.Default.Save();
Implementation using Registry:
static string AppRegyPath = "Software\\Cheeso\\ApplicationName";
static string rvn_Runs = "Runs";
private Microsoft.Win32.RegistryKey _appCuKey;
public Microsoft.Win32.RegistryKey AppCuKey
{
get
{
if (_appCuKey == null)
{
_appCuKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(AppRegyPath, true);
if (_appCuKey == null)
_appCuKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(AppRegyPath);
}
return _appCuKey;
}
set { _appCuKey = null; }
}
public int UpdateRunCount()
{
int x = (Int32)AppCuKey.GetValue(rvn_Runs, 0);
x++;
AppCuKey.SetValue(rvn_Runs, x);
return x;
}
If it's a WinForms app, you can hook the Form's OnClosing event to run UpdateCount.
Then Check tutorial to Read, write and delete from registry with C#

Related

How to determine if the PC has been rebooted since my program's last run?

The title says it all.
What is the best way to determine if the PC has been rebooted since my program's last run?
Context:
C# - Win XP and on
A piece of hardware (PCIe board) that I'm configuring requires the settings to only be sent once per power cycle but users may close and open the program multiple times before power cycling the PC.
I'm thinking I need some sort of a global reference that my program starts/sets while starting then it can check if said global reference is running/true at each start up and act accordingly.
Ideas? Suggestions?
See How to know when was Windows started or shutdown on how to get the last boot time.
You can write the boot time to a file. When you start your program you can check if the saved value match the current value or not, and update the file with the new value if needed.
See also Getting last reboot time
As user Panagiotis Kanavos commented, an event log entry is written when Windows boots.
If you have a look in Event Viewer in the System log, you will find those entries have Event ID == 12, which is accessed in code by using the InstanceId property of an EventLogEntry (the EventID property is deprecated).
So you can get all those log entries, sort them, and get the latest one, like this:
using System;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
EventLog systemLog = new EventLog("System");
var bootEntry = systemLog?.Entries.Cast<EventLogEntry>().
Where(x => x.InstanceId == 12).
OrderByDescending(x => x.TimeGenerated).
FirstOrDefault();
if (bootEntry != null)
{
Console.WriteLine("Last boot: " + bootEntry.TimeGenerated.ToString("yyyy-MM-dd HH:mm:ss"));
}
else
{
Console.WriteLine("Could not open System log or no boot event found.");
}
Console.ReadLine();
}
}
}
(Tested as working on Windows 10 20H2.)
Now, my computer has a fast SSD, and my experience of reading the event logs from an HDD is that that can be sloooooow, so you might want to get the entry in some background task.
It looks possible to look up the boot time in the Windows Event Log. I haven't verified this, but maybe this can work for you.
Manually, you can use the Event Viewer to find the PC's boot time. This will get you the information you need to make the programmatics call to get the relevant data. You'd do something like this (not a complete solution):
var logs = EventLog.GetEventLogs();
// not sure about this; you may need to change the search below...
var log = logs.Single(l => l.LogDisplayName == "Application and Services Log");
// search entries
var bootEntries = log.Entries.Where(x => ...);
...
This uses these APIs
EventLog class
EventLog.GetEventLogs() method
EventLog.Entries property
EventLogEntry class
So, it looks like it's possible to drill down to the entry you need, grab out the timestamp and do your various checks. Good luck!
Save the last boot time (e.g. in user.config) and then compare it with the current value. Environment.TickCount64 keeps track of the time since the system started.
var storedLastBootTime = LoadBootTimeFromSettings();
var currentTime = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
var lastBootTime = currentTime - Environment.TickCount64;
if (lastBootTime > storedLastBootTime)
{
// A system reboot must have taken place!
}
SaveBootTimeToSettings(lastBootTime);
If the saved value is greater, a restart must have taken place. To handle that you need to save the current time too.

Stop SetVolumeMountPoint from opening file explorer

I am using SetVolumeMountPoint to mount a vhd to a drive letter of my choosing. The problem is that when the vhd is mounted file explorer automatically opens at the new drive directory. This is a problem for me as I need my programs to remain on the foreground and sometimes the spawned file explorer becomes part of the foreground.
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-setvolumemountpointa
Thoughts?
UPDATE:
I programmatically set the noautorun registry key using these two methods before mounting my vhd:
/// <summary>
/// Removing file explorer auto run for the given DriveLetter so that when a vhd is mounted file explorer doesn't open
/// </summary>
/// <param name="DriveLetter"></param>
private void RemoveFileExplorerAutoRun(char DriveLetter)
{
var KeyPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
RegistryKey AutoRunKey = Registry.CurrentUser.OpenSubKey(KeyPath, true);
var DriveLetterValue = DriveLetter - 'A';
if (AutoRunKey != null)
{
RemoveFileExplorerAutoRun(AutoRunKey, DriveLetterValue);
}
else // create key as it does not exist
{
AutoRunKey = Registry.CurrentUser.CreateSubKey(KeyPath);
RemoveFileExplorerAutoRun(AutoRunKey, DriveLetterValue);
}
}
private void RemoveFileExplorerAutoRun(RegistryKey AutoRunKey, int DriveLetterValue)
{
if (AutoRunKey != null)
{
AutoRunKey.SetValue("NoDriveTypeAutoRun", DriveLetterValue);
AutoRunKey.Close();
}
}
Cleanest way seem to be to catch RegisterWindowMessage("QueryCancelAutoPlay") message by your foreground window and return TRUE from your window procedure.
https://learn.microsoft.com/en-us/windows/desktop/shell/autoplay-reg
EDIT:
If foreground window is not your application window, then I would recommend against editing registry, since it is global state, whereas you need just temporary autorun bypass.
Besides windows hook, mentioned in other answer, I would suggest registering your implementation of IQueryCancelAutoPlay interface in running object table
Another way is using Registry.
Please reference "Using the Registry to Disable AutoRun" "How to disable the Autorun functionality in Windows"
Note
The NoDriveAutoRun and NoDriveTypeAutoRun values should only be
modified by system administrators to change the value for the entire
system for testing or administrative purposes. Applications should not
modify these values, as there is no way to reliably restore them to
their original values.
The third way is based on #Alexander Gutenev have pointed out that register a "QueryCancelAutoPlay" window message and then install a global hook from your application to monitor this message.
Note
You should use global hooks only for debugging purposes; otherwise,
you should avoid them. Global hooks hurt system performance and cause
conflicts with other applications that implement the same type of
global hook.
Hooks tend to slow down the system because they increase the amount of
processing the system must perform for each message. You should
install a hook only when necessary, and remove it as soon as possible.

How safe is it to open file and wait for change in a C# program

In my C# WinForms app, users are allowed to create documents and show them in other programs (typically, Word or Excel) and once users close it (if modified), the file is saved by the app in a specific database.
I use the following code to open the file with the correct default program:
string tmpPath = "myTempDoc.xyz"; // extension might vary
FileInfo f = new FileInfo(tmpPath);
DateTime tmpStamp = f.LastWriteTimeUtc;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(tmpPath);
p.WaitForExit();
f = new FileInfo(tmpPath);
if (f.LastWriteTimeUtc > tmpStamp.AddSeconds(1)) {
db_store_file(tmpPath); // stores the modified version of the file in a database
}
// ---- REMAINING CODE AFTER CLOSING ---
doSomeStuff();
I am a bit concerned with the WaitForExit() method. Users need to close the default program for the app to continue. This is ok, but is it really safe?
What if the user (or some process) kills the App during the WaitForExit? For sure, remaining code doSomeStuff() will NOT be executed so I need to make sure all is done BEFORE starting the process... But is there any additional risk?
I know about FileSystemWatcher could be an alternative... But this allows the user to continue in the app without saving changes, which is an additional risk I'd rather not take...
Is the above method safe? Or is there a standard method for letting users modify files in their default program and, once done, retrieve these changes in the database?

Storing the Users Choice in C# Winform permanently

How can I store the user's choice permanently in c# winform.
I wrote this code to fetch the setting:
string my_data_to_do = (string)Settings.Default["MyDataToDo"];
And to save the user's setting I wrote:
if (checkBox3.Checked)
{
Settings.Default["MyDataToDo"] = "Tasks In Hand";
}
else
{
Settings.Default["MyDataToDo"] = "Nothing To Do";
}
This is showing the saved data but only until I exit my application. When I exit and start my program again, all these settings gets automatically removed, and the default data comes, which I saved in Settings.settings file.
Can anyone please help me in this?
It's hard to tell if you're doing it from just the code exert you've posted, but after setting the setting like that you will need to call Settings.Default.Save() to have it persist beyond the application closing.

Why multiple log files are getting created with GUID using System.Diagnostics c# [duplicate]

I use TextWriterTraceListener (System.Diagnostics) in my application to trace several things like exceptions,...
The application is running on a terminal server and if there are many users using it simultaneously the listener starts to create many tracefiles with random GUIDs in the filename.
Are there possibilities or workarounds to avoid this behaviour ?
I've just taken a look at the documentation for TextWriterTraceListener and there's a note about 1/3 of the way down the page
If an attempt is made to write to a file that is in use or unavailable, the file name is automatically prefixed by a GUID
So, this would appear to be by design. If the file is indeed unavailable then there's nothing that can be done about it with the current implementation. What you could try doing is writing a custom implementation of TextWriterTraceListener that overrides the relevant Write/WriteLine methods so that the output goes to a file, per user, with a name that better suits your needs.
If what you want is for ALL logging from ALL users on the Terminal Server to go to a single file, then you'll almost certainly need to have some kind of "3rd party" process running that "owns" the file and synchronises writes to it, such as a Windows Service that is then called by your custom TextWriterTraceListener
Was the fix calling the Trace.Listeners.Add(xxx listener) multiple times on accident?
Because if you have multiple listeners added they write too all listeners when you call the Trace.writeline();
Also local IIS might be continueing to have the file in use when you shut down the application.
I am currently testing the addition of System.Diagnostics.Trace.Listeners.Clear() in my output method...
// Upon a new day re-create the TextWriterTraceListener to update our file name...
if (_date?.Day != DateTime.Now.Day) { _listener = null; }
if (_listener == null)
{
System.Diagnostics.Trace.Listeners.Clear();
_fileName = $"{DateTime.Now.ToString("yyyy-MM-dd")}_Trace.json";
// Add a writer that appends to the trace.log file:
_listener = new System.Diagnostics.TextWriterTraceListener(_fileName);
_listener.IndentSize = 4;
_listener.TraceOutputOptions = System.Diagnostics.TraceOptions.None; // TraceOptions.DateTime | TraceOptions.ThreadId;
System.Diagnostics.Trace.AutoFlush = true;
System.Diagnostics.Trace.Listeners.Add(_listener);
// Obtain the Console's output stream, then add that as a listener...
System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out));
}

Categories