I'm trying to implement a function in my application that lists all the plugged in USB Mass Storage Devices in a computer.
My code works well when launching the application but my problem is that I want the box in my form to refresh automatically when a USB device is removed or attached.
Implementing DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE conditions should work but I get back a "DisconnectedContext was detected" exception.
I learned that I need to use a delegate and set an asyncronous call for this to work correctly.
Here's my code:
public void listUSB()
{
ManagementScope sc = new ManagementScope(wmiUsbList);
ObjectQuery query = new ObjectQuery("select * from Win32_DiskDrive " + "where InterfaceType='USB'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(sc, query);
ManagementObjectCollection result = searcher.Get();
foreach (ManagementObject obj in result)
{
if (obj["DeviceID"] != null)
{
usbListTextBox.AppendText(obj["Model"].ToString());
}
}
}
I'd really like to know how to apply a delegate to my method.
I also looked at this thread on MSDN which provides an excellent example, but as of that example I am not able to understand how to put the deviceList in a textbox.
I'm still Learning so if someone could be so kind to point me to the right direction on one or both of my questions, that would be greatly appreciated.
Thanks!
Try to use ManagementEventWatcher and assign an event handler to the EventArrived.
I don't know how to accomplish exactly this, but here is a watcher that listens to the print events:
string printQuery = "Select * From __InstanceCreationEvent Within 1 Where TargetInstance ISA 'Win32_PrintJob'";
string nspace = #"\\.\root\CIMV2";
var watcher = new ManagementEventWatcher(nspace, printQuery);
Hope it helps.
private usbListArrayDelegate mDeleg;
protected override void WndProc(ref Message m)
{
int devType;
base.WndProc(ref m);
switch (m.WParam.ToInt32())
{
case DBT_DEVICEARRIVAL:
devType = Marshal.ReadInt32(m.LParam, 4);
if (devType == DBT_DEVTYP_VOLUME)
{
// usb device inserted, call the query
mDeleg = new usbListArrayDelegate(usbListArray);
AsyncCallback callback = new AsyncCallback(usbListArrayCallback);
// invoke the thread that will handle getting the friendly names
mDeleg.BeginInvoke(callback, new object());
}
break;
case DBT_DEVICEREMOVECOMPLETE:
devType = Marshal.ReadInt32(m.LParam, 4);
if (devType == DBT_DEVTYP_VOLUME)
{
mDeleg = new usbListArrayDelegate(usbListArray);
AsyncCallback callback = new AsyncCallback(usbListArrayCallback);
// invoke the thread that will handle getting the friendly names
mDeleg.BeginInvoke(callback, new object());
}
break;
}
}
public ArrayList usbListArray()
{
ArrayList deviceList = new ArrayList();
manager = new UsbManager(); ==> about how to implement this please see http://www.codeproject.com/Articles/63878/Enumerate-and-Auto-Detect-USB-Drives
UsbDiskCollection disks = manager.GetAvailableDisks();
foreach (UsbDisk disk in disks)
{
deviceList.Add(disk);
}
return deviceList;
}
// delegate wrapper function for the getFriendlyNameList function
private delegate ArrayList usbListArrayDelegate();
// callback method when the thread returns
private void usbListArrayCallback(IAsyncResult ar)
{
string ArrayData = string.Empty;
// got the returned arrayList, now we can do whatever with it
ArrayList result = mDeleg.EndInvoke(ar);
int count = 0;
foreach (UsbDisk disk in result)
{
++count;
ArrayData += count + ") " + disk.ToString().
}
Related
I have written an api to get all external storage drives connected to my computer. But i am not able to detect hard disk drives.
private async Task GetAllDrivesConnected()
{
await Task.Run(() =>
{
var drives = DriveInfo.GetDrives();
lock (this.myUsbDriveListLock)
{
foreach (var aDrive in drives .Where(theDrive => theDrive.DriveType == DriveType.Removable && theDrive.IsReady))
{
DriveLetter_Array.Add(aDrive.Name);
}
}
string LatestPath = DriveLetter_Array.LastOrDefault();
this.SetCurrentUsbPath(LatestPath);
var DeviceMessageEventArgs = new DeviceMessageEventArgs { Drive = LatestPath, UsbAdded = true };
FireEventAddPathRemovePath(DeviceMessageEventArgs);
});
}
I am making use of WML queries to listen to device inserted event:
private async Task DeviceNotification()
{
await Task.Run(() =>
{
var InsertQuery = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2");
myInsertionWatcher = new ManagementEventWatcher(InsertQuery);
myInsertionWatcher.EventArrived += this.DeviceInsertedEvent;
myInsertionWatcher.Start();
var RemoveQuery = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 3");
myRemovalWatcher = new ManagementEventWatcher(RemoveQuery);
myRemovalWatcher.EventArrived += this.DeviceRemovedEvent;
myRemovalWatcher.Start();
});
}
Please try adding the wait for next event method after start
myInsertionWatcher.WaitForNextEvent();
It's not clear from your comment if you actually checked for other DriveTypes. If I run the following after having connected an external hard drive I get the output from the image:
DriveInfo.GetDrives().Where(d => d.IsReady)
As you can see it has DriveType Fixed, even if it's connected through a USB port.
You may want to change your foreach loop:
foreach (var aDrive in drives .Where(theDrive => theDrive.IsReady))
{
DriveLetter_Array.Add(aDrive.Name);
}
If you want to only see external hard drives, you may want to take a look at this answer
As a flightsim enthusiast, I'm making my own cockpit hardware. I interface this hardware with my computer(s) using the USB HID interface (HW based on PIC microcontrollers). All hardware has the same VID/PID, and the Product Descriptor string is "FMGS HW Device" (fyi: FMGS is the name of the Airbus A320 simulator software I'm using).
On startup, my application scans all the USB devices and only puts the ones with my "VID/PID/Product Descriptor" combination in a Dictionary. As key, I'm using the "DevicePath" that I retrieve via the PSP_DEVICE_INTERFACE_DETAIL_DATA structure with a call to SetupDiGetDeviceInterfaceDetail (setupapi.dll).
Below is a small code extract that shows the core of this operation - just so you get the idea:
// Retrieving the detailDataBuffer
SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero);
// Skip over cbsize (4 bytes) to get the address of the devicePathName
var pDevicePath = new IntPtr(detailDataBuffer.ToInt32() + 4);
// Get the String containing the devicePath
AddDevice(Marshal.PtrToStringAuto(pDevicePath));
This DevicePath has the following format:
\?\hid#vid_04d8&pid_003f#9&599cfdc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
Question 1:
I can clearly see the VID/PID part (vid_04d8&pid_003f) and the HidGuid (4d1e55b2-f16f-11cf-88cb-001111000030), but what is the part with "9&599cfdc&0&0000"? Is that unique for every device? With other words, isn't there a risk that 2 of my devices have exactly the same DevicePath?
Now I also want to detect if devices are connected/disconnected while the application is running. If device are disconnected, I need to remove them from my Dictionary. If devices are connected, I need to put them in my Dictionary and start communicating with them.
I'm using the "WMI method" (I know there is also a WM_DEVICECHANGE method in WndProc, not sure what is better?). Below is the code (not finished, but works so far).
private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
Debug.WriteLine($"DeviceInsertEvent");
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach(PropertyData p in instance.Properties )
{
Debug.WriteLine($"{p.Name} = {p.Value }");
}
Debug.WriteLine($"{instance.Properties["Dependent"].Value }");
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
Debug.WriteLine($"DeviceRemovedEvent");
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
foreach (PropertyData p in instance.Properties)
{
Debug.WriteLine($"{p.Name} = {p.Value }");
}
Debug.WriteLine($"{instance.Properties["Dependent"].Value}");
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true;
try
{
WqlEventQuery insertQuery = new WqlEventQuery();
insertQuery.EventClassName = "__InstanceCreationEvent";
insertQuery.WithinInterval = new TimeSpan(0, 0, 1);
insertQuery.Condition = #"TargetInstance ISA 'Win32_USBControllerdevice'";
ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent);
insertWatcher.Start();
WqlEventQuery removeQuery = new WqlEventQuery();
removeQuery.EventClassName = "__InstanceDeletionEvent";
removeQuery.WithinInterval = new TimeSpan(0, 0, 1);
removeQuery.Condition = #"TargetInstance ISA 'Win32_USBControllerdevice'";
ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery);
removeWatcher.EventArrived += new EventArrivedEventHandler(DeviceRemovedEvent);
removeWatcher.Start();
}
catch (Exception ex)
{
Debug.WriteLine($"backgroundWorker_DoWork Exception: {ex}");
}
while (true) ;
}
I am not a WMI expert, so I have honestly no clue what I'm doing (still learning) - just got the code from several google searches. I discovered that "instance.Properties["Dependent"].Value" gives me also some kind of DevicePath, with the below format.
\DESKTOP-HANS\root\cimv2:Win32_PnPEntity.DeviceID="HID\VID_04D8&PID_003F\9&2E7AE93E&0&0000"
I see the same VID/PID combination, and the unknown "9&2E7AE93E&0&0000" part that I asked for in Question 1. So basically, with some string-manipulations, I could reconstruct the same DevicePath that I'm using as the key in my Dictionary.
Question 2:
Is there another way to discover device connect/disconnect events that give me the same DevicePath as returned by SetupDiGetDeviceInterfaceDetail?
I have been continuing with the above concept, and it works as a charm. I changed the code in the below, and now my USB devices are nicely added or removed dynamically when my application is running. The "puzzling part" is in constructing the correct DevicePath format in the DeviceCreatedEvent and DeviceRemovedEvent.
_stringHidGuid is obtained in the constructer of my UsbServer. I need it a few times, so I created a private member for it. It is a string with the format (already added the '#' and curly brackets):
#{4d1e55b2-f16f-11cf-88cb-001111000030}
I use this to "construct" the DevicePath based on the "Dependent" value I'm getting from the WMI __InstanceCreationEvent and __InstanceDeletionEvent.
_DeviceArrivedWatcher and _DeviceRemovedWatcher are another 2 private members of type ManagementEventWatcher to keep the notifiers when initializing the code. _vid and _pid contain my VID and PID.
Below is the full code extract.
private void DeviceCreatedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
// Describes the logical device connected to the Universal Serial Bus (USB) controller.
string path = (string)instance.Properties["Dependent"].Value;
// Check if it is our device
int start = path.IndexOf($"HID\\\\VID_{_vid:X4}&PID_{_pid:X4}");
if (start != -1)
{
// Create the DevicePath to be used in UsbServer
path = path.Substring(start, path.Length - start - 1).Replace("\\\\", "#");
path = string.Concat("\\\\?\\", path, _stringHidGuid);
Debug.WriteLine($"DeviceCreatedEvent for {path}");
AddDevice(path);
}
}
private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
// Describes the logical device connected to the Universal Serial Bus (USB) controller.
string path = (string)instance.Properties["Dependent"].Value;
// Check if it is our device
int start = path.IndexOf($"HID\\\\VID_{_vid:X4}&PID_{_pid:X4}");
if (start != -1)
{
// Create the DevicePath to be used in UsbServer
path = path.Substring(start, path.Length - start - 1).Replace("\\\\", "#");
path = string.Concat("\\\\?\\", path, _stringHidGuid);
Debug.WriteLine($"DeviceRemovedEvent for {path}");
RemoveDevice(path);
}
}
private void AddDeviceArrivedHandler()
{
try
{
var scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true;
var q = new WqlEventQuery();
q.EventClassName = "__InstanceCreationEvent";
q.WithinInterval = new TimeSpan(0, 0, 1);
q.Condition = #"TargetInstance ISA 'Win32_USBControllerdevice'";
_deviceArrivedWatcher = new ManagementEventWatcher(scope, q);
_deviceArrivedWatcher.EventArrived += DeviceCreatedEvent;
_deviceArrivedWatcher.Start();
}
catch (Exception ex)
{
Debug.WriteLine($"AddDeviceArrivedHandler() Exception: {ex}");
if (_deviceArrivedWatcher != null)
_deviceArrivedWatcher.Stop();
}
}
private void AddDeviceRemovedHandler()
{
try
{
var scope = new ManagementScope("root\\CIMV2");
scope.Options.EnablePrivileges = true;
var q = new WqlEventQuery();
q.EventClassName = "__InstanceDeletionEvent";
q.WithinInterval = new TimeSpan(0, 0, 1);
q.Condition = #"TargetInstance ISA 'Win32_USBControllerdevice'";
_deviceRemovedWatcher = new ManagementEventWatcher(scope, q);
_deviceRemovedWatcher.EventArrived += DeviceRemovedEvent;
_deviceRemovedWatcher.Start();
}
catch (Exception ex)
{
Debug.WriteLine($"AddDeviceRemovedHandler() Exception: {ex}");
if (_deviceRemovedWatcher != null)
_deviceRemovedWatcher.Stop();
}
}
private void DeviceNotificationsStop()
{
try
{
if (_deviceArrivedWatcher != null)
_deviceArrivedWatcher.Stop();
if (_deviceRemovedWatcher != null)
_deviceRemovedWatcher.Stop();
}
catch (Exception ex)
{
Debug.WriteLine($"DeviceNotificationStop() Exception: {ex}");
throw;
}
}
For a best source of knowledge about this topic I can recommend USB Complete
The Developer's Guide book, USBView and HClient official MS samples on GitHub.
\?\hid#vid_04d8&pid_003f#9&599cfdc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} is a so called device interface path. Its format is not documented by MS (so could be changes at any time) and its not safe to parse it. Every device could provide several interfaces to interact with it. For example every USB HID device also have interface with GUID_DEVINTERFACE_USB_DEVICE - {A5DCBF10-6530-11D2-901F-00C04FB951ED}.
There are two main Win32 APIs exist to query for connected devices: SetupDi* (defined in SetupAPI.h) and CM_* (defined in cfgmgr32.h). You can also use WMI but I not familiar with it.
Regarding how to convert device interface path to VID/PID:
You can use CM_Get_Device_Interface_PropertyW (or SetupDiGetDevicePropertyW) with DEVPKEY_Device_InstanceId param to request "device instance identifier". After that you can open that device via CM_Locate_DevNodeW (or SetupDiGetClassDevsW) with device instance id that you got and query DEVPKEY_Device_HardwareIds (string list) property on it. And returned stuff you can parse because its documented:
Each interface has a device ID of the following form:
USB\VID_v(4)&PID_d(4)&MI_z(2)
Where:
v(4) is the 4-digit vendor code that the USB committee assigns to the vendor.
d(4) is the 4-digit product code that the vendor assigns to the device.
z(2) is the interface number that is extracted from the bInterfaceNumber field of the interface descriptor.
PS: Found WMI example code with VID/PID filtering for in a book I mentioned:
void FindDevice()
{
const String deviceIdString = #”USB\VID_0925&PID_150C”;
_deviceReady = false;
var searcher = new ManagementObjectSearcher(“root\\CIMV2”, “SELECT PNPDeviceID FROM Win32_PnPEntity”);
foreach (ManagementObject queryObj in searcher.Get()) {
if (queryObj[“PNPDeviceID”].ToString().Contains(deviceIdString)) {
_deviceReady = true;
}
}
}
I was wondering if there is a way to programmatically check how many messages are in a private or public MSMQ using C#? I have code that checks if a queue is empty or not using the peek method wrapped in a try/catch, but I've never seen anything about showing the number of messages in the queue. This would be very helpful for monitoring if a queue is getting backed up.
You can read the Performance Counter value for the queue directly from .NET:
using System.Diagnostics;
// ...
var queueCounter = new PerformanceCounter(
"MSMQ Queue",
"Messages in Queue",
#"machinename\private$\testqueue2");
Console.WriteLine( "Queue contains {0} messages",
queueCounter.NextValue().ToString());
There is no API available, but you can use GetMessageEnumerator2 which is fast enough. Sample:
MessageQueue q = new MessageQueue(...);
int count = q.Count();
Implementation
public static class MsmqEx
{
public static int Count(this MessageQueue queue)
{
int count = 0;
var enumerator = queue.GetMessageEnumerator2();
while (enumerator.MoveNext())
count++;
return count;
}
}
I also tried other options, but each has some downsides
Performance counter may throw exception "Instance '...' does not exist in the specified Category."
Reading all messages and then taking count is really slow, it also removes the messages from queue
There seems to be a problem with Peek method which throws an exception
If you need a fast method (25k calls/second on my box), I recommend Ayende's version based on MQMgmtGetInfo() and PROPID_MGMT_QUEUE_MESSAGE_COUNT:
for C#
https://github.com/hibernating-rhinos/rhino-esb/blob/master/Rhino.ServiceBus/Msmq/MsmqExtensions.cs
for VB
https://gist.github.com/Lercher/5e1af6a2ba193b38be29
The origin was probably http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/ but I'm not convinced that this implementation from 2008 works any more.
We use the MSMQ Interop. Depending on your needs you can probably simplify this:
public int? CountQueue(MessageQueue queue, bool isPrivate)
{
int? Result = null;
try
{
//MSMQ.MSMQManagement mgmt = new MSMQ.MSMQManagement();
var mgmt = new MSMQ.MSMQManagementClass();
try
{
String host = queue.MachineName;
Object hostObject = (Object)host;
String pathName = (isPrivate) ? queue.FormatName : null;
Object pathNameObject = (Object)pathName;
String formatName = (isPrivate) ? null : queue.Path;
Object formatNameObject = (Object)formatName;
mgmt.Init(ref hostObject, ref formatNameObject, ref pathNameObject);
Result = mgmt.MessageCount;
}
finally
{
mgmt = null;
}
}
catch (Exception exc)
{
if (!exc.Message.Equals("Exception from HRESULT: 0xC00E0004", StringComparison.InvariantCultureIgnoreCase))
{
if (log.IsErrorEnabled) { log.Error("Error in CountQueue(). Queue was [" + queue.MachineName + "\\" + queue.QueueName + "]", exc); }
}
Result = null;
}
return Result;
}
//here queue is msmq queue which you have to find count.
int index = 0;
MSMQManagement msmq = new MSMQManagement() ;
object machine = queue.MachineName;
object path = null;
object formate=queue.FormatName;
msmq.Init(ref machine, ref path,ref formate);
long count = msmq.MessageCount();
This is faster than you selected one.
You get MSMQManagement class refferance inside "C:\Program Files (x86)\Microsoft SDKs\Windows" just brows in this address you will get it. for more details you can visit http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx.
I had real trouble getting the accepted answer working because of the xxx does not exist in the specified Category error. None of the solutions above worked for me.
However, simply specifying the machine name as below seems to fix it.
private long GetQueueCount()
{
try
{
var queueCounter = new PerformanceCounter("MSMQ Queue", "Messages in Queue", #"machineName\private$\stream")
{
MachineName = "machineName"
};
return (long)queueCounter.NextValue();
}
catch (Exception e)
{
return 0;
}
}
The fastest method I have found to retrieve a message queue count is to use the peek method from the following site:
protected Message PeekWithoutTimeout(MessageQueue q, Cursor cursor, PeekAction action)
{
Message ret = null;
try
{
ret = q.Peek(new TimeSpan(1), cursor, action);
}
catch (MessageQueueException mqe)
{
if (!mqe.Message.ToLower().Contains("timeout"))
{
throw;
}
}
return ret;
}
protected int GetMessageCount(MessageQueue q)
{
int count = 0;
Cursor cursor = q.CreateCursor();
Message m = PeekWithoutTimeout(q, cursor, PeekAction.Current);
{
count = 1;
while ((m = PeekWithoutTimeout(q, cursor, PeekAction.Next)) != null)
{
count++;
}
}
return count;
}
This worked for me. Using a Enumarator to make sure the queue is empty first.
Dim qMsg As Message ' instance of the message to be picked
Dim privateQ As New MessageQueue(svrName & "\Private$\" & svrQName) 'variable svrnme = server name ; svrQName = Server Queue Name
privateQ.Formatter = New XmlMessageFormatter(New Type() {GetType(String)}) 'Formating the message to be readable the body tyep
Dim t As MessageEnumerator 'declared a enumarater to enable to count the queue
t = privateQ.GetMessageEnumerator2() 'counts the queues
If t.MoveNext() = True Then 'check whether the queue is empty before reading message. otherwise it will wait forever
qMsg = privateQ.Receive
Return qMsg.Body.ToString
End If
If you want a Count of a private queue, you can do this using WMI.
This is the code for this:
// You can change this query to a more specific queue name or to get all queues
private const string WmiQuery = #"SELECT Name,MessagesinQueue FROM Win32_PerfRawdata_MSMQ_MSMQQueue WHERE Name LIKE 'private%myqueue'";
public int GetCount()
{
using (ManagementObjectSearcher wmiSearch = new ManagementObjectSearcher(WmiQuery))
{
ManagementObjectCollection wmiCollection = wmiSearch.Get();
foreach (ManagementBaseObject wmiObject in wmiCollection)
{
foreach (PropertyData wmiProperty in wmiObject.Properties)
{
if (wmiProperty.Name.Equals("MessagesinQueue", StringComparison.InvariantCultureIgnoreCase))
{
return int.Parse(wmiProperty.Value.ToString());
}
}
}
}
}
Thanks to the Microsoft.Windows.Compatibility package this also works in netcore/netstandard.
The message count in the queue can be found using the following code.
MessageQueue messageQueue = new MessageQueue(".\\private$\\TestQueue");
var noOFMessages = messageQueue.GetAllMessages().LongCount();
Scenario
One windows service polls a url every two minutes to retrieve certain data.
If any data has been added since the previous call, the data is retrieved and stored otherwise the loop carries on.
Issue
Sometimes a request takes more than two minutes to return a response.
When this happens, the next request is still made and finds new data, since the previous request hasn't return a response yet
This results in duplicate entries when the data is stored.
What I've tried
I tried to handle that by using a boolean like so:
Boolean InProgress = true;
foreach (var item in Lists)
{
\\Make a request and return new data (if any)
InProgress = false;
if (InProgress = false)
{
\\Store new data
}
}
This doesn't solve the issue. I believe I'm using the boolean in wrong place, but I'm not sure where it should.
This is the loop that makes the request and store the data
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
Data getCredentials = new Data();
DataTable credentials = getCredentials.loadCredentials();
Boolean InProgress = true;
for (int i = 0; i < credentials.Rows.Count; i++)
{
if (credentials != null)
{
var PBranchID = (int)credentials.Rows[i]["PortalBranchID"];
var negRef = (int)credentials.Rows[i]["NegotiatorRef"];
var Username = credentials.Rows[i]["Username"].ToString();
var Password = credentials.Rows[i]["Password"].ToString();
var Domain = credentials.Rows[i]["Domain"].ToString();
var FooCompanyBaseUrl = "https://" + Domain + ".FooCompany.com/";
Data getCalls = new Data();
DataTable calls = getCalls.loadCalls(PBranchID);
//If it's not the first call
if (calls != null && calls.Rows.Count > 0)
{
//Makes a call
DateTime CreatedSince = DateTime.SpecifyKind((DateTime)calls.Rows[0]["LastSuccessOn"], DateTimeKind.Local);
string IssueListUrl = FooCompany.WebApi.V2.URLs.Issues(BaseUrl, null, CreatedSince.ToUniversalTime(), null);
FooCompany.WebApi.V2.DTO.PrevNextPagedList resultIssueList;
resultIssueList = FooCompany.WebApi.Client.Helper.Utils.Getter<Foocompany.WebApi.V2.DTO.PrevNextPagedList>(IssueListUrl, Username, Password);
InProgress = false;
if (InProgress == false)
{
if (resultIssueList.Items.Count > 0)
{
//If call returns new issues, save call
Data saveCalls = new Data();
saveCalls.saveCalls(PBranchID);
foreach (var item in resultIssueList.Items)
{
var Issue = FooCompany.WebApi.Client.Helper.Utils.Getter<FooCompany.WebApi.V2.DTO.Issue>(item, Username, Password);
string TenantSurname = Issue.Surname;
string TenantEmail = Issue.EmailAddress;
Data tenants = new Data();
int tenantPropRef = Convert.ToInt32(tenants.loadTenantPropRef(PBranchID, TenantSurname, TenantEmail));
Data Properties = new Data();
DataTable propAddress = Properties.loadPropAddress(PBranchID, tenantPropRef);
var Address1 = propAddress.Rows[0]["Address1"];
var Address2 = propAddress.Rows[0]["Address2"];
var AddressFolder = Address1 + "," + Address2;
if (!Directory.Exists("path"))
{
Directory.CreateDirectory("path");
}
string ReportPDFDestination = "path";
if (File.Exists(ReportPDFDestination))
{
File.Delete(ReportPDFDestination);
}
FooCompany.WebApi.Client.Helper.Utils.DownloadFileAuthenticated(FooCompany.WebApi.V2.URLs.IssueReport(BaseUrl, Issue.Id), Username, Password, ReportPDFDestination);
//Store data
}
IssueListUrl = resultIssueList.NextURL;
}
}
}
else
{
continue;
}
}
}
catch (Exception ex)
{
//write to log
}
}
Question
I'm sure there is a better way than a boolean.
Could anyone advice a different method to handle the issue properly?
Thanks.
Solution
I ended up using a combination of both Thomas and Mason suggestions. I wrapped a lock statement around the main function of my windows service and used a boolean inside the function section that makes the call to the remote server.
Tested many times and it's error free.
You seems to have a problem of synchronisation, just surround the code that iterate though the List with a lock, and you will be fine.
public class MyClass{
private readonly object internalLock= new object();
private bool AlreadyRunning { get; set; }
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if(AlreadyRunning){
return;
}
try{
lock(internalLock){
Thread.MemoryBarrier();
if(AlreadyRunning){
return;
}
AlreadyRunning = true;
...Do all the things...
}
}
catch(Exception e){
..Exception handling
}
finally
{
AlreadyRunning = false;
}
}
bool InProgress=false;
void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if(!InProgress)
{
InProgress=true;
//retrieve data
InProgress=false;
}
}
Your InProgress variable needs to be declared outside the event handler. When you enter the method, check to see if it's already running. If it is, then we do nothing. If it's not running, then we say it's running, retrieve our data, then reset our flag to say we've finished running.
You'll probably need to add appropriate locks for thread safety, similar to Thomas's answer.
How can I get a process send/receive bytes? the preferred way is doing it with C#.
I've searched this a lot and I didn't find any simple solution for this. Some solutions suggested to install the WinPCap on the machine and to work with this lib.
Like this guy asked: Need "Processes with Network Activity" functionality in managed code - Like resmon.exe does it
I don't want the overhead of the lib.
Is there a simple solution for this?
Actually I want the exactly data that the Resource Monitor of Windows gives under the "Processes with Network Activity" tab:
How does the Resource Monitor of Windows gets this information?
Any example?
Also, tried to use the counter method which is mentioned over here:
Missing network sent/received
but with no success - as not every process is shown under this counter.
And again I'm wondering how the Resource Monitor gets this information even without using this counter...
Resource monitor uses ETW - thankfully, Microsoft have created a nice nuget .net wrapper to make it easier to use.
I wrote something like this recently to report back my process's network IO:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
namespace ProcessMonitoring
{
public sealed class NetworkPerformanceReporter : IDisposable
{
private DateTime m_EtwStartTime;
private TraceEventSession m_EtwSession;
private readonly Counters m_Counters = new Counters();
private class Counters
{
public long Received;
public long Sent;
}
private NetworkPerformanceReporter() { }
public static NetworkPerformanceReporter Create()
{
var networkPerformancePresenter = new NetworkPerformanceReporter();
networkPerformancePresenter.Initialise();
return networkPerformancePresenter;
}
private void Initialise()
{
// Note that the ETW class blocks processing messages, so should be run on a different thread if you want the application to remain responsive.
Task.Run(() => StartEtwSession());
}
private void StartEtwSession()
{
try
{
var processId = Process.GetCurrentProcess().Id;
ResetCounters();
using (m_EtwSession = new TraceEventSession("MyKernelAndClrEventsSession"))
{
m_EtwSession.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP);
m_EtwSession.Source.Kernel.TcpIpRecv += data =>
{
if (data.ProcessID == processId)
{
lock (m_Counters)
{
m_Counters.Received += data.size;
}
}
};
m_EtwSession.Source.Kernel.TcpIpSend += data =>
{
if (data.ProcessID == processId)
{
lock (m_Counters)
{
m_Counters.Sent += data.size;
}
}
};
m_EtwSession.Source.Process();
}
}
catch
{
ResetCounters(); // Stop reporting figures
// Probably should log the exception
}
}
public NetworkPerformanceData GetNetworkPerformanceData()
{
var timeDifferenceInSeconds = (DateTime.Now - m_EtwStartTime).TotalSeconds;
NetworkPerformanceData networkData;
lock (m_Counters)
{
networkData = new NetworkPerformanceData
{
BytesReceived = Convert.ToInt64(m_Counters.Received / timeDifferenceInSeconds),
BytesSent = Convert.ToInt64(m_Counters.Sent / timeDifferenceInSeconds)
};
}
// Reset the counters to get a fresh reading for next time this is called.
ResetCounters();
return networkData;
}
private void ResetCounters()
{
lock (m_Counters)
{
m_Counters.Sent = 0;
m_Counters.Received = 0;
}
m_EtwStartTime = DateTime.Now;
}
public void Dispose()
{
m_EtwSession?.Dispose();
}
}
public sealed class NetworkPerformanceData
{
public long BytesReceived { get; set; }
public long BytesSent { get; set; }
}
}
You can use PerformanceCounter. Sample code:
//Define
string pn = "MyProcessName.exe";
var readOpSec = new PerformanceCounter("Process","IO Read Operations/sec", pn);
var writeOpSec = new PerformanceCounter("Process","IO Write Operations/sec", pn);
var dataOpSec = new PerformanceCounter("Process","IO Data Operations/sec", pn);
var readBytesSec = new PerformanceCounter("Process","IO Read Bytes/sec", pn);
var writeByteSec = new PerformanceCounter("Process","IO Write Bytes/sec", pn);
var dataBytesSec = new PerformanceCounter("Process","IO Data Bytes/sec", pn);
var counters = new List<PerformanceCounter>
{
readOpSec,
writeOpSec,
dataOpSec,
readBytesSec,
writeByteSec,
dataBytesSec
};
// get current value
foreach (PerformanceCounter counter in counters)
{
float rawValue = counter.NextValue();
// display the value
}
And this is to get performance counters for the Network card. Note it is not process specific
string cn = "get connection string from WMI";
var networkBytesSent = new PerformanceCounter("Network Interface", "Bytes Sent/sec", cn);
var networkBytesReceived = new PerformanceCounter("Network Interface", "Bytes Received/sec", cn);
var networkBytesTotal = new PerformanceCounter("Network Interface", "Bytes Total/sec", cn);
Counters.Add(networkBytesSent);
Counters.Add(networkBytesReceived);
Counters.Add(networkBytesTotal);
Have a look at the IP Helper API. There is an implementation in C# by Simon Mourier that sums transferred bytes per process: https://stackoverflow.com/a/25650933/385513
It would be interesting to know how this compares with Event Tracing for Windows (ETW)...