SMBIOS - Get SPD (Serial Presence Detect) Modules Information C# - c#

I searched a lot but did not find any working codes getting SPD tables information via C#. Out there there are lots of softwares which get this info but HOW?
as shown in the image, for RAM devices, you can see Manufacture's name which can not be retrieve at all by WMI etc
If there is a DLL for using in C# will be perfect also
After some Research found this:
https://github.com/sapozhnikovay/SMBIOS
but it can not read table 17 to get memory device information.

Once I was researching about this, you need to get this information through SMBUS (not SMBIOS). But you need to create a driver (WDM in C/C++) to access this information.

Make sure you have added System.Management as a reference.
Here is a string that will return almost any information you want from the component :
private string getComponent(string hwClass, string syntax)
{
ManagementObjectSearcher mos = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM " + hwClass);
foreach (ManagementObject mj in mos.Get())
{
return Convert.ToString(mj[syntax]);
}
return null;
}
Using the string would look like this, say on a button click :
label1.Text = getComponent("Win32_PhysicalMemory", "SerialNumber");
I tested it and it returned a serial number, you can also look at the list of things you can put in like manufacturer, name, capacity etc.
I got all of this information from this YouTube video.
You can find all of the devices and their properties here (CPU, GPU, etc.)

Related

Retrieve formatted performance data from WMI

I'm writing a WMI Provider and I've managed to retrieve all info on the Computer System and Hardware Classes but cannot get data I want from the Performance Counter Classes. (Win32 Classes)
Looking through the MSDN documentation and using examples they provide, I've come up with a shell script that should return all properties of the Win32_PerfFormattedData abstract base class.
Script:
$osClass = New-Object System.Management.ManagementClass Win32_PerfFormattedData
$osClass.Options.UseAmendedQualifiers = $true
# Get the Properties in the class
$properties = $osClass.Properties
"This class has {0} properties as follows:" -f $properties.count
# display the Property name, description, type, qualifiers and instance values
foreach ($property in $properties) {
"Property Name: {0}" -f $property.Name
"Description: {0}" -f $($property.Qualifiers["Description"].Value)
"Type: {0}" -f $property.Type
"-------"
}
(referenced from here)
The problem is that I'm only retrieving the properties from it's base class Win32_Perf
EDIT
After doing more research, I found this on MSDN:
The WMI formatted class name for a counter object is of the form "Win32_PerfFormattedData_service_name_object_name"
I am trying to get the service_name's that are in the Win32_PerfFormattedData and the object_name's within those services.
I'm unsure whether getting the properties is how I want to go about this now but I cannot find any documentation to get the services. Are they the same thing? And, if not, how can I get the info I require? (service_name's & object_name's)
I've also tried this in some C# code and get the same result:
ManagementClass processClass = new ManagementClass();
processClass.Path = new ManagementPath("Win32_PerfFormattedData");
PropertyDataCollection properties = processClass.Properties;
Console.WriteLine("\nProperties:");
foreach (PropertyData property in properties)
{
Console.WriteLine(property.Name);
}
And I tried retrieving the methods to check if that is what I wanted but nothing is returned:
Console.WriteLine("Methods: ");
foreach (MethodData method in methods)
{
Console.WriteLine(method.Name);
}
EDIT 2
Is there another way to retrieve this data? I've looked all through the MSDN documentation on the WMI and I think to get the information I want, I have to access that class (Win32_PerfFormattedData). Sorts of values I want to retrieve:
CPU
RAM
Drives (SSD/HDD)
Processes
OS
GPU
I've retrieved a few classes that will give basic information about some of these but will not provide up to date data on, for example, the temperature of each logical processor. I've managed to get 1 service from the class Win32_PerfFormattedData_PerfOS_Processor which provides the load % of each logical processor but that class must holds other services which I need.
Win32_PerfFormattedData_* classes are located under the "root\cimv2" namespace. To enumerate these classes (and get the service names) you run the following WQL query against that namespace:
SELECT * FROM meta_class WHERE __Class LIKE "Win32_PerfFormattedData%"
Actually you can omit the namespace (at least with ManagementObjectSearcher) in which case the search occurs everywhere. Here is how to search through WMI with C#:
void SearchWmi()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM meta_class WHERE __Class LIKE \"Win32_PerfFormattedData%\"");
foreach (ManagementClass wmiClass in searcher.Get())
{
Console.WriteLine(wmiClass["__CLASS"].ToString());
}
}
You need to add referece to System.Management as well as the corresponding using directive.
You could find performance data about the:
CPU: Win32_PerfFormattedData_Processor
RAM: Win32_PerfFormattedData_Memory
OS: Win32_PerfFormattedData_System
Drives: Win32_PerfFormattedData_PerfDisk_*
Processes: Win32_PerfFormattedData_PerfProc_*
I have no idea about the GPU. Most likely it is driver dependent.
There are numerous WMI explorer tools out there with a UI and all the good stuff. Have you tried some? I use the "WMI Explorer 2.0"
You can download it from here

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
}
}

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)

