How to uniquely identify a computer using C# [duplicate] - c#

This is my old implementation to get a Unique DeviceID for Windows Universal 8.1 but the type HardwareIdentification does not exist anymore.
private static string GetId()
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
return BitConverter.ToString(bytes).Replace("-", "");
}

That is the complete solution for Windows Desktop:
Add the Extension reference "Windows Desktop Extensions for the UWP" like Peter Torr - MSFT mentioned.
Use this Code to get the HardwareId:
using System;
using Windows.Security.ExchangeActiveSyncProvisioning;
using Windows.System.Profile;
namespace Tobit.Software.Device
{
public sealed class DeviceInfo
{
private static DeviceInfo _Instance;
public static DeviceInfo Instance
{
get {
if (_Instance == null)
_Instance = new DeviceInfo();
return _Instance; }
}
public string Id { get; private set; }
public string Model { get; private set; }
public string Manufracturer { get; private set; }
public string Name { get; private set; }
public static string OSName { get; set; }
private DeviceInfo()
{
Id = GetId();
var deviceInformation = new EasClientDeviceInformation();
Model = deviceInformation.SystemProductName;
Manufracturer = deviceInformation.SystemManufacturer;
Name = deviceInformation.FriendlyName;
OSName = deviceInformation.OperatingSystem;
}
private static string GetId()
{
if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.System.Profile.HardwareIdentification"))
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
return BitConverter.ToString(bytes).Replace("-", "");
}
throw new Exception("NO API FOR DEVICE ID PRESENT!");
}
}
}

