I am printing using PrintDocument class.
I have a DB table having doc info to be printed. Instead of having its PrintName I just have IP address of the printer. All printers are installed locally. And I'm working on a windows service that will print those documents.
There is another app, out of my scope, where the user chose one printer, but just its IP is stored at DB... so
How can I set PrinterSettings.PrinterName having just its IP address??
By printername I assume you mean the name the printer is set up with in Windows and not the printer model, or sharename.
I don't really understand what you mean by the printers are installed locally. Is your computer acting as a printserver for the printers, since you have their IP address, or are they installed and shared from another printserver?
What you are actually looking for, when you only have the IP address is the printers TCPIPPrinterPort, which then is related to a printer. Unfortunatly the PrintServer class in C# doesn't return the hostaddress of the associated port (which is why we always name our ports "IP_10.200.49.230" or the like, because then you can find the port by name instead of hostaddress, which IS included in the printserver class.
In your situation I would do something like this:
static void Main(string[] args)
{
String serverName = "Print-Server"; //set servername (your own computername if you truly are hosting the printers locally)
String ipToSearchFor = "10.91.40.75";//ip to search for in this example
//this loads all TCPPrinterPorts into a Dictionary indexed by the ports Hostaddress (IP)
//I'm loading all because I assume you are going to iterate over them at some point, since It seems you have a list
Dictionary<string, ManagementObject> printerPorts = LoadScope(serverName, "select * from Win32_TCPIPPrinterPort");
//after we've got the ports, open the printserver
using (PrintServer ps = new PrintServer("\\\\" + serverName))
{
//find the queue where queueport.name equals name of port we look up from IP
var queue = ps.GetPrintQueues().Where(p => p.QueuePort.Name == printerPorts[ipToSearchFor]["Name"].ToString()).FirstOrDefault();
//print sharename
Console.WriteLine(queue.ShareName);
}
}
//Loads everything in scope into a dictionary, in this case indexed by hostaddress
private static Dictionary<string, ManagementObject> LoadScope(string server, string query)
{
ManagementScope scope = new ManagementScope("\\\\" + server + "\\root\\cimv2");
scope.Connect();
SelectQuery q = new SelectQuery(query);
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, q);
ManagementObjectCollection pp = search.Get();
Dictionary<string, ManagementObject> objects = new Dictionary<string, ManagementObject>();
foreach (ManagementObject p in pp)
{
string name = p["HostAddress"].ToString().ToLower();
if (!objects.ContainsKey(name))
objects.Add(name, p);
}
return objects;
}
I would advise for you to loop through your list and from here on, also save the sharename and servername of the printer.
Related
we have a print server and lots of printers on it. We access them like this:
\\print-server-name\printer1
\\print-server-name\printer1_color
\\print-server-name\printer2
...etc.
I now need a list of all printers on that server. Until now, I could only find all printers installed locally on the machine. I found this while googling which gave me only the local printers aswell:
PrintServer lps = new PrintServer();
PrintQueueCollection prQueue = lps.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Connections });
liServerPrinterNames = (from printer in prQueue select printer).ToList();
Actually I only need the names of all printers on the server in a string array, I don't even need objects for interaction, only the names of all printers as string. Is that possible? How?
Thanks for any help in advance!
Gets all InstalledPrinters
foreach (string printer in PrinterSettings.InstalledPrinters)
Using WMI Windows Management Instrumentation
SelectQuery query = new SelectQuery("SELECT * FROM Win32_Printer");
ManagementObjectSearcher mos= new ManagementObjectSearcher(mos, query);
System.Management.ManagementObjectCollection moc= mos.Get();
foreach (ManagementObject Printers in moc )
Printers["Name"]; //GetPrinterName
}
Here is how I did it:
using System.Printing;
string serverAddress = #"\\server.domain.local"
PrintServer printServer = new PrintServer($#"{serverAddress}")
PrintQueueCollection queues = printServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local });
foreach (var item in queues)
{
Console.WriteLine(item.Name)
}
If you want the full name (\\server.domain.local\PrinterName) use property FullName instead of Name :)
I need to find the IP address of the installed printers on my laptop. I move my laptop between different locations and networks. Each network has its own set of ip addresses. The laptop has different printers installed for each location with all connections being made wirelessly.
In using the below code (.net 4.0), the QueuePort.Name returns:
WSD-27e3f972-cdc7-459d-b0c1-20e8410fb1db.0032 and
192.168.1.12_1
Since these are network printers, I assume these have to resolve to a real IP Address??
Where am I going wrong? Or is there a better way? Any help is really appreciated.
IEnumerable<Printer> GetLocalPrinters()
{
EnumeratedPrintQueueTypes[] enumerationFlags = { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections };
LocalPrintServer printServer = new LocalPrintServer();
var x = printServer.GetPrintQueues(enumerationFlags).Select(y =>
new Printer
{
Fullname = y.FullName,
QueuePortName = y.QueuePort.Name,
Location = y.Location
})
.OrderBy( z => z.QueuePortName);
return x;
}
The portname is NOT the IP address. Sometimes they are the same text.
They answer appears to be here:
Determine the IP Address of a Printer in C#
Edited 31-Oct-2011:
Query the WMI for the printer port IP address.
using System;
using System.Management;
namespace WMI_example_01
{
class Program
{
static void Main(string[] args)
{
var scope = new ManagementScope(#"\\.\root\cimv2");
var query = new ObjectQuery("SELECT * FROM win32_tcpipprinterport");
var searcher = new ManagementObjectSearcher(scope, query);
var collection = searcher.Get();
foreach(var col in collection)
{
Console.WriteLine("Port name: {0}\tHostAddress: {1}", col["Name"], col"HostAddress"]);
}
}
}
}
The printing queue has a corresponding port that is handled by the port monitor.
There are different port monitors (not only standard monitors like TCPMON and WSD but also custom and vendor-specific), as far as I know, there is no universal way to deal with all kinds of them.
From the provided port name, I assume you are dealing with the WSD port. Here things become a bit tricky, I suggest you read my answer https://stackoverflow.com/a/63705944/4700228 for the solution.
I found many samples on how to get a hostname by an IP address, how can I get the IP address of a host in the LAN?
Try this
public static void DoGetHostAddresses(string hostname)
{
IPAddress[] ips;
ips = Dns.GetHostAddresses(hostname);
Console.WriteLine("GetHostAddresses({0}) returns:", hostname);
foreach (IPAddress ip in ips)
{
Console.WriteLine(" {0}", ip);
}
}
i got this from http://msdn.microsoft.com/en-us/library/system.net.dns.gethostaddresses.aspx
Here is simple code if you want to get the IP Address(V4) from your pc.
Import this library into your class
using System.Net;
Initialize and declare these variables into your codes. They contain hostname, ipaddress and an array of Host Addresses:
string HostName = Dns.GetHostName().ToString();
IPAddress[] IpInHostAddress = Dns.GetHostAddresses(HostName);
string IPV4Address = IpInHostAddress[1].ToString(); //Default IPV4Address. This might be the ip address you need to retrieve
string IPV6Address = IpInHostAddress[0].ToString(); //Default Link local IPv6 Address
Open your command prompt, just type "ipconfig" and press enter.Once you are done, you could check if the string IPV4Address matches to IPv4Address in our pc.
As long as you know the name of a machine, you can use Dns.GetHostAddresses. Your network DNS should recognize it as LAN computer and return proper IP.
Use Dns.GetHostEntry(hostname) instead of obsolete Dns.GetHostAddresses.
Here is an excellent example of how it is doing: http://www.codeproject.com/Articles/854/How-To-Get-IP-Address-Of-A-Machine
you could use the windows management classes to do this, it also works for remote machines that are in the same domain (but I don't know if they need to enable or disable any security or policy settings for this to work). for example:
public List<NetworkAdapter> GetAdapterList()
{
ManagementClass mgmt = new ManagementClass("Win32_NetworkAdapterConfiguration ");
ManagementObjectCollection moc = mgmt.GetInstances();
List<NetworkAdapter> adapters = new List<NetworkAdapter>();
// Search for adapters with IP addresses
foreach(ManagementObject mob in moc)
{
string[] addresses = (string[])mob.Properties["IPAddress"].Value;
if (null == addresses)
{
continue;
}
NetworkAdapter na = new NetworkAdapter();
na.Description = (string) mob.Properties["Description"].Value;
na.MacAddress = (string) mob.Properties["MACAddress"].Value;
na.IPAddresses = addresses;
adapters.Add(na);
}
return adapters;
}
and to access a remote machine create the management class like this instead:
ManagementClass mgmt = new ManagementClass
(\\\\servername\\root\\cimv2:Win32_NetworkAdapterConfiguration);
this approach may get you more IPs than just the ones that have been registered in the DNS.
My company developed a device that communicates with a PC via Bluetooth using a virtual COM port.
Now we need a user to pair a device with a PC (MS Windows OS) first and then enter it's com port number manually into our application(I bet 95% of users will fail on this taks).
So I'd like my application to present a user with a list of paired bluetooth devices (a list of their "friendly names") and after that I'd like to find out the selecded device's COM port number automatically.
How can I do it in c#? (a solution independent of installed bluetooth stack is appreciated).
Thanks in advance.
See my answer at Widcomm bluetooth : how to open the virtual COM for my understanding of the licence: using the binary version is free for commercial use. And, also that I'm maintainer of the library.
So a brief slight digression. I'm not a big fan of virtual COM ports. It always seems much easier to use a direct 'sockets' connection, rather than attempt to setup a COM port, and try to find what name it was created as (see below!), and then have to open a SerialPort to use it, and then if the connection is lost one doesn't know and have simply to keep retrying... With the library its so much easier to just to create and use that direct Bluetooth connection!
However you may want a solution to your current task at the moment. :-) So, use WMI to find the current COM ports in place and see if any of them are for your device. For example in PowerShell:
C:\> Get-WmiObject -query "select DeviceID,PNPDeviceID from Win32_SerialPort"
...
...
DeviceID : COM66
PNPDeviceID : BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}\7&1D80ECD3&0&00803A686519_C00000003
In that big long string one sees the address of the target device: 00803A686519. One can use WMI from .NET, run that query, filter the ones with "BTHENUM", and then parse out the address.
If you the do need to create a new Bluetooth virtual COM port, use 32feet.NET's BluetoothDeviceInfo.SetServiceState(BluetoothService.SerialPort) API. See the "Bluetooth Serial Ports" section in the User Guide e.g. at http://www.alanjmcf.me.uk/comms/bluetooth/32feet.NET%20--%20User%20Guide.html, and the class documentation in the release.
Unfortunately the native Win32 API we call does not tell what name of COM port it created! :-( So run the WMI query before and after the call to see what new name appeared (or use System.IO.Ports.SerialPort.GetPortNames as its simpler).
That's all specific to the Microsoft Bluetooth stack. I haven't investigated how other stacks behave in this regard. After a brief check Widcomm's serial ports appear in SerialPort.GetPortNames but not in the WMI query...
First, create a Management Object Searcher to search the WMI database:
ManagementObjectSearcher serialSearcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_SerialPort");
Next, use LINQ to get all the serial ports into a query:
var query = from ManagementObject s in serialSearcher.Get()
select new { Name = s["Name"], DeviceID = s["DeviceID"], PNPDeviceID = s["PNPDeviceID"] }; // DeviceID -- > PNPDeviceID
You can now print all the COM ports, their friendly names and you can even filter through their PNPDeviceID's to find the bluetooth device address. Here's an example:
foreach (var port in query)
{
Console.WriteLine("{0} - {1}", port.DeviceID, port.Name);
var pnpDeviceId = port.PNPDeviceID.ToString();
if(pnpDeviceId.Contains("BTHENUM"))
{
var bluetoothDeviceAddress = pnpDeviceId.Split('&')[4].Split('_')[0];
if (bluetoothDeviceAddress.Length == 12 && bluetoothDeviceAddress != "000000000000")
{
Console.WriteLine(" - Address: {0}", bluetoothDeviceAddress);
}
}
}
I manage to get the bluetooth name and the COM port by fiddling the registry key
The pseudo code to obtain the bluetooth information is below:
enumerate all the COM port available in the PNP
obtain the device classGuid
search the bluetooth address from the classGuid
when the bluetooth address is known, the bluetooth name can be obtained from the this registry SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices
The code is below, just call the GetBluetoothPort(), it will return a list of bluetooth devices, and you could connect them by passing the COM port number to the SerialPort class
public static string[] GetBluetoothPort()
{
Regex regexPortName = new Regex(#"(COM\d+)");
List<string> portList = new List<string>();
ManagementObjectSearcher searchSerial = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity");
foreach (ManagementObject obj in searchSerial.Get()) {
string name = obj["Name"] as string;
string classGuid = obj["ClassGuid"] as string;
string deviceID = obj["DeviceID"] as string;
if (classGuid != null && deviceID != null) {
if (String.Equals(classGuid, "{4d36e978-e325-11ce-bfc1-08002be10318}", StringComparison.InvariantCulture)) {
string[] tokens = deviceID.Split('&');
if (tokens.Length >= 4) {
string[] addressToken = tokens[4].Split('_');
string bluetoothAddress = addressToken[0];
Match m = regexPortName.Match(name);
string comPortNumber = "";
if (m.Success) {
comPortNumber = m.Groups[1].ToString();
}
if (Convert.ToUInt64(bluetoothAddress, 16) > 0) {
string bluetoothName = GetBluetoothRegistryName(bluetoothAddress);
portList.Add(String.Format("{0} {1} ({2})", bluetoothName, bluetoothAddress, comPortNumber));
}
}
}
}
}
return portList.ToArray();
}
private static string GetBluetoothRegistryName(string address)
{
string deviceName = "";
string registryPath = #"SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices";
string devicePath = String.Format(#"{0}\{1}", registryPath, address);
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(devicePath)) {
if (key != null) {
Object o = key.GetValue("Name");
byte[] raw = o as byte[];
if (raw != null) {
deviceName = Encoding.ASCII.GetString(raw);
}
}
}
return deviceName;
}
Maybe it is not what you are looking for, and maybe you already found your answer...
I just found a question not exactly like yours but worked for me.. With this one you can find out which one of your COM Ports are from a Bluetooth device:
StackOverflow - Determine if serial port is normal COM or SPP
I hope it helps somehow. If you find out how to do what you wanted, please let me know. Thanks.
So, to get the information about a remote device including its name, using 32feet.NET do:
BluetoothAddress addr = ... ...
BluetoothDeviceInfo info = new BluetoothDeviceInfo(addr);
string name = info.DeviceName;
If not using the library you'll have to P/Invoke Win32's BluetoothGetDeviceInfo.
private static string FindSerialPortForRFIDReaderCore()
{
string serialPort = "";
List<string> ports = new List<string>();
System.Management.ManagementObjectSearcher Searcher = new System.Management.ManagementObjectSearcher("Select * from WIN32_SerialPort");
foreach (System.Management.ManagementObject Port in Searcher.Get())
{
if (Port["PNPDeviceID"].ToString().ToUpper().Contains("MacAddress"))
ports.Add(Port["DeviceID"].ToString());
}
if (ports.Count > 1) // There are more than one Serial Ports created for the bluetooth device.
serialPort = ports.OrderByDescending(p => p).FirstOrDefault();
else if(ports.Count == 1)
serialPort = ports[0];
return serialPort;
}
Is there a straightforward way to enumerate all visible network printers in .NET? Currently, I'm showing the PrintDialog to allow the user to select a printer. The problem with that is, local printers are displayed as well (along with XPS Document Writer and the like). If I can enumerate network printers myself, I can show a custom dialog with just those printers.
Thanks!!
Get the default printer from LocalPrintServer.DefaultPrintQueue
Get the installed printers (from user's perspective) from PrinterSettings.InstalledPrinters
Enumerate through the list:
Any printer beginning with \\ is a network printer - so get the queue with new PrintServer("\\UNCPATH").GetPrintQueue("QueueName")
Any printer not beginning with \\ is a local printer so get it with LocalPrintServer.GetQueue("Name")
You can see which is default by comparing FullName property.
Note: a network printer can be the default printer from LocalPrintServer.DefaultPrintQueue, but not appear in LocalPrintServer.GetPrintQueues()
// get available printers
LocalPrintServer printServer = new LocalPrintServer();
PrintQueue defaultPrintQueue = printServer.DefaultPrintQueue;
// get all printers installed (from the users perspective)he t
var printerNames = PrinterSettings.InstalledPrinters;
var availablePrinters = printerNames.Cast<string>().Select(printerName =>
{
var match = Regex.Match(printerName, #"(?<machine>\\\\.*?)\\(?<queue>.*)");
PrintQueue queue;
if (match.Success)
{
queue = new PrintServer(match.Groups["machine"].Value).GetPrintQueue(match.Groups["queue"].Value);
}
else
{
queue = printServer.GetPrintQueue(printerName);
}
var capabilities = queue.GetPrintCapabilities();
return new AvailablePrinterInfo()
{
Name = printerName,
Default = queue.FullName == defaultPrintQueue.FullName,
Duplex = capabilities.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge),
Color = capabilities.OutputColorCapability.Contains(OutputColor.Color)
};
}).ToArray();
DefaultPrinter = AvailablePrinters.SingleOrDefault(x => x.Default);
using the new System.Printing API
using (var printServer = new PrintServer(string.Format(#"\\{0}", PrinterServerName)))
{
foreach (var queue in printServer.GetPrintQueues())
{
if (!queue.IsShared)
{
continue;
}
Debug.WriteLine(queue.Name);
}
}
found this code here
private void btnGetPrinters_Click(object sender, EventArgs e)
{
// Use the ObjectQuery to get the list of configured printers
System.Management.ObjectQuery oquery =
new System.Management.ObjectQuery("SELECT * FROM Win32_Printer");
System.Management.ManagementObjectSearcher mosearcher =
new System.Management.ManagementObjectSearcher(oquery);
System.Management.ManagementObjectCollection moc = mosearcher.Get();
foreach (ManagementObject mo in moc)
{
System.Management.PropertyDataCollection pdc = mo.Properties;
foreach (System.Management.PropertyData pd in pdc)
{
if ((bool)mo["Network"])
{
cmbPrinters.Items.Add(mo[pd.Name]);
}
}
}
}
Update:
"This API function can enumerate all network resources, including servers, workstations, printers, shares, remote directories etc."
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=741&lngWId=10
PrinterSettiings.InstalledPrinters should give you the collection you want
In another post(https://stackoverflow.com/a/30758129/6513653) relationed to this one, Scott Chamberlain said "I do not believe there is anything in .NET that can do this, you will need to make a native call". After to try all the possible .NET resource, I think he is right.
So, I started to investigate how ADD PRINTER dialog does its search. Using Wireshark, I found out that ADD PRINTER send at least two types of packages to all hosts in local network: two http/xml request to 3911 port and three SNMP requests.
The first SNMP request is a get-next 1.3.6.1.2.1.43, which is Printer-MIB. The second one, is a get 1.3.6.1.4.1.2699.1.2.1.2.1.1.3 which is pmPrinterIEEE1284DeviceId of PRINTER-PORT-MONITOR-MIB. This is the most interesting because is where ADD PRINTER takes printer name. The third is a get 1.3.6.1.2.1.1.1.0, which is sysDescr of SNMP MIB-2 System.
I do believe that the second SNMP request is enough to find most of network printers in local network, so I did this code. It works for Windows Form Application and it depends on SnmpSharpNet.
Edit: I'm using ARP Ping instead normal Ping to search active hosts in network. Link for an example project: ListNetworks C# Project
Note that if you're working over RDP it seems to complicate this because it looks like it just exports everything on the host as a local printer.
Which is then a problem if you're expecting it to work the same way when not on RDP.