Get list of audio devices and select one using c#

Hi I am creating a desktop based application in windows using C#.
I have to show list of all available audio & video devices in 2 different combo boxes.
Selecting any device from combo box will set that particular device as the default one
I am using WMI.
Code to get list of available audio devices:
ManagementObjectSearcher mo =
new ManagementObjectSearcher("select * from Win32_SoundDevice");
foreach (ManagementObject soundDevice in mo.Get())
{
String deviceId = soundDevice.GetPropertyValue("DeviceId").ToString();
String name = soundDevice.GetPropertyValue("Name").ToString();
//saving the name and device id in array
}
if i try to set the device like this:
using (RegistryKey audioDeviceKey =
Registry.LocalMachine.OpenSubKey(audioDevicesReg
+ #"\" + audioDeviceList.SelectedText.ToString(), true)){}
i get exception :
System.Security.SecurityException occurred in mscorlib.dll
Now I have few questions:
1) How to set the selected device as the default audio device?
2) The array contains device name as : "High Definition audio device"
even when I have attached a headset.
3) I want the list as speaker,headset etc...How to get that?
can anybody point me in the right direction?
There is no documented mechanism for changing the default audio device.
That's because you're enumerating the physical audio devices, not the audio endpoints.
You want to use the IMMDeviceEnumerator API to enumerate the audio endpoints (speakers, etc).
Unfortunately there is no managed interop published by Microsoft for the IMMDeviceEnumerator API, you'll need to define your own (there are several definitions available on the internet).
I am answering too late to this question.. but it may be helpful for others.
Lync 2013 SDK provides DeviceManager class which list all the audio and video devices in collections
LyncClient.GetClient().DeviceManager.AudioDevices enumerates all the audio devices on the system
LyncClient.GetClient().DeviceManager.VideoDevices enumerates all the video devices on the system
So, one can set the device as:
LyncClient client = LyncClient.GetClient();
DeviceManager dm = client.DeviceManager;
dm.ActiveAudioDevice = (AudioDevice)dm.AudioDevices[0]; //or any other found after foreach
dm.ActiveVideoDevice = (VideoDevice)dm.VideoDevices[0]; //or any other found after foreach
HTH.

How should I using C# to read partition table/boot sector?

Hi i'v look through the WMI class... but none can help me in getting the partition table information... now i'm having a project which is to display the USB thumbdrive's .MBR how should i go about it? really puzzle... Any help and guide will be very much appreciated!
p.s. the code can only be written in C#
Edit
Thank you! I've browse through the CreateFile documentation... Still wondering how should I use P/Invoke to call CreateFile and to read the boot sector( display out the .MBR )? Do you have any reference code for this portion? Thank you once again!!
If you want you can use WMI to get information about any drive. To do this you need to query the corresponding WMI classes. With C# you must add these references:
System.Management
and using statements:
using System.Management;
To get disk info for which are attached to your computer you can use this query:
Select * From Win32_DiskDrive
with C#, you can query like:
SelectQuery wmi_sorgusu = new SelectQuery("Select * from Win32_DiskDrive");
ManagementObjectSearcher wmi_bulucu = new ManagementObjectSearcher( wmi_sorgusu );
foreach (ManagementObject wmi_nesne in wmi_bulucu.Get()) {
Console.WriteLine(wmi_nesne.GetPropertyValue( "DeviceID" ).ToString());
Console.WriteLine(wmi_nesne.GetPropertyValue( "InterfaceType" ).ToString());
Console.WriteLine(wmi_nesne.GetPropertyValue( "Caption" ).ToString());
Console.WriteLine(wmi_nesne.GetPropertyValue( "Status" ).ToString());
Console.WriteLine(wmi_nesne.GetPropertyValue( "MediaLoaded" ).ToString());
//... etc
}
After getting the device parameters, you can use the same method to query Win32_DiskPartition WMI Class. You can give the device parameters to SELECT query as WHERE clause. Queries to Win32_DiskPartition returns all the partitions of all drives attached to system.
If you're prepared to parse the raw information yourself, you can use P/Invoke to call CreateFile. If your user account has enough mojo, you can open the raw disk device by passing it a string, something like "\\.\PHYSICALDRIVE0". See the documentation for CreateFile for more details.
To be honest, I would be very much surprised if you can't open it with IO.FileStream with the same magic path.
Indeed C# FileStream cannot open physical device directly:
Unhandled Exception: System.ArgumentException: FileStream will not
open Win32 devices such as disk partitions and tape drives. Avoid use
of "\.\" in the path.

Categories

Resources