Update for Windows 1609 ("Anniversary Update")
See this Q&A for a much better way to get an ID.
Old info for older OS builds
You need to add a reference to the Desktop and / or Mobile SDKs to build against the Hardware Token. At runtime you should use the ApiInformation type to query if the API is present before using it (other device families like Xbox don't have it).
That said, many times when people ask for the device ID that's not actually the best solution for their problem -- are you sure you need to identify the physical device across its entire lifespan, even if ownership changes?

It seems that
var deviceInformation = new EasClientDeviceInformation();
string Id = deviceInformation.Id.ToString();
is doing the magic, refering to EasClientDeviceInformation it provides a unique Id.
The Id property represents the DeviceId using the GUID truncated from the first 16 bytes of the SHA256 hash of the MachineID, User SID, and Package Family Name where the MachineID uses the SID of the local users group.
BUT it only works for Windows Store Apps... so there have to be another solution.

EasClientDeviceInformation does not work for Windows 10 mobile. The device id is just the same for every phone (all our win10m customers gets registered with the same GUID) We need the id for sending push messages to the right phone.

//you can use this
//its working with me very fine on windows 10
//replace the word bios with any hardware name you want
//data also can be found with using windows application named (wbemtest)
using System.Management;
public static async Task<string> ReturnHardWareID()
{
string s = "";
Task task = Task.Run(() =>
{
ManagementObjectSearcher bios = new ManagementObjectSearcher("SELECT * FROM Win32_BIOS");
ManagementObjectCollection bios_Collection = bios.Get();
foreach (ManagementObject obj in bios_Collection)
{
s = obj["SerialNumber"].ToString();
break; //break just to get the first found object data only
}
});
Task.WaitAll(task);
return await Task.FromResult(s);
}

Related

Memory Leak in ConcurrentQueue<T>?

Hi I have a simple class in a .NET Core SDK -> 3.1.409 project for the communication with devices.
public class WriteCommand
{
//Commands is an enumeration.
public Commands LaserCommand { get; }
public List<byte> Parameter { get; }
public List<byte> Data { get; }
public WriteCommand(Commands laserCommand, byte[] parameter = null)
{
Data = BuildSendData(laserCommand, parameter);
Parameter = new List<byte>(parameter);
LaserCommand = laserCommand;
}
private List<byte> BuildSendData(Commands command, byte[] paramBytes)
{
var parameter = paramBytes ?? Array.Empty<byte>();
int numberOfBytes = parameter.Length + Constants.ADD_TO_PARAMETER; // Defined by protocol
List<byte> sendData = new List<byte>();
sendData.Add(Constants.PACKET_START_BYTE);
sendData.Add((byte)numberOfBytes);
sendData.Add(Constants.COMMAND_START_BYTE);
sendData.Add((byte)command);
foreach (var param in parameter)
{
sendData.Add(param);
}
sendData.Add(Constants.PACKET_END_BYTE);
byte checksum = new CheckSumCalculator().CalculateCheckSum(sendData);
sendData.Add(checksum);
return sendData;
}
}
I use this class to add to a ConcurrentQueue in one taks like this.
public void AddCommand()
{
commandsQueue.Enqueue(new WriteCommand(Commands.SetRs232BaudRate));
}
And in another task I get the command out of the ConcurrentQueue
public void SendAndReceiveMessages()
{
while (!commandsQueue.IsEmpty)
{
if (commandsQueue.TryDequeue(out WriteCommand writeCommand))
{
//Do something
}
}
}
In my progam I habe 6 devices to communicate within an interval of one second. Each device has it's own communication class.
When the program run for a while (more than 2 days) I see an increase of the needed memory.
I Check this with the a memory profiler and see a memory leak:
WriteCommand
ConcurrentQueueSegment+Slot
This is only articelI found.
You can find the example code here
Does anyone know this problem?
Greetings Mike

How to detect document and real hardware printers in .net? [duplicate]

I have a list of all printers available in WinXP. I need the code (ideally .NET) to filter out all the virtual printers from this list. Is it possible to do? I analyzed all the properties of Win32_Printer wmi class but can't see any suitable one.
I don't think it's possible, at least with any certainty. The whole point of a virtual printer is to imitate a real one as closely as possible, so any differences you can identify are basically just bugs in the virtual printer.
That said, you can make some guesses based on the PortName. Just for a couple of examples, a PortName that includes an IP address or starts with "USB" is likely to refer to a physical connection.
I know this is an old question but this answer may be helpful to someone with the same problem.
If my understanding of a "virtual printer" is correct. You could check the WMI property "PrintProcessor" and ignore "winprint". To my knowledge this will ignore all of Windows 7 software based printer options. Here is some sample code to demonstrate that. Returns the printer name.
using System.Management;
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_Printer");
foreach (ManagementObject obj in searcher.Get())
{
if(obj != null)
{
if(obj["PrintProcessor"].ToString().ToUpper() != "WINPRINT")
{
Console.WriteLine(obj["Name"]);
}
}
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
I have a project to collect hardware information
and after testing the HiTech answer I see some of old printers (for example HP 2014 on Windows 10) that connect with LPT have WINPRINT PrintProcessor and these printers are connected diectly to computer and not virtual. So I combined the Local, Network and PortName properties (on offer Jerry Coffin answer) to find more accurate local and network printers(not virtual printers).
using System.Management;
class Printer
{
public string Name { get; set; }
public string Status { get; set; }
public bool Default { get; set; }
public bool Local { get; set; }
public bool Network { get; set; }
public string PrintProcessor { get; set; }
public string PortName { get; set; }
}
private void btnGetPrinters_Click(object sender, EventArgs e)
{
List<Printer> printers = new List<Models.Printer>();
var query = new ManagementObjectSearcher("SELECT * from Win32_Printer");
foreach (var item in query.Get())
{
string portName = item["PortName"].ToString().ToUpper();
if (((bool)item["Local"]==true || (bool)item["Network"]==true) && (portName.StartsWith("USB") || portName.StartsWith("LPT")))
{
Printer p = new Models.Printer();
p.Name = (string)item.GetPropertyValue("Name");
p.Status = (string)item.GetPropertyValue("Status");
p.Default = (bool)item.GetPropertyValue("Default");
p.Local = (bool)item.GetPropertyValue("Local");
p.Network = (bool)item.GetPropertyValue("Network");
p.PrintProcessor = (string)item.GetPropertyValue("PrintProcessor");
p.PortName = (string)item.GetPropertyValue("PortName");
printers.Add(p);
}
}
// Show on GridView
gv.DataSource = printers;
}
This method works for the printers that connect with USB and LPT. I don't have any idea about other ports (like some faxes port).

Azure storage account throws HTTP 400 error when writing

I've developed a simple Azure Webapp with C#. And use the table of Azure storage account to save some kinds of records of the website.
It works well on my own computer on both read and write operations, with the real connection string. I can find the record with the "Azure Storage Explorer".
However, after I deploy the app. The cloud version keeps throwing Http 400 error when I try to write the table. But the read operation still works fine. (The local version is always OK.)
The problem is wierd. Please help me with it.
Thanks.
== UPDATE ==
The save & query code is something like this.
public class CodeSnippet: TableEntity
{
public string Title { get; set; }
public string Author { get; set; }
public string FileType { get; set; }
public string Code { get; set; }
public Guid Save()
{
var guid = Guid.NewGuid();
var datetime = DateTimeOffset.UtcNow;
this.RowKey = guid.ToString();
this.PartitionKey = datetime.ToString();
var json = JsonConvert.SerializeObject(this);
var client = AzureStorage.DefaultClient.Instance.GetTableClient();
var table = client.GetTableReference("privateshare");
var insertOp = TableOperation.Insert(this);
table.Execute(insertOp);
return guid;
}
public static CodeSnippet Query(Guid? guid)
{
if (guid == null)
{
return null;
}
var client = AzureStorage.DefaultClient.Instance.GetTableClient();
var table = client.GetTableReference("privateshare");
var query = new TableQuery<CodeSnippet>()
.Where(TableQuery.GenerateFilterCondition(
"RowKey", QueryComparisons.Equal, guid.ToString()))
.Take(1);
var res = table.ExecuteQuery(query);
return res?.First();
}
}
Problem solved.
The error occurs when I take DateTimeOffset.UtcNow.ToString() as the partition key.
After I change it to DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), it eventually works fine.
I don't know how & why the problem happens. But I guess the special characters in the "PartitionKey" may be the reason of the problem.

How do I get a Unique Identifier for a Device within Windows 10 Universal?

This is my old implementation to get a Unique DeviceID for Windows Universal 8.1 but the type HardwareIdentification does not exist anymore.
private static string GetId()
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
return BitConverter.ToString(bytes).Replace("-", "");
}
That is the complete solution for Windows Desktop:
Add the Extension reference "Windows Desktop Extensions for the UWP" like Peter Torr - MSFT mentioned.
Use this Code to get the HardwareId:
using System;
using Windows.Security.ExchangeActiveSyncProvisioning;
using Windows.System.Profile;
namespace Tobit.Software.Device
{
public sealed class DeviceInfo
{
private static DeviceInfo _Instance;
public static DeviceInfo Instance
{
get {
if (_Instance == null)
_Instance = new DeviceInfo();
return _Instance; }
}
public string Id { get; private set; }
public string Model { get; private set; }
public string Manufracturer { get; private set; }
public string Name { get; private set; }
public static string OSName { get; set; }
private DeviceInfo()
{
Id = GetId();
var deviceInformation = new EasClientDeviceInformation();
Model = deviceInformation.SystemProductName;
Manufracturer = deviceInformation.SystemManufacturer;
Name = deviceInformation.FriendlyName;
OSName = deviceInformation.OperatingSystem;
}
private static string GetId()
{
if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.System.Profile.HardwareIdentification"))
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
return BitConverter.ToString(bytes).Replace("-", "");
}
throw new Exception("NO API FOR DEVICE ID PRESENT!");
}
}
}
Update for Windows 1609 ("Anniversary Update")
See this Q&A for a much better way to get an ID.
Old info for older OS builds
You need to add a reference to the Desktop and / or Mobile SDKs to build against the Hardware Token. At runtime you should use the ApiInformation type to query if the API is present before using it (other device families like Xbox don't have it).
That said, many times when people ask for the device ID that's not actually the best solution for their problem -- are you sure you need to identify the physical device across its entire lifespan, even if ownership changes?
It seems that
var deviceInformation = new EasClientDeviceInformation();
string Id = deviceInformation.Id.ToString();
is doing the magic, refering to EasClientDeviceInformation it provides a unique Id.
The Id property represents the DeviceId using the GUID truncated from the first 16 bytes of the SHA256 hash of the MachineID, User SID, and Package Family Name where the MachineID uses the SID of the local users group.
BUT it only works for Windows Store Apps... so there have to be another solution.
EasClientDeviceInformation does not work for Windows 10 mobile. The device id is just the same for every phone (all our win10m customers gets registered with the same GUID) We need the id for sending push messages to the right phone.
//you can use this
//its working with me very fine on windows 10
//replace the word bios with any hardware name you want
//data also can be found with using windows application named (wbemtest)
using System.Management;
public static async Task<string> ReturnHardWareID()
{
string s = "";
Task task = Task.Run(() =>
{
ManagementObjectSearcher bios = new ManagementObjectSearcher("SELECT * FROM Win32_BIOS");
ManagementObjectCollection bios_Collection = bios.Get();
foreach (ManagementObject obj in bios_Collection)
{
s = obj["SerialNumber"].ToString();
break; //break just to get the first found object data only
}
});
Task.WaitAll(task);
return await Task.FromResult(s);
}

How to save ObservableCollection in Windows Store App?

I am creating Windows Store App based on Split App template. What is the best way to save data from SampleDataSource for later use?
I tried:
Windows.Storage.ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings;
roamingSettings.Values["Data"] = AllGroups;
It throws exception: 'Data of this type is not supported'.
RoamingSettings only supports the runtime data types (with exception of Uri); additionally, there's a limitation as to how much data you can save per setting and in total.
You'd be better off using RoamingFolder (or perhaps LocalFolder) for the storage aspects.
For the serialization aspect you might try the DataContractSerializer. If you have a class like:
public class MyData
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
public ObservableCollection<MyData> coll;
then write as follows
var f = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("data.txt");
using ( var st = await f.OpenStreamForWriteAsync())
{
var s = new DataContractSerializer(typeof(ObservableCollection<MyData>),
new Type[] { typeof(MyData) });
s.WriteObject(st, coll);
and read like this
using (var st = await Windows.Storage.ApplicationData.Current.LocalFolder.OpenStreamForReadAsync("data.txt"))
{
var t = new DataContractSerializer(typeof(ObservableCollection<MyData>),
new Type[] { typeof(MyData) });
var col2 = t.ReadObject(st) as ObservableCollection<MyData>;
}

Categories

Resources