Is it possible to get PC's # of physical USB ports? - c#

I'm trying to get number of physical USB ports of PC for different Windows operating systems. To start with it seemed like an easy task but now I'm getting desperate.
Maybe this question is not even valid since I don't know how USB ports are treated on hardware level.
I thought using WMI(C) and ManagementObjectSearcher would be the right path to take and it returned right values... on certain operating systems. Or that's what I thought.
For example, I tried the following:
// >wmic path win32_usbhub get name
private const string UsbProperty = "Name";
private const string UsbPath = "Win32_USBHub";
private const string UsbPortName = "USB ROOT HUB";
...
// Get USB Ports
public IEnumerable<string> GetUsbPorts()
{
// All from Win32_USBHub where name contains USB ROOT HUB
return GetManagementObjectValues(UsbProperty, UsbPath).Where(name =>
CultureInfo.CurrentCulture.CompareInfo.IndexOf(
name, UsbPortName, CompareOptions.IgnoreCase) >= 0);
}
.
// Query
private static IEnumerable<string> GetManagementObjectValues(
string properties, string path, Func<object, string> formatter = null)
{
var values = new List<string>();
string query = string.Format("SELECT {0} FROM {1}", properties, path);
var search = new ManagementObjectSearcher(query);
try
{
foreach (ManagementObject item in search.Get())
{
string value = string.Empty;
foreach (string property in properties.Split(',')
.Select(prop => prop.Trim()))
{
if (item[property] == null)
continue;
if (value.Length > 0)
value += " ";
if (formatter != null)
value += formatter(item[properties]);
value += item[property].ToString();
}
values.Add(value.TrimEnd());
}
}
catch (Exception e)
{
if (e is ManagementException)
Logger.Warn(string.Format(
"Can't extract {0} properties of {1}", properties, path), e);
else
Logger.Error(e);
}
return values.Count >= 1 ? values : new List<string> { DefaultValue };
}
This seemed to get me the right amount on Windows8 but on WindowsXP it was totally off.
Next, I tried (for example) the following. I noticed that on Win8 I have USB<number> as ExternalReferenceDesignator but on WinXP, there's plain USB as InternalReferenceDesignator and external is empty.
For XP this seemed to work just fine but then again on Win8 amount of ports was six (6). Actual port count is 3 and with docking station station seven (7).
// >wmic path Win32_PortConnector get ExternalReferenceDesignator,InternalReferenceDesignator
private const string UsbPortName = "USB";
private const string PortProperties =
"ExternalReferenceDesignator, InternalReferenceDesignator";
private const string PortPath = #"Win32_PortConnector";
...
public IEnumerable<string> GetEthernetPorts()
{
// All where external includes USB or internal equals USB
return GetManagementObjectValues(PortProperties, PortPath).Where(name =>
CultureInfo.CurrentCulture.CompareInfo.IndexOf(
name, UsbPortName, CompareOptions.IgnoreCase) >= 0 ||
string.Compare(name, UsbPortName, StringComparison.OrdinalIgnoreCase) == 0);
}
So is it even possible or am I just looking from the wrong place?

And to answer my own question: No, it's not possible.
WMIC query results for Win32_USBController (or some related path) might seem right but you can't draw any conclusions from them. Information about connectors aren't stored on the baseboard or any other location either.
For example an old Dell Latitude D830 with Windows XP SP3 has three (3) physical connectors but WMIC and USBView.exe shows results below:
C:\>wmic path win32_usbcontroller get caption
Caption
Intel(R) ICH8 Family USB Universal Host Controller - 2834
Intel(R) ICH8 Family USB Universal Host Controller - 2835
Intel(R) ICH8 Family USB2 Enhanced Host Controller - 283A
Intel(R) ICH8 Family USB Universal Host Controller - 2830
Intel(R) ICH8 Family USB Universal Host Controller - 2831
Intel(R) ICH8 Family USB Universal Host Controller - 2832
Intel(R) ICH8 Family USB2 Enhanced Host Controller - 2836

