Enumerate available WiFi Printers in my Windows Phone app - c#

I know similar questions have been asked a lot, ie "can I print from my wp8?". Most folks seem content with the simple "no" response. I am looking to add this functionality into my app and I know it can be accomplished at some level - even if I can only support a very minimum printer set for now.
I've looked at the app PrintHand, and it appears to have the capabilities I need: print to wireless and Bluetooth printers.
I've been looking through the Bluetooth scenarios document a bit and I think this might help discover a Bluetooth printer. That's a start. Perhaps it will help in identifying wireless printers also.
I realize I need to start very small with this project and I want to first try to enumerate any wireless printers (I don't have a Bluetooth one yet) available on the current network. Would anybody happen to have a pointer in the right direction on how to get started or better yet, some related sample code?
Thanks so much!

Best I can give is my Github Repo which isn't related to Wifi printers, but Google cloud printing.
There isn't really a .net reference for using Google Cloud Print in their documentation, but the code works in Mono, and should be easy to move over to .NET and hence, Windows Phone.
MonoGCP

I was able to detect a nearby wireless printer using Simple Service Discovery Protocol.
Here is my sample function:
private const string SSDP_IP = "239.255.255.250";
private const string SSDP_PORT = "1900";
public async static void DiscoverAsync2()
{
var multicastIP = new HostName(SSDP_IP);
var found = false;
using (var socket = new DatagramSocket())
{
socket.MessageReceived += (sender, e) =>
{
var reader = e.GetDataReader();
var bytesRemaining = reader.UnconsumedBufferLength;
var receivedString = reader.ReadString(bytesRemaining);
// TODO: something useful with this new info
found = true;
};
await socket.BindEndpointAsync(null, string.Empty);
socket.JoinMulticastGroup(multicastIP);
while (true)
{
found = false;
using (var stream = await socket.GetOutputStreamAsync(multicastIP, SSDP_PORT))
{
var request = new StringBuilder();
request.AppendLine("M-SEARCH * HTTP/1.1");
request.AppendLine("HOST: " + SSDP_IP + ":" + SSDP_PORT);
request.AppendLine("MAN: \"ssdp:discover\"");
request.AppendLine("MX: 3");
request.AppendLine("ST: urn:schemas-upnp-org:device:Printer:1"); // use ssdp:all to get everything
request.AppendLine(); // without this extra blank line, query won't run properly
var buff = Encoding.UTF8.GetBytes(request.ToString());
await stream.WriteAsync(buff.AsBuffer());
await Task.Delay(5000);
if (!found)
break;
}
}
}

Related

Trouble with transfer function in WIA C#

I have a problem with the below code. I want to scan a document by clicking a button in a WinForms C# application.
I use WIA, Visual studio and the scanner Fujitsu N7100A working with Windows 8. I am following a tutorial online for using WIA.
But the program doesn't run as expected. It seems to break down at the Transfer method.
// Create a DeviceManager instance
var deviceManager = new DeviceManager();
// Create an empty variable to store the scanner instance
DeviceInfo firstScannerAvailable = null;
// Loop through the list of devices to choose the first available
AddLogs(deviceManager.DeviceInfos.Count.ToString(), filename);
foreach (DeviceInfo d in deviceManager.DeviceInfos)
{
if (d.Type == WiaDeviceType.ScannerDeviceType)
{
firstScannerAvailable = d;
}
}
// Connect to the first available scanner
var device = firstScannerAvailable.Connect();
// Select the scanner
var scannerItem = device.Items[0];
// Retrieve a image in JPEG format and store it into a variable
var imageFile = (ImageFile)scannerItem.Transfer(FormatID.wiaFormatPNG);
//Save the image in some path with filename
var path = #"C:\Documents\scan.png";
if (File.Exists(path))
{
File.Delete(path);
}
// Save image !
imageFile.SaveFile(path);
I just have to remove the addition of lines in the file of log.
This is much more of a workaround since i have no idea about your scanner.
I would assume that all scanners has a drive where they store their scanned documents, like mine, So i would suggest that you read all available drives loop through them check for DriveType and VolumeLabel and then read it's files and copy the document where you want
Something like this :
foreach (var item in DriveInfo.GetDrives())
{
//VolumeLabel differs from a scanner to another
if (item.VolumeLabel == "Photo scan" && item.DriveType == DriveType.Removable)
{
foreach (var obj in Directory.GetFiles(item.Name))
{
File.Copy(obj, "[YOUR NEW PATH]");
break;
}
break;
}
}
Finaly a TWAIN application work with this scanner. I will work with that. I don't said why do that work with TWAIN and not with WIA but that the reality. Sorry for this waste of time. Thank you for the answers. Have a nice day.
I am currently solving this very problem. It seems the N7100A driver sets the Pages property of the device to 0, which should mean continous scanning, but the transfer method is unable to handle this value. You must set that property to 1:
var pages = 1;
// Not all devices have this property, but Fujitsu N7100A has.
device.Properties["Pages"]?.set_Value(ref pages);
I think the problem is here
var scannerItem = device.Items[0];
as WIA indexes are NOT zero based so it should be 1 instead
var scannerItem = device.Items[1];

PrintQueue.Refresh don't show the status of printer

I need to run a Windows Service of server X to show the status of all printers: Out of paper, no toner, etc.
The service is running on a machine but of course not all printers are installed on it. Even when the printers are installed on the machine, we do NOT have the status of the printers!
The only thing I was able to do is to remove the paper, print a test page (notepad), and now I can see that I'm missing paper with the code below, but as you might thing, this is not doable: I don't want to send a test page to every printers of the network every 10 minutes or so!
I try to query PrintQueue.Refresh but status is not updating, I don't see that the printer tray is open (or missing paper, or no toner, whatever I do with the printer.)
BTW, Win32_printer don't show me a better result.
NOTE:
MonitoringWS is the web service that can access the database.
Printers is the list of printers that we want to query.
This is what I try to do.
var printServers = GetListOfPrinterServers();
var listPrinters = printers as List<Printer> ?? printers.ToList();
foreach (
var printServer in
printServers.Select(
server => new PrintServer(server, PrintSystemDesiredAccess.EnumerateServer)))
{
printServer.Refresh();
var printQueues = printServer.GetPrintQueues();
foreach (var printQueue in printQueues)
{
var queue = printQueue;
var printersFound = listPrinters.Where(p =>
string.Equals(p.PrinterName, queue.FullName,
StringComparison.OrdinalIgnoreCase));
foreach (var printer in printersFound)
{
printQueue.Refresh();
Debug.WriteLine(string.Format("{0} {1}", printQueue.FullName, printQueue.HostingPrintServer.Name) );
var pm = new MonitoringWS.PrinterMonitoring
{
FkPrinter = printer.PkPrinter,
QueueStatus = printQueue.QueueStatus,
DriverName = printQueue.QueueDriver.Name,
MonitoringDateTime = DateTime.Now
};
printerMonitorings.Add(pm);
}
}
}
I found a way: SNMP. I use library SNMP# at http://www.snmpsharpnet.com/ and I implement RFC 2790: https://www.rfc-editor.org/rfc/rfc2790 .
With that, when the printer support that standard and when SNMP is active, I got the status of the printer (no toner, no paper, paper jam, etc.)
Thanks everybody for your help.

Windows IoT Raspberry Pi 3 C# GetDiskFreeSpace

I have a USB thumb-drive connected to my raspberry pi 3. I'd need to find out how to check for the available disk space to be printed on a textblock. I couldn't find any example for UWP application.
What I found was GetDiskFreeSpaceEx function and Is there a method available for UWP apps to get available disk space
Is there any example I could refer to?
Thanks.
Updated:
I have tried [Get available disk free space for a given path on Windows [duplicate]] .. Couldn't get it to work too..
You can use StorageFolder.Properties.RetrievePropertiesAsync() API to get the free space size of USB storage.I tested with the following pieces of code:
var removableDevices = KnownFolders.RemovableDevices;
var externalDevices = await removableDevices.GetFoldersAsync();
var usbDriver = externalDevices.FirstOrDefault();
var allProperties = usbDriver.Properties;
IEnumerable<string> propertiesToRetrieve = new List<string> { "System.FreeSpace" };
var storageIdProperties = await allProperties.RetrievePropertiesAsync(propertiesToRetrieve);
var freeSpaceSize = storageIdProperties["System.FreeSpace"].ToString();

UWP/C# - Issue with AQS and USB Devices

I have an issue with a UWP app that I am trying to write. I am connecting to a custom embedded USB Bulk device that I have programmed (it is actually an out of the box example from Cypress Semiconductor). I am using the WinUSB.sys driver using the embedded MS OS string in the device to allow the device to be used with out having to write a custom INF file to call the WinUSB.sys driver.
In my code, I am using the UsbDevice.GetDeviceSelector method to return an AQS that can then be passed into DeviceInformation.FindAllAsync to begin communicating with the device in my app. I have confirmed that the device shows up in the device manager without any issues, and I have checked in the registry to ensure that it has an Interface GUID. I have a screenshot from USBViewer to show the configuration of the device. This method for finding and connecting with USB devices is from this MSDN example found here.
When I use the UsbDevice.GetDeviceSelector method, it returns a GUID that is not associated with this device. The GUID that it returns is actually associated with Lumia Phones (DEE824EF-729B-4A0E-9C14-B7117D33A817). Because of this, it does not find my device connected to the system.
To troubleshoot, I have both called the DeviceInformation.FindAllAsync with out any arguments to see if my device is listed, and it does find the device (amongst over 1000 other devices that have been connected ever to my machine). I then wrote a custom AQS string without the help of the GetDeviceSelector method, starting with just the GUID. Doing this returned 27 devices, but when I tried to add the VID and PID to this AQS string, nothing returned.
I have also made sure that the device that I want to use is listed in the app manifest by its appropriate VID and PID as this is required for a device with a Custom Class of 0xFF. I have used the Custom USB UWP device example and it can find the device, though it uses a completely different method with a device picker, which I will go to if needed, but this is not my desire as it makes that part of the app not as clean of a solution.
I have posted this question over in the MSDN forums here with more information, but I have not gotten a lot of engagement there. Any help would be appreciated. I know that I must be missing something simple.
Adam
private async void button_Click(object sender, RoutedEventArgs e)
{
//UInt32 vid = 0x04B4;
//UInt32 pid = 0x00F0;
UInt32 vid = uint.Parse(textBox1.Text, System.Globalization.NumberStyles.HexNumber);
UInt32 pid = UInt32.Parse(textBox2.Text, System.Globalization.NumberStyles.HexNumber);
Guid winusbInterfaceGuid = new Guid("a5dcbf10-6530-11d2-901f-00c04fb951ed");
//string aqs = UsbDevice.GetDeviceSelector(vid, pid);
string aqs = UsbDevice.GetDeviceSelector(winusbInterfaceGuid);
var myDevices = await DeviceInformation.FindAllAsync(aqs, null);
//var myDevices = await DeviceInformation.FindAllAsync();
var myDevicesCount = myDevices.Count;
if (myDevicesCount >= 1)
{
textBlock2.Text = "Device Found";
} else
{
textBlock2.Text = "Searching";
await Task.Delay(1000);
textBlock2.Text = "looking for device";
}
}
just dropped you a mail asking about progress (I think, had to guess your mail address), but now it seems I found a solution myself. Please see my answer on UWP app cannot find/connect to USB device
In short, you have to create an inf for installing the winusb driver. I have no clue why, but that did the trick for me (and someone else, see Cannot create UsbDevice from DeviceInformation.Id)
The Guid DEE824EF-729B-4A0E-9C14-B7117D33A817 is actually the standard WinUSB Guid. I don't think it has anything to do with Lumia Phones. I don't know why it is not documented anywhere. I think that the Guid a5dcbf10-6530-11d2-901f-00c04fb951ed you specified is actually a red herring. I mistakenly used that as well, but it just led me down the garden path. It shows up USB interfaces, but I can't connect to them.
You might want to try this class https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net.UWP/UWPUsbDevice.cs .
Here is how it gets the device:
public async Task<IEnumerable<DeviceDefinition>> GetConnectedDeviceDefinitions(uint? vendorId, uint? productId)
{
var aqsFilter = "System.Devices.InterfaceClassGuid:=\"{DEE824EF-729B-4A0E-9C14-B7117D33A817}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND " + $" System.DeviceInterface.WinUsb.UsbVendorId:={vendorId.Value} AND System.DeviceInterface.WinUsb.UsbProductId:={productId.Value}";
var deviceInformationCollection = await wde.DeviceInformation.FindAllAsync(aqsFilter).AsTask();
//TODO: return the vid/pid if we can get it from the properties. Also read/write buffer size
var deviceIds = deviceInformationCollection.Select(d => new DeviceDefinition { DeviceId = d.Id, DeviceType = DeviceType.Usb }).ToList();
return deviceIds;
}
This sample connects to a device and I think you'll be able to connect to the device in the same way:
private static async Task InitializeTrezor()
{
//Register the factory for creating Usb devices. This only needs to be done once.
UWPUsbDeviceFactory.Register();
//Register the factory for creating Usb devices. This only needs to be done once.
UWPHidDeviceFactory.Register();
//Note: other custom device types could be added here
//Define the types of devices to search for. This particular device can be connected to via USB, or Hid
var deviceDefinitions = new List<DeviceDefinition>
{
new DeviceDefinition{ DeviceType= DeviceType.Hid, VendorId= 0x534C, ProductId=0x0001, Label="Trezor One Firmware 1.6.x" },
new DeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C1, ReadBufferSize=64, WriteBufferSize=64, Label="Trezor One Firmware 1.7.x" },
new DeviceDefinition{ DeviceType= DeviceType.Usb, VendorId= 0x1209, ProductId=0x53C0, ReadBufferSize=64, WriteBufferSize=64, Label="Model T" }
};
//Get the first available device and connect to it
var devices = await DeviceManager.Current.GetDevices(deviceDefinitions);
var trezorDevice = devices.FirstOrDefault();
await trezorDevice.InitializeAsync();
//Create a buffer with 3 bytes (initialize)
var buffer = new byte[64];
buffer[0] = 0x3f;
buffer[1] = 0x23;
buffer[2] = 0x23;
//Write the data to the device
await trezorDevice.WriteAsync(buffer);
//Read the response
var readBuffer = await trezorDevice.ReadAsync();
}
If you connect to the device in this way, you'll get Windows classic, and Android support for free with Device.Net (https://github.com/MelbourneDeveloper/Device.Net)
With Device.net's DeviceManager.Current.GetDevices(deviceDefinitions) using .NET 5 I can't find any device connected to my win10, which can be easily selected by ManagementObjectSearcher:
public List<ManagementBaseObject> GetLogicalDevices()
{
List<ManagementBaseObject> devices = new List<ManagementBaseObject>();
ManagementObjectCollection collection;
ManagementObjectSearcher seacher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM CIM_LogicalDevice");
collection = seacher.Get();
foreach (var device in collection)
{
devices.Add(device);
}
return devices;
}

Hostname scanning in C#

Iv'e recently started a new job as an ICT Technician and im creating an Console application which will consists of stuff that will help our daily tools!
My first tool is a Network Scanner, Our system currently runs on Vanilla and Asset tags but the only way we can find the hostname / ip address is by going into the Windows Console tools and nslookup which to me can be improved
I want to create an application in which I enter a 6 digit number and the application will search the whole DNS for a possible match!
Our hostsnames are like so
ICTLN-D006609-edw.srv.internal the d 006609 would be the asset tag for that computer.
I wish to enter that into the Console Application and it search through every hostname and the ones that contain the entered asset tag within the string will be returned along with an ip and full computer name ready for VNC / Remote Desktop.
Firstly how would I go about building this, shall i start the project of as a console app or a WPF. can you provide an example of how I can scan the hostnames via C#, or if there's an opensource C# version can you provide a link.
Any information would be a great help as it will take out alot of issues in the workpalce as we have to ask the customer to go into there My Computer adn properties etc and then read the Computer name back to use which I find pointless.
Regards.
Updates:
*1 C# Version I made: http://pastebin.com/wBWxyyuh
I would actually go about this with PowerShell, since automating tasks is kinda its thing. In fact, here's a PowerShell script to list out all computers visible on the network. This is easily translatable into C# if you really want it there instead.
function Find-Computer( [string]$assetTag ) {
$searcher = New-Object System.DirectoryServices.DirectorySearcher;
$searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry;
$searcher.SearchScope = 'Subtree';
$searcher.PageSize = 1000;
$searcher.Filter = '(objectCategory=computer)';
$results = $searcher.FindAll();
$computers = #();
foreach($result in $results) {
$computers += $result.GetDirectoryEntry();
}
$results.Dispose(); #Explicitly needed to free resources.
$computers |? { $_.Name -match $assetTag }
}
Here's a way you can accomplish this, although it's not the best. You might consider hitting Active Directory to find the legitimate machines on your network. The code below shows how you might resolve a machine name, and shows how to ping it:
static void Main()
{
for (int index = 0; index < 999999; index++)
{
string computerName = string.Format("ICTLN-D{0:000000}-edw.srv.internal", index);
string fqdn = computerName;
try
{
fqdn = Dns.GetHostEntry(computerName).HostName;
}
catch (SocketException exception)
{
Console.WriteLine(">>Computer not found: " + computerName + " - " + exception.Message);
}
using (Ping ping = new Ping())
{
PingReply reply = ping.Send(fqdn);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine(">>Computer is alive: " + computerName);
}
else
{
Console.WriteLine(">>Computer did not respond to ping: " + computerName);
}
}
}
}
Hope that helps...

Categories