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).
Related
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);
}
Step 1: I have created a C# application called : Student details
Step 2: Added four TextBoxes and named them as :
Image below to refer:
Studentname.Text
StudentSurname.Text
StudentCity.Text
StudentState.Text
DATA INSIDE CSV FILE
vikas,gadhi,mumbai,maharashtra
prem,yogi,kolkata,maha
roja,goal,orissa,oya
ram,kala,goa,barka
Issue is How do I fetch all the data(surname,city,state) of user prem into above textboxes studentsurname,studentcity,studentstate from csv file when I search the name in textbox 1 => studentname.Text as prem
Below is the Code where I am stuck at return null and code inside Load_Script_Click
void Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
}
}
return;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Connection_fetch_details cd = Connection_fetch_details(con_env);
textusername.Text = cd.username;
}
==============================================================
Class file name : Address.class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DDL_SCRIPT_GENERATOR
{
public class Connection_fetch_details
{
public string username { get; set; }
}
}
The main problem is that your method is void, which means it doesn't return any value. So even though you may be finding a match, and creating a Connection_fetch_details object, you aren't returning that result back to the calling method.
This will fix that problem:
Connection_fetch_details Connection_fetch_details(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
if (line.Split(',')[0].Equals(searchName))
{
Connection_fetch_details cd = new Connection_fetch_details()
{
username = line.Split(',')[1]
};
return cd; //return the object containing the matched username
}
}
return null;
}
Now it will return a Connection_fetch_details object if there is a match, or null if there is no match.
Next, you asked about returning all the fields, not just one. For that you would need to
a) add more properties to your object
b) add more code to populate those properties from the CSV
c) add code to populate the textboxes with the results from the object.
I'm also going to rename "username" to something more relevant, since none of the field names you described in the question match that. I'm also going to rename your class to "Student", and rename your search method, for the same reason.
Here's an example:
Student searchStudent(String searchName)
{
var strLines = File.ReadLines(filePath);
foreach (var line in strLines)
{
var split = line.Split(',');
if (split[0].Equals(searchName))
{
Student s = new Student()
{
firstname = searchName,
surname = split[1],
city = split[2],
state = split[3]
};
return s; //return the object containing the matched name
}
}
return null;
}
private void Load_Script_Click(object sender, EventArgs e)
{
// load script is button
String con_env = textenv.Text.ToString();
//Address Address = GetAddress("vikas");
//textsurname.text = Address.Surname
Student st = searchStudent(con_env);
textsurname.Text = st.surname;
txtcity.Text = st.city;
txtstate.Text = st.state;
}
namespace DDL_SCRIPT_GENERATOR
{
public class Student
{
public string firstname { get; set; }
public string surname { get; set; }
public string city { get; set; }
public string state { get; set; }
}
}
To accomplish your goal you have to further separate your problem in more granular steps and also distinguish between what you show in your UI and what informations you hold in the background in which format.
Create a class with the desired properties
public class Student { public string Name { get; set; } ... }
Learn how to read a csv file into such an object by using an existing library like CsvHelper or CsvReader.
When you have something like List<Student> from this part. Learn how you can visualize such a thing by using some Binding (also depends on the visualization you use Winforms, WPF, etc.).
Depending on the visualization component it already supports filtering or you need to filter by yourself by using e.g. LINQ to get the matching elements students.Where(student => student.Name.StartsWith(search)).
So far a lot of smaller problems which is simply to much to answer in a single one. Please try to break down your problems into smaller ones and search for their solutions. If you get stuck, ask a new question. That's all I can do for you now.
In device manager of windows7 in com port's branch I choose menu "properties" one of port. In tab of "details" I chose property "parent" and see the string:
How I can obtain this string from vb .net or another language in visual studio in cmd also will be good?
I tried to use win32_ clases: pnpentity, serialPort etc but this no solved to my problem even output of Get-WMIObject Win32_SerialPort in PS had not property "parent".
Dim objService = GetObject("winmgmts://./root/cimv2")
For Each objPort In objService.ExecQuery("SELECT * FROM Win32_PnPEntity WHERE ClassGuid='{4d36e978-e325-11ce-bfc1-08002be10318}'")
Console.WriteLine(objPort.Caption & vbCrLf)
Console.Write(objPort.DeviceID & vbCrLf)
Console.ReadLine()
Next
Except Device ID I try Caption and all syntax that available in List.
Do you have any idea, please?
My solution was the following:
Get all active ports with their PnpDeviceIds:
private static List<PortInfo> GetActivePorts()
{
var ports = new List<PortInfo>();
using (var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_SerialPort"))
using (var collection = searcher.Get())
{
foreach (var device in collection)
{
var portInfo = new PortInfo
{
Port = (string)device.GetPropertyValue("DeviceID"),
PnPDeviceId = (string)device.GetPropertyValue("PNPDeviceID")
};
if (!string.IsNullOrEmpty(portInfo.Port) && !string.IsNullOrEmpty(portInfo.PnPDeviceId))
{
ports.Add(portInfo);
}
}
}
return ports;
}
where PortInfo is
private class PortInfo
{
public string Port { get; set; }
public string PnPDeviceId { get; set; }
public string ParentDeviceId { get; set; }
}
fill ParentDeviceIds :
private static async void FillParentIds(IReadOnlyCollection<PortInfo> ports)
{
var propertiesToQuery = new List<string> {
"System.Devices.DeviceInstanceId",
"System.Devices.Parent"
};
var aqs = string.Join(" OR ", ports.Select(p => $"System.Devices.DeviceInstanceId:={p.PnPDeviceId}"));
var pnpDevices = await PnpObject.FindAllAsync(PnpObjectType.Device, propertiesToQuery, aqs);
foreach (var pnpDevice in pnpDevices)
{
var port = ports.FirstOrDefault(p => string.Compare(p.PnPDeviceId, pnpDevice.Id, StringComparison.InvariantCultureIgnoreCase) == 0);
if (port != null && pnpDevice.Properties.TryGetValue("System.Devices.Parent", out var parentId))
{
port.ParentDeviceId = parentId?.ToString();
}
}
}
ParentDeviceId will be that string you are looking for.
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);
}
I do have the following Class and Controller
public class FieldHelper
{
public FieldHelper(RoomMeta rm, string typeClass)
{
this.typeClass = typeClass;
this.Name = rm.Name;
if (rm.Required)
this.required = "required";
else
this.required = "optional";
}
public FieldHelper(EventTypeMeta etm, string typeClass)
{
this.typeClass = typeClass;
this.Name = etm.Name;
if (etm.Required)
this.required = "required";
else
this.required = "optional";
}
public string typeClass { get; set; }
public string Name { get; set; }
public string required { get; set; }
}
[HttpGet]
public JsonResult GetDefaultFields(int eventTypeID, int roomID)
{
using (var db = new MyDbContext())
{
List<FieldHelper> fields = new List<FieldHelper>();
foreach(RoomMeta rm in db.RoomMetaSet.Where(rm => rm.RoomId == roomID))
{
fields.Add(new FieldHelper(rm, rm.FieldTypes.Name)); //Here the Exception gets thrown
}
foreach(EventTypeMeta etm in db.EventTypeMetaSet.Where(etm => etm.EventTypeId == eventTypeID))
{
fields.Add(new FieldHelper(etm, etm.FieldTypes.Name));
}
return Json(fields, JsonRequestBehavior.AllowGet);
}
}
My database layout looks as follows:
Now, when I run this on my local machine, where I use a SQL Server Express 2014 installation, everything works just the way I expected it. However, once I deploy the Application to a Windows Azure Website with a Azure SQL Database, I get an EntityCommandExecutionException at the line marked. The inner exception tells me "There is already an open DataReader associated with this Command which must be closed first." which seems somehow more useful to me, but still I couldn't figure out why this works localy but not online.
Any Ideas would be appreciated.
Looks like I've found the Answer myself. Since I didnt Include the related Entitys in my query, entity framework tried to open another connection, which failed due to the restriction of my azure sql database.
I changed
foreach(RoomMeta rm in db.RoomMetaSet.Where(rm => rm.RoomId == roomID))
to
foreach(RoomMeta rm in db.RoomMetaSet.Include("FieldTypes").Where(rm => rm.RoomId == roomID))
and everything works fine now.