I know it has been a while since the question was asked, but I just happened to be working on a USB port tree for a support app of some sort.
Initially, I tried to use Win32..., as much as it is not intended to be used as a source of information for the rebuilding of the device tree, the answer of this post explains some possibilities (Get List of connected USB Devices).
I played with it but I did not like it. UsbView by itself was also not an option (lack of skill in C ). Luckily I found NativeUsbLib. It provides you with a USB device tree, you just need to understand how to read it. Not a physical USB port This image shows a port that clearly states it is not possible to use it. In addition to that parameter, there is "Companion Hub Symbolic Link Name", in my experience, it has to be present on a valid USB port.
As for multiple controllers, and even multiple ports in one controller that satisfy my previous statement, there is an explanation. Multiple ports for same physical port, in my case, ports 1 and 13 are the same. If a device is 1.1 or 2.0 it will show under port 1, and if it supports 3.0 it will show up under port 13. And same goes for two controllers, they don't have 100% the same structure, but once you strip unnecessary data, and merge data (not necessarily all of it) that is left, the result will be a USB port tree. I can't guarantee all of the statements are true, but that is my current experience, and I might update this post. If not, feel free to message me if you have some questions. Btw. NativeUsbLib by default does not provide data for ports that don't have a device present (plugged in). To fix that, comment out lines in DeviceFactory that check if the device is present (line 35).
Hope this helps someone and sorry for my spelling, I am sure I messed up somewhere...

Related

List all USB audio headsets connected to a Windows PC

I want to use C# to retrieve the USB headset devices connected to PC. I tried the below solutions but didn't work:
Solution 1:
How to enumerate audio out devices in c#
I tried this but the device name appears as "(Generic USB Audio)" and not the actual name.
Solution 2:
How to get the default audio device?
Solution 3:
Detecting Audio Input & output devices connected to system
Solution 2 and Solution 3 gave me the below result:
The device name is truncated to 31 characters.
Eg: "Microphone (Sennheiser VOICE 689"
****Question: Is there any way I can get the complete name of the device?****
If you know it's an USB audio device, and assuming the driver is correctly written for the device, you could do:
foreach (ManagementObject drive in
new ManagementObjectSearcher(
"select Name from Win32_USBDevice where Service='usbaudio'").Get())
{
{
string s = drive["Name"].ToString();
// Continue
}
}
Addition
You're only getting 31 characters (technically 32) because the PInvoke to the native .DLLs use a char[32], so it can't return more than that; you won't get what you need from solution 1 & 2.
Also, I don't know why you can't use Win32_USBDevice, as I'm also using Win7 x64 and I'm having no problems. This link might help you.
Possible Alternate
You might be able to use the Win32_PnPEntity class:
foreach (ManagementObject drive in
new ManagementObjectSearcher(
"select Name from Win32_PnPEntity where Service='usbaudio'").Get())
{
{
string s = drive["Name"].ToString();
// Continue. Can look at Description, Caption, etc. too
}
}

Retrieve host VM MAC address via guest VM

