Get a processes Private Working Set memory - c#

Trying to programmatically get the private working set of a process.
Currently I am able to get the working set without issue but having trouble getting the private working set.
Here's method:
private void GetProcessesForServer(string serverName)
{
var runningProcesses = new Process[0];
try
{
runningProcesses = Process.GetProcesses(serverName);
}
catch (Exception e)
{
ResultsPanel.Controls.Add(new Label { Text = string.Format("There was an error: {0}", e.GetBaseException().Message) });
}
IOrderedEnumerable<CustomProcess> processes = runningProcesses
.Select(process => new CustomProcess(process.Id, process.ProcessName, (process.WorkingSet64 / 1024)))
.ToList()
.OrderBy(process => process.ProcessName);
if (processes.Count() > 0)
ResultsLabel.Text = string.Format("Current running processes on {0}", ServerNamesDropDown.SelectedItem.Text);
ResultsGridView.DataSource = processes;
ResultsGridView.DataBind();
}
So I'm passing in a server name then trying to get all the running processes for that server then binding the list of processes to a grid view. Everything works without any issues however I need to get the private working set - similar to what you see in Windows Task manager - rather than the total working set.
Many thanks,
Tim

On Windows Vista and beyond there is the "Working Set - Private" performance counter in the "Process" category (see msdn).
Given you are on such a platform you could use the System.Diagonstics.PerformanceCounter class to query this information.
To establish a link between a process ID and a given performance counter instance, use the "ID Process" counter of a category. In other words: lookup the instance where the "ID Process" counter is your desired process ID, the read the value of the "Working Set - Private" counter.
Hint: if you need to query all values for all processes use the System.Diagonstics.PerformanceCounterCategory.ReadCategory() call instead, as it is much faster the reading individual counters for all processes/instances.
Update: There is an article on codeproject that shows how to calculate that value on XP/2000, if you must. I have not tested it, so don't blame me ;-)
Update 2: You may also want to checkout this stackoverflow question/answer.

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.

Is there a way to get WAN mini-port statistics in windows?

Is there code or API (either C++/C#) to get WAN mini-port statistics similar to status report when it is connected?
In UWP, you could use NetworkInformation.GetInternetConnectionProfile Method to get the connection profile associated with the internet connection currently used by the local machine, or you could use NetworkInformation.GetConnectionProfiles Method to get a list of profiles for connections, active or otherwise, on the local machine.
Then, you could use ConnectionProfile.GetNetworkUsageAsync Method to get a list of the estimated data traffic and connection duration over a specified period of time, for a specific network usage state.
After that, you could get the NetworkUsage's BytesReceived and BytesSent data.
I made a simple code sample for your reference:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
var usageStates = new NetworkUsageStates
{
Roaming = TriStates.DoNotCare,
Shared = TriStates.DoNotCare
};
var networkUsage = await internetConnectionProfile.GetNetworkUsageAsync(
DateTimeOffset.Now.AddDays(-1),
DateTimeOffset.Now,
DataUsageGranularity.Total,
usageStates);
foreach (var usage in networkUsage)
{
Debug.WriteLine(internetConnectionProfile.ProfileName+" Sent: "+usage.BytesSent+" Received: "+usage.BytesReceived);
}
}
From what I read, it looks like this is most easily accessed via performance counters.
The Network Adapter section in particular, lists out the juicy details for each network adapter.
There are many tutorials out there for reading performance counters in C#, but here's one I like: https://dotnetcodr.com/2017/03/29/reading-the-value-of-a-performance-counter-on-windows-with-c-net-3

how to get real time log via perforce api similar to p4v log

I am facing issue with perforce api (.net), as i am unable to pull sync logs in real time.
- What am I trying to do
I am trying to pull real time logs as Sync is triggered using the
Perforce.P4.Client.SyncFiles() command. Similar to the P4V GUI Logs, which update when we try to sync any files.
- What is happening now
As the output is generated only after the command is done execution its not something intended for.
Also tried looking into Perforce.P4.P4Server.RunCommand() which does provide detailed report but only after the execution of the command.
Looked into this
Reason is -
I am trying to add a status update to the Tool i am working on which shows which Perforce file is currently being sync'd.
Please advise. Thanks in Advance.
-Bharath
In the C++ client API (which is what P4V is built on), the client receives an OutputInfo callback (or OutputStat in tagged mode) for each file as it begins syncing.
Looking over the .NET documentation I think the equivalents are the P4CallBacks.InfoResultsDelegate and P4CallBacks.TaggedOutputDelegate which handle events like P4Server.InfoResultsReceived etc.
I ended up with the same issue, and I struggled quite a bit to get it to work, so I will share the solution I found:
First, you should use the P4Server class instead of the Perforce.P4.Connection. They are two classes doing more or less the same thing, but when I tried using the P4.Connection.TaggedOutputReceived events, I simply got nothing back. So instead I tried with the P4Server.TaggedOutputReceived, and there, finally, I got the TaggedOutput just like I wanted.
So, here is a small example:
P4Server p4Server = new P4Server(cwdPath); //In my case I use P4Config, so no need to set user or to login, but you can do all that with the p4Server here.
p4Server.TaggedOutputReceived += P4ServerTaggedOutputEvent;
p4Server.ErrorReceived += P4ServerErrorReceived;
bool syncSuccess=false;
try
{
P4Command syncCommand = new P4Command(p4Server, "sync", true, syncPath + "\\...");
P4CommandResult rslt = syncCommand.Run();
syncSuccess=true;
//Here you can read the content of the P4CommandResult
//But it will only be accessible when the command is finished.
}
catch (P4Exception ex) //Will be caught only when the command has failed
{
Console.WriteLine("P4Command failed: " + ex.Message);
}
And the method to handle the error messages or the taggedOutput:
private void P4ServerErrorReceived(uint cmdId, int severity, int errorNumber, string data)
{
Console.WriteLine("P4ServerErrorReceived:" + data);
}
private void P4ServerTaggedOutputEvent(uint cmdId, int ObjId, TaggedObject Obj)
{
Console.WriteLine("P4ServerTaggedOutputEvent:" + Obj["clientFile"]); //Write the synced file name.
//Note that I used this only for a 'Sync' command, for other commands, I guess there might not be any Obj["clientFile"], so you should check for that.
}

How to determine specific printer properties for a printer job?

I am working on some code that monitors the printer queue and then uses the event information to collect some specifics about the job, including # pages, orientation, whether or not it was color and how many copies were requested.
I catch the events using the code from Merrion Computing (which is now open source); which handles the interop.
In the case of Color, it is supposed to be stored in JOB_INFO_2.pDeviceMode.dmColor; however no matter how I submit the job (color or black and white using the printer properties printing from several apps, including word and adobe) it always indicates color. I debugged through that code directly, and the interop appears to be correct, so then I used the JobId from the event to query the print system via .NET with the code (below); and it contains exactly the same settings for copies and color.
int iJobId = e.PrintJob.JobId;
LocalPrintServer printServer = new LocalPrintServer();
PrintQueueCollection queueCollection = printServer.GetPrintQueues();
foreach (PrintQueue queue in queueCollection)
{
queue.Refresh();
if(queue.FullName.Equals(e.PrintJob.PrinterName,StringComparison.OrdinalIgnoreCase))
{
int? iPageCount;
PrintJobInfoCollection jobs = queue.GetPrintJobInfoCollection();
foreach(PrintSystemJobInfo job in jobs)
{
job.Refresh();
if(job.JobIdentifier==iJobId)
{
iPageCount = job.NumberOfPages;
}
}
//-- Found the Printer...
int? iCopyCount=queue.CurrentJobSettings.CurrentPrintTicket.CopyCount;
PageOrientation? eOrientation = queue.CurrentJobSettings.CurrentPrintTicket.PageOrientation;
OutputColor? eColor = queue.CurrentJobSettings.CurrentPrintTicket.OutputColor;
Debug.WriteLine("queue=" + queue.FullName + ", Copies=" + iCopyCount.Value + ",Color=" + eColor.ToString() + ", pagecount=" + "unk" /*iPageCount.Value*/ + ", Orientation=", eOrientation.ToString());
Debug.WriteLine("---");
}
}
Has anyone seen a reliable way to retrieve the number of copies and page count (preferably using .NET) for a specific printer job?
I
I did find this post describing the same type of problem, but there wasn't a resolution there.
Determine current print job color using C#
It should also be noted that the WMI Code from the above article also returns color.
I went in an enabled the eventlog for printing (http://www.papercut.com/kb/Main/LogPrintJobsInEventViewer). Looking at the details of the print event; the color setting is as expected "2", which indicates grayscale.
It is pretty clear that the windows subsystem is receiving the requested setting; however I have been unsuccessful to retrieve the value using WMI, System.Printing's namespace, or the interop from Merrion's print monitoring library where the values all indicate that the job is color with the correct number of pages and copies.
Is it possible to grab the spool file generated for this print to check that it is setting the dmColor setting itself?
The setting you are getting from the event log, 2, corresponds to DMCOLOR_COLOR not DMCOLOR_MONOCHROME so it seems the colour setting in the log thinks it is colour too.
It may be that the printer driver is being a bit sneaky in submitting the job as colour when it creates it but then sending a "set device settings" message in the spool that changes it to monochrome? If so there should be an SPT_DEVMODE record in the spool file.
Check this article for a spool file reader: http://www.codeproject.com/Articles/10586/EMF-Printer-Spool-File-Viewer
You need to refresh your jog until the flag IsSpooling becomes false.
for (int i = 0; i < jobs.Count(); i++)
{
try
{
int timeOut = 20000;
var jobInfo = jobs.ElementAt(i);
while (jobInfo.IsSpooling && timeOut > 0)
{
Thread.Sleep(100);
timeOut-=100;
jobInfo.Refresh();
} var pages = Math.Max(jobInfo.NumberOfPages,jobInfo.NumberOfPagesPrinted);
}
}

How do i reset the system cache of WLAN info?

I am trying to write a WLAN fingerprinting program using NativeWifi in C#. To do this i run a loop to get the wlan information many times and then later use matlab to average / analyze the data.
The problem is that i get all the same values, even as i move about the house, when the program is running. From the internet i've seen that there is a cache that stores the data of available networks. I was wondering if there is a system call which resets this cache.
I have also seen this using the cmd call
netsh wlan show networks mode=bssid
this gives me the same values until i open the available wifi networks in my OS and if i run it again after, it will give different values.
edit: This system will be for my use only, so i would be comfortable starting over on a linux platform if there is a known library that can handle this for me. I don't even know what to google to even get the information, though. Anything related to "network cache" takes me to help threads of unrelated topics...
I will provide the relevant part of my code below:
public void get_info_instance(StreamWriter file)
{
try
{
foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
Wlan.WlanBssEntry[] wlanBssEntries = wlanIface.GetNetworkBssList();
foreach (Wlan.WlanBssEntry network in wlanBssEntries)
{
int rss = network.rssi;
byte[] macAddr = network.dot11Bssid;
string tMac = "";
for (int i = 0; i < macAddr.Length; i++)
{
tMac += macAddr[i].ToString("x2").PadLeft(2, '0').ToUpper();
}
file.WriteLine("Found network: " + System.Text.ASCIIEncoding.ASCII.GetString(network.dot11Ssid.SSID).ToString());
file.WriteLine("Signal: " + network.linkQuality + "%");
file.WriteLine("BSS Type: " + network.dot11BssType + ".");
file.WriteLine("RSSID: " + rss.ToString());
file.WriteLine("BSSID: " + tMac);
file.WriteLine(" ");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Internally, netsh is powered by this API. What this means, is that calling netsh wlan show networks mode=bssid just returns the cache of the networks that showed up during the last scan. This is what you've discovered.
This means that in order to refresh this cache, you need to trigger a scan. If your C# library you are using includes it, you could make this happen on demand with a call to WlanScan. I am not sure which C# wrapper you are using, but it probably includes this function. When you get a scan complete notification (register with source WLAN_NOTIFICATION_SOURCE_ACM and look out for wlan_notification_acm_scan_list_refresh), the cache should be updated.
If you let me know which C# library you are using, maybe I can point you to the relevant functions.
You mentioned that opening the available networks causes the cache to refresh. This is because opening the available networks triggers a call to WlanScan.
Profiles are not relevant to the available network list -- profiles are what the Wlan service uses to keep track of which networks are configured on your machine -- deleting them does not make WlanSvc scan again. It may be a coincidence that deleting them happens to coincide with a scan, but it is more of a side effect than the designed usage.
edit: to subscribe to notifications using the Managed Wifi API you are using, this snippet should work:
wlanIface.WlanNotification += wlanIface_WlanNotification;
And the callback:
static void wlanIface_WlanNotification(Wlan.WlanNotificationData notifyData)
{
if (notifyData.notificationCode == (int)Wlan.WlanNotificationCodeAcm.ScanComplete)
{
Console.WriteLine("Scan Complete!");
}
}
You can test this by running this, then opening the available networks on Windows. You should see "Scan Complete" shortly after you open it each time. You can use a messagebox instead of Console.WriteLine if you prefer.
To trigger a scan yourself:
wlanIface.Scan();
for all
netsh wlan delete profile name=* i=*
you might not want to do it on all interfaces, and hard code the interface in there for faster result

Categories