Objective: I am trying to create a simple console app whose functionality is to set default print preferences for my local machine. Any local application that accesses the printer will use this setting by default.
Below are the properties that am trying to set default values
Paper Type
Paper Orientation
Margin
Default Printer
I have implemented the below code with little use,
using (ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer"))
{
using (ManagementObjectCollection objectCollection = objectSearcher.Get())
{
foreach (ManagementObject mo in objectCollection)
{
if (string.Compare(mo["Name"].ToString(), "OneNote", true) == 0)
{
mo.InvokeMethod("SetDefaultPrinter", null, null);
return true;
}
}
}
}
Even the default printer get updated, but every time when I do ctrl+p a different printer is selected
Secondly, I have implemented the below code to modify HKCU, but it is not providing intended results.
string pageSetupKey = "Software\\Microsoft\\Internet Explorer\\PageSetup";
bool isWritable = true;
RegistryKey rKey = Registry.CurrentUser.OpenSubKey(pageSetupKey, isWritable);
rKey.SetValue("margin_bottom",1000, RegistryValueKind.DWord);
rKey.SetValue("margin_top", 1000, RegistryValueKind.DWord);
rKey.SetValue("margin_left", 1000, RegistryValueKind.DWord);
rKey.SetValue("margin_right", 1000, RegistryValueKind.DWord);
kindly clarify that what I intend to do is achievable and the ways to achieve it.
I have also referred to other posts and questions which are not helpful.
Note: I want to make these changes, not on the process/program basis but for the current user.
Related
I'm trying to return, or in this example print out each user that has been created on a windows machine, I don't really care about the windows users like "defaultuser0", but if anyone can tell me how I can exclude them aswell, that would be great, but back to the main question.
I have this code below, and it works to a certain degree. Output I received was this.
\PC_NAME\root\cimv2:Win32_UserAccount.Domain="PC_NAME",Name="admin"
\PC_NAME\root\cimv2:Win32_UserAccount.Domain="PC_NAME",Name="Administrator"
\PC_NAME\root\cimv2:Win32_UserAccount.Domain="PC_NAME",Name="DefaultAccount"
\PC_NAME\root\cimv2:Win32_UserAccount.Domain="PC_NAME",Name="defaultuser0"
\PC_NAME\root\cimv2:Win32_UserAccount.Domain="PC_NAME",Name="Guest"
\PC_NAME\root\cimv2:Win32_UserAccount.Domain="HEAVEN",Name="WDAGUtilityAccount"
Now I understand that this is natural behaviour of my code. Is there a way I can get the actual usernames, without including the domain and all the other directory code?
Here is the code I'm using.
var searcher = new ManagementObjectSearcher(new SelectQuery("Win32_UserAccount"));
foreach (var managementBaseObject in searcher.Get())
{
Console.WriteLine(((ManagementObject) managementBaseObject).ToString());
}
Instead of letting the compiler choose the base type ManagementBaseObject, you can specify that you only want all ManagementObjectinstances in the collection.
foreach (ManagementObject instance in searcher.Get())
This way you do not need to cast explicitely again.
To access any property of such a ManagementObject use the [string] access notation. The string has to be the property name, in your case it would be Name.
Console.WriteLine("Username: {0}", instance["Name"]);
The full code would be:
var searcher = new ManagementObjectSearcher(new SelectQuery("Win32_UserAccount"));
foreach (ManagementObject instance in searcher.Get())
{
var strUsername = instance["Name"];
Console.WriteLine("Username: {0}", strUsername);
}
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];
I'm developing 'Share Monitoring Application' via C# and it's monitoring the sharing activities and I'm using these APIs to implement enumerate shared items/un-sharing shared items.
Api used:
NetShareEnum
NetShareDel
NetShareEnum to enumerate all shared items and NetShareDel to delete shared items (=unshare).
I used SHChangeNotify to remove shared mark and directories working fine. (Delete shared item using NetShareDel is not affected immediately.)
But printer state is not affected by SHChangeNotify. Which mean after deleting shared printer via NetShareDel and call SHChangeNotify with SHCNE_NETUNSHARE and SHCNF_PATHW. Also I used SHCNE_NETUNSHARE and SHCNF_PRINTERW too, but nothing happened.
Shared printer's state mark: http://i.stack.imgur.com/1ZGrI.png
In this picture, you can see the users the right side of check circle and that indicate printer is shared.
But after calling NetShareDel to unshared shared printer and it's succeed, but shared mark is disappear.
Anyone know how to implement this? I'm waiting for your help. :D
Sorry for my bad english.
Have you tried going via WMI?
I haven't used it myself to "unshare" a printer, but I use it alot in an application to edit printers and printer-ports in other ways.
I would think something like this should do the trick.
The Win32_Printer class looks like it has a "shared" property, so I would suggest trying to switch it to false.
https://msdn.microsoft.com/en-us/library/aa394363%28v=vs.85%29.aspx
I haven't tested this code with unsharing, but it is the exact same code I use to change other properties.
//get the printer(s) through wmi query
//prep query
SelectQuery query = new SelectQuery(string.Format("select * from Win32_Printer WHERE Name = '{0}'", "printername"));
//create scope (connect to server)
ManagementScope scope = new ManagementScope("\\\\serverName\\root\\cimv2");
//search for printers
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, query);
//get collection of printers (should be 0 or 1, but it returns a collection regardless because of the query
ManagementObjectCollection printers = search.Get();
//iterate through the 0-1 printers and set Shared to false
foreach (ManagementObject printer in printers)
{
printer.SetPropertyValue("Shared",false);
printer.put();
}
I tried WMI and it works on my computer, but other computers throw an exception. And I think the reason of application throw an exception is the one of required library is missing on the computer.
So I'm looking for the API that can be used instead of the WMI.
Finally I found the GetPrinter and SetPrinter from the MSDN.
And also I found PRINTER_INFO_5 structure. According to MSDN, Attributes field indicate the printer's attribute including printer is shared or not. And this can be checked Attributes field has PRINTER_ATTRIBUTE_SHARED value.
Anyway, this problem can be solved only OpenPrinter, GetPrinter and SetPrinter.
This image shows the before and after calling 'UnsharePrinter' method.
This is the method I made to un-share the shared printer.
(Un-sharing the shared printer can be performed via NetShareDel, but it cannot notify printer is un-shared to the system.)
Boolean UnsharePrinter(String printerName) {
// fill PRINTER_DEFAULTS structure
// and set DesiredAccess to PRINTER_ACCESS_ADMINISTER to
// get rights to call SetPrinter
PRINTER_DEFAULTS pd;
pd.pDatatype = IntPtr.Zero;
pd.pDevMode = IntPtr.Zero;
pd.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
IntPtr pDefaults = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PRINTER_DEFAULTS)));
Marshal.StructureToPtr(pd, pDefaults, true);
IntPtr hPrinter;
// open the printer
if ( !OpenPrinter(printerName, out hPrinter, pDefaults) ) {
Marshal.FreeHGlobal(pDefaults);
return false;
}
// first, call Zero pointer and 0 size to get minimum required space
IntPtr pInfo = IntPtr.Zero;
Int32 pcbNeeded;
GetPrinter(hPrinter, 5, pInfo, 0, out pcbNeeded);
// alloc reqiured space and call GetPrinter
pInfo = Marshal.AllocHGlobal(pcbNeeded);
if ( !GetPrinter(hPrinter, 5, pInfo, pcbNeeded, out pcbNeeded) ) {
Marshal.FreeHGlobal(pInfo);
ClosePrinter(hPrinter);
return false;
}
// pointer to structure
PRINTER_INFO_5 pi5 = (PRINTER_INFO_5) Marshal.PtrToStructure(pInfo, typeof(PRINTER_INFO_5));
Marshal.FreeHGlobal(pInfo);
// if printer is not shared, release the memory and exit
if ( (pi5.Attributes & PRINTER_ATTRIBUTE_SHARED) == 0 ) {
ClosePrinter(hPrinter);
return false;
}
// remove the shared flag
pi5.Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
// alloc pointer and make structure as pointer
pInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PRINTER_INFO_5)));
Marshal.StructureToPtr(pi5, pInfo, true);
// set printer
Boolean r = SetPrinter(hPrinter, 5, pInfo, 0);
Marshal.FreeHGlobal(pInfo);
ClosePrinter(hPrinter);
return r;
}
I'm using the WMI Volume ManagementObject to format a drive (Docs). If I try to do this from a non-elevated application, I get a result code of 3 (Access denied) which makes sense. Running the application as an administrator means I get a return code of 18 (Unknown Error).
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
String.Format("select * from Win32_Volume WHERE DriveLetter = \"{0}\"", Drive));
foreach (ManagementObject vi in searcher.Get()) {
FormatResult result = (FormatResult)(int)(uint)vi.InvokeMethod("Format", new object[] { FileSystem, QuickFormat, ClusterSize, Label, EnableCompression });
if (result != FormatResult.Success) {
throw new FormatFailedException(String.Format("{0} (Error code {1})", result.ToString(), (int)result));
}
}
Parameters:
FileSystem: "NTFS"
Quick: false
ClusterSize: 4096
Label: "Test"
EnableCompression: false
I can format the drive with the above parameters through Explorer without any problems. How can I diagnose the issue and find out what's going on?
Since there seems to be some confusion, FormatResult is just an enum to simplify handling return codes...
enum FormatResult {
Success = 0,
UnsupportedFileSystem = 1,
IncompatibleMediaInDrive = 2,
AccessDenied = 3,
CallCanceled = 4,
...
UnknownError = 18
}
To give an idea of what I'm doing:
Since the docs mention that this method is usually called asynchronously, I've tried switching to an Async call with the same result (code available upon request). I've also tried various combinations of FileSystem (NTFS/FAT32), ClusterSize (including 0 to let the system pick a default), and Quick/Full formats. All give the same result of 18.
What am I missing?
I have created a C# application to rename printers on a Citrix server (Server 2008 R2).
The reason for this is because every time a user logs on the printer gets forwarded to the server and gets a unique name(For example Microsoft XPS Document Writer (from WI_UFivcBY4-wgoYOdlQ) in session 3) and from within some applications thats an issue since the printer is pointed to the name and by that you need to change the printer setting everytime you logon a session.
The program itself works like a charm and the printer gets the names I desire.
However the issue is after that the printers have been renamed Windows does not seem to be able to identify them anymore. For example if I try to change default printer i get an error saying "Error 0x00000709 Double check the printer name and make sure that the printer is connected to the network."
var query = new ManagementObjectSearcher("SELECT * FROM Win32_Printer where name like '%(%'");
ManagementObjectCollection result = query.Get();
foreach (ManagementObject printer in result)
{
string printerName = printer["name"].ToString();
if (printerName.IndexOf('(') > 0)
{
printer.InvokeMethod("RenamePrinter", new object[] { printerName.Substring(0, printerName.IndexOf('(')).Trim() + " " + userName }); //userName is provided as an inputparameter when running the application
}
}
Am I missing anything? Are there anything else i need to do when renaming?
I cant seem to find any info regarding this case at all.
i thing this codeproject is what your looking for. But after some own experiences with the printers in C# i can only say it does not make fun and it can be really frustrating
Code with small modifications:
//Renames the printer
public static void RenamePrinter(string sPrinterName, string newName)
{
ManagementScope oManagementScope = new ManagementScope(ManagementPath.DefaultPath);
oManagementScope.Connect();
SelectQuery oSelectQuery = new SelectQuery();
oSelectQuery.QueryString = #"SELECT * FROM Win32_Printer WHERE Name = '" + sPrinterName.Replace("\\", "\\\\") + "'";
ManagementObjectSearcher oObjectSearcher =
new ManagementObjectSearcher(oManagementScope, oSelectQuery);
ManagementObjectCollection oObjectCollection = oObjectSearcher.Get();
if (oObjectCollection.Count == 0)
return;
foreach (ManagementObject oItem in oObjectCollection)
{
int state = (int)oItem.InvokeMethod("RenamePrinter", new object[] { newName });
switch (state)
{
case 0:
//Success do noting else
return;
case 1:
throw new AccessViolationException("Access Denied");
case 1801:
throw new ArgumentException("Invalid Printer Name");
default:
break;
}
}
}
Still works great in 2022, thank you. Just had to change type
int
to
UInt32
to avoid new Exception:
UInt32 state = (UInt32)oItem.InvokeMethod("RenamePrinter", new object[] { newName });
switch (state)
{...