This has been an issue I have been looking to for two days. I will share my findings.
I am currently working on an in-house license management system for our software. It's nothing too fancy - as long as it can uniquely identify a user, it's good enough. Our mechanism currently relies on user sign-in + password + MAC address.
99% of the users so far have had no issues, but there is a small subset, the 1%, that has been returning an issue. This 1% is so important to us, because one failure means one hole in our system, something we would like to weed out. Okay - onto the main topic.
Method 1:
public static string returnMAC1()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select MACAddress, PNPDeviceID FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL AND PNPDEVICEID IS NOT NULL");
ManagementObjectCollection mObject = searcher.Get();
foreach (ManagementObject obj in mObject)
{
string pnp = obj["PNPDeviceID"].ToString();
if (pnp.Contains("PCI\\"))
{
string mac = obj["MACAddress"].ToString();
mac = mac.Replace(":", string.Empty);
return mac;
}
}
return "Nothing happened...";
}
Method 1 retrieves the MAC address based on the fact that the physical card is connected to the PCI interface.
Method 2:
public static string returnMAC2()
{
string mac = string.Empty;
foreach (System.Net.NetworkInformation.NetworkInterface nic in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces())
{
if (nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up)
{
macAddresses += nic.GetPhysicalAddress().ToString();
break;
}
}
return mac;
}
The second method is a standard method retrieved from MSDN documentation in-regards to MAC addresses.
Based on some tests, it seems the second method is a tad unreliable to retrieve MAC addresses, since it retrieves the wireless card's address. We've had some users returning null addresses as a result of using that method, and while I don't know why that would happen, it could be because there's a lack of a wireless card in their computers. With that said, that's only conjecture. Method #1 relies on using SQL queries to retrieve the PCI MAC. This one has been reliable.
Tests:
Using a Windows 8.1 Enterprise Evaluation edition (free 90-day trial, yay!) installed onto the VirtualBox VM, the tests confirmed that there are major differences in the MAC addresses returned via the guest VM and the host VM.
According to my research, in most cases, the virtual machine is assigned the same MAC address every time it is powered on, so long as the virtual machine is not moved and no changes are made to the certain settings in the configuration file. With that said, and here's the bad news... The guest VM MAC could be anything. So it seems, this is one of the reasons the MAC addresses are inconsistent when used as unique identifiers, which is an issue I found out when some users were on their company VMs. I never knew that's the way people worked, but here we are, so no gloating about it at this point.
My question is - is there any way, without making the user change any settings on their end, to retrieve the host VM's MAC as opposed to the guest VM?
At this point I don't see any reason why someone won't assign the same MAC to every single guest machine to get around our floating license mechanism. Retrieving the host VM MAC would get around this issue, as it would show as one MAC.
We decided this is both impossible and unnecessary. We also decided to use the motherboard UUID as the primary unique identifier, and falling back to the MAC address using the MAC address method below, in case the UUID returns a FFFF-FFFF....... on the rare occasion the vendor does not supply a UUID to that motherboard.
public static string returnMAC1()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select MACAddress, PNPDeviceID FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL AND PNPDEVICEID IS NOT NULL");
ManagementObjectCollection mObject = searcher.Get();
foreach (ManagementObject obj in mObject)
{
string pnp = obj["PNPDeviceID"].ToString();
if (pnp.Contains("PCI\\"))
{
string mac = obj["MACAddress"].ToString();
mac = mac.Replace(":", string.Empty);
return mac;
}
}
return "Nothing happened...";
}

How can I find what is OID for cpu usage in windows 7?

I have a vm with windows 7. I have installed windows snmp agent service.
Then from my pc I have developed a small program in C# to communicate with SNMP agent using snmpsharpnet and works!
I used some sample OIDs like:
.1.3.6.1.2.1.1.1.0 to get system description
.1.3.6.1.2.1.25.1.6. to get number of processes
So my program works and I have correct network connectivity.
string host = "192.168.1.92";
string community = "public";
SimpleSnmp snmp = new SimpleSnmp(host, community);
if (!snmp.Valid)
{
Console.WriteLine("SNMP agent host name/ip address is invalid.");
return;
}
Dictionary<Oid, AsnType> result = snmp.Get(SnmpVersion.Ver1, new string[] { ".1.3.6.1.2.1.25.3.3.1.2" });
if (result == null)
{
Console.WriteLine("No results received.");
Console.ReadKey();
return;
}
foreach (KeyValuePair<Oid, AsnType> kvp in result)
{
Console.WriteLine("{0}: {1} {2}", kvp.Key.ToString(),
SnmpConstants.GetTypeName(kvp.Value.Type),
kvp.Value.ToString());
}
Console.ReadKey();
}
Now I am trying to get cpu load using .1.3.6.1.2.1.25.3.3.1.2 but I doen't work (got info from here). I have also installed a Mib Browser (from ireasoning.com) to learn correct OIDs.
My questions are:
Which is correct OID to get CPU Load from windows 7?
OID are not common for all systems, aren't them? I mean linux, windows, routers have their own OIDs?
Where can I find OIDs for windows 7?
1.3.6.1.2.1.25.3.3.1.2 is part of the hrProcessorTable in the HOST-RESOURCES MIB. Using a tool like Mib Browser, do an SNMP Walk on the table OID, 1.3.6.1.2.1.25.3.3. Or, start on that OID and do an SNMP Next. If you for example have a dual-core CPU, the processor load for one of the cores may be in an OID like 1.3.6.1.2.1.25.3.3.1.2.1.

Is there really any way to uniquely identify any computer at all

I know there are a number of similar questions in stackoverflow such as the followings:
What's a good way to uniquely identify a computer?
What is a good unique PC identifier?
Unique computer id C#
WIN32_Processor::Is ProcessorId Unique for all computers
How to uniquely identify computer using C#?
... and dozens more and I have studied them all.
The problem is that some of the accepted answers have suggested MAC address as an unique identifier which is entirely incorrect. Some other answers have suggested to use a combination of various components which seems more logical. However, in case of using a combination it should be considered which component is naturally unlikely to be changed frequently. A few days ago we developed a key generator for a software licensing issue where we used the combination of CPUID and MAC to identify a windows pc uniquely and till practical testing we thought our approach was good enough. Ironically when we went testing it we found three computers returning the same id with our key generator!
So, is there really any way to uniquely identify any computer at all? Right now we just need to make our key generator to work on windows pc. Some way (if possible at all) using c# would be great as our system is developed on .net.
Update:
Sorry for creating some confusions and an apparently false alarm. We found out some incorrectness in our method of retrieving HW info. Primarily I thought of deleting this question as now my own confusion has gone and I do believe that a combination of two or more components is good enough to identify a computer. However, then I decided to keep it because I think I should clarify what was causing the problem as the same thing might hurt some other guy in future.
This is what we were doing (excluding other codes):
We were using a getManagementInfo function to retrieve MAC and Processor ID
private String getManagementInfo(String StrKey_String, String strIndex)
{
String strHwInfo = null;
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + StrKey_String);
foreach (ManagementObject share in searcher.Get())
{
strHwInfo += share[strIndex];
}
}
catch (Exception ex)
{
// show some error message
}
return strHwInfo;
}
Then where needed we used that function to retrieve MAC Address
string strMAC = getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress");
and to retrieve ProcessorID
string strProcessorId = getManagementInfo("Win32_Processor", "ProcessorId");
At this point, strMAC would contain more than one MAC address if there are more than one. To take only one we just took the first 17 characters (12 MAC digits and 5 colons in between).
strMAC = strMAC.Length > 17 ? strMAC.Remove(17) : strMAC;
This is where we made the mistake. Because getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress") was returning a number of extra MAC addresses that were really in use. For example, when we searched for MAC addresses in the command prompt by getmac command then it showed one or two MAC addresses for each pc which were all different. But getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress") returned four to five MAC addresses some of which were identical for all computers. As we just took the first MAC address that our function returned instead of checking anything else, the identical MAC addresses were taken in strMAC incidently.
The following code by Sowkot Osman does the trick by returning only the first active/ enabled MAC address:
private static string macId()
{
return identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
}
private static string identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
}
return result;
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
However, I was absolutely right about the identical Processor ID issue. All three returned the same Processor ID when we put wmic cpu get ProcessorId command in their command prompts.
Now we have decided to use Motherboard serial number instead of Processor ID to make a combination with MAC address. I think our purpose will be served with this way and if it doesn't in some cases then we should let it go in those few cases.
How about adding motherboard serial number as well e.g.:
using System.management;
//Code for retrieving motherboard's serial number
ManagementObjectSearcher MOS = new ManagementObjectSearcher("Select * From Win32_BaseBoard");
foreach (ManagementObject getserial in MOS.Get())
{
textBox1.Text = getserial["SerialNumber"].ToString();
}
//Code for retrieving Processor's Identity
MOS = new ManagementObjectSearcher("Select * From Win32_processor");
foreach (ManagementObject getPID in MOS.Get())
{
textBox2.Text = getPID["ProcessorID"].ToString();
}
//Code for retrieving Network Adapter Configuration
MOS = new ManagementObjectSearcher("Select * From Win32_NetworkAdapterConfiguration");
foreach (ManagementObject mac in MOS.Get())
{
textBox3.Text = mac["MACAddress"].ToString();
}
The fact in getting a globally unique ID is, only MAC address is the ID that will not change if you set up your system all over. IF you are generating a key for a specific product, the best way to do it is assigning unique IDs for products and combining the product ID with MAC address. Hope it helps.
I Completely agree with just the above comment.
For Software licensening, you can use:
Computer MAC Address (Take all if multiple NIC Card) + Your software Product Code
Most of the renowned telecom vendor is using this technique.
However, I was absolutely right about the identical Processor ID
issue. All three returned the same Processor ID when we put wmic cpu
get ProcessorId command in their command prompts.
Processor ID will be same if all the systems are running as virtual machines on the same hypervisor.
MAC ID seems fine. Only thing is users must be provided the option to reset the application, in case the MAC changes.
It looks like custom kitchen is the way for that.
SMBIOS UUID (motherboard serial) is not robust, but works fine in 99% cases. However some brands will set the same UUID for multiple computers (same production batch maybe). Getting it requires WMI access for the user (if he's not administrator), you can solve that by starting an external process asking administrator priviledges (check codeproject.com/Articles/15848/WMI-Namespace-Security)
Windows Product ID might be good, but I read it could be identical in some circumstances (https://www.nextofwindows.com/the-best-way-to-uniquely-identify-a-windows-machine)
Could someone clarify if the same Product ID (not product key) might be present on multiple computers ?
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid seems interesting. It's generated when installing Windows and if changed, it requires to reactivate Windows.
Mac Addresses are interresting but you can only take the first one or your unique ID will change when the interface is disabled, or when another network interface is added and appears first etc.
Hard Drive serial number is nice but when installing a ghost, it might also override the serial number from the original drive... And the HD serial is very easy to change.
The best might be to generate an ID with a combination of those machine identifiers and decide if the machine is the same by comparing those identifiers (ie if at least one Mac address + either SMBIOS UUID or Product ID is ok, accept)

How can I check for 3G, wifi, EDGE, Cellular Networks in Windows Phone 7?

How can I check for 3G, wifi, EDGE, Cellular Networks in Windows Phone 7 using C#?
If you can use the Mango (7.1) SDK, and if your scenario involves using sockets, there's a trivial way to get the NetworkInterfaceType/SubType information for the connection you just made:
NetworkInterfaceInfo netInterfaceInfo = socket.GetCurrentNetworkInterface();
var type = netInterfaceInfo.InterfaceType;
var subType = netInterfaceInfo.InterfaceSubtype;
No need to use the NetworkInterface.NetworkInterfaceType property (which notoriously takes up to 30sec to return); no need to trigger a hostname resolution just to determine the network type; no need to listen to network change events.
Of course, this works best in conjunction with DeviceNetworkInformation.IsNetworkAvailable or NetworkInterface.GetIsNetworkAvailable() - those calls return immediately whether you're on a network or not. If you are, you connect the socket first and ask questions when it's connected :-)
A final note: beware of Mango's DeviceNetworkInformation.IsWiFiEnabled - I thought it would return whether I was on a wifi network, but instead it returns whether wifi is turned on or off in the phone settings... not super useful.
take a look at phoney tools, they have class PhoneNetworking for this:
http://wildermuth.com/2011/03/05/Phoney_Tools_Updated_(WP7_Open_Source_Library)
its open source you can check the source code
As of the Mango release (beta 2 and RC), this information is now available but it requires you to actually make a connection, presumably because it doesn't check until something needs it.
You can either perform a DNS resolution (see below) or use the GetCurrentNetworkInterface WebRequest extension method, which will throw an InvalidOperationException if the request hasn't connected yet.
There are also some events to follow in the Microsoft.Phone.Net.NetworkInformation namespace, but I wouldn't be surprised if those events didn't fire until a connection was made.
Interestingly, it seems you can also prefer or require on a per-connection basis using the SetNetworkPreference and SetNetworkRequirement extension methods, though it doesn't go beyond wifi vs cellular.
DeviceNetworkInformation.ResolveHostNameAsync(
new DnsEndPoint("microsoft.com", 80),
new NameResolutionCallback(nrr =>
{
var info = nrr.NetworkInterface;
var type = info.InterfaceType;
var subType = info.InterfaceSubtype;
}), null);
The enumeration values for NetworkInterfaceType (wifi/gsm) and NetworkInterfaceSubType (edge/3g) are available on MSDN.
Without socket:
var currentList = new NetworkInterfaceList().Where(i => i.InterfaceState == ConnectState.Connected).Select(i => i.InterfaceSubtype);
if (currentList.Contains(NetworkInterfaceSubType.WiFi))
Debug.WriteLine("WiFi");
if (currentList.Intersect(new NetworkInterfaceSubType[]
{
NetworkInterfaceSubType.Cellular_EVDO,
NetworkInterfaceSubType.Cellular_3G,
NetworkInterfaceSubType.Cellular_HSPA,
NetworkInterfaceSubType.Cellular_EVDV,
}).Any())
Debug.WriteLine("3G");
if (currentList.Intersect(new NetworkInterfaceSubType[]
{
NetworkInterfaceSubType.Cellular_GPRS,
NetworkInterfaceSubType.Cellular_1XRTT,
NetworkInterfaceSubType.Cellular_EDGE,
}).Any())
Debug.WriteLine("2G");
Unfortunately the api's don't provide very limited information about the kind of network connection you have. You can tell if you are on 3G, Cellular or Ethernet (i.e. USB connection to PC) but that is all the information you get.
Check out this for more info Better way to check for an network connection on WP7
To get Network Data for windows phone app i.e it is connected to a ethernet, wifi or cellular network also getting the subtype i.e 2G or 3g network following program can be used.
Using Microsoft.Phone.Net.NetworkInformation
Using Microsoft.Phone.net.NetworkInfromation
var Newlist = new NetworkInterfaceList();
foreach (NetworkInterfaceInfo x in Newlist)
{
if(x.InterfaceState==ConnectState.Connected)
{
if(x.InterfaceSubtype.Equals(NetworkInterfaceSubType.WiFi))
{
Interface = x.InterfaceType.ToString();
SubInterface = x.InterfaceSubtype.ToString();
break;
}
else if(x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_EVDO) || x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_3G) || x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_HSPA) || x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_EVDV))
{
Interface = x.InterfaceType.ToString();
SubInterface= “3G Network”;
break;
}
else if(x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_GPRS) || x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_1XRTT) || x.InterfaceSubtype.Equals(NetworkInterfaceSubType.Cellular_EDGE))
{
Interface = x.InterfaceType.ToString();
SubInterface= “2G Network”;
break;
}
else
{
Interface = “Ethernet”;
SubInterface= “Unknown” ;
break;
}
}
else
{
Interface=”not connected”;
SubInterface=”unknown”;
}
Here, Interface and SubInterface gives the network information.

Categories

Resources