How to set advanced printer settings [duplicate] - c#
We have a project of managing printing documents. At first I wonder why printing options couldn't be set up in single place. For example printer tray selection for first page and for other pages can be done using MS Word automation:
var doc = _applicationObject.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
AddToRecentFiles: ref addToRecentFiles,
Visible: ref visible);
doc.PageSetup.FirstPageTray = (WdPaperTray) firstPageTrayCode;
doc.PageSetup.OtherPagesTray = (WdPaperTray) otherPagesTrayCode;
_applicationObject.ActivePrinter = printerPath;
doc.Activate();
_applicationObject.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
doc.Close(ref saveChanges, ref _missing, ref _missing);
In the code above printer tray is specified as integer because some printers have not standart values for trays (we had this issue with HP - it's tray codes described here). So we first retrieve what trays printer have, using code:
var setting = new PrinterSettings();
setting.PrinterName = myPrinterName;
foreach (PaperSource tray in setting.PaperSources)
{
Console.WriteLine("\t{0}: #{1}", tray.SourceName, tray.RawKind);
}
And this code works with no problems.
But there is no way to specify duplex and staple options here. Duplex can be done, using driver functions OpenPrinter and SetPrinter, like described here and recommended by Microsoft as well in this forum thread.
Staple is completely unclear and if somebody knows by the way how to implement this, please let me know. Using Stapling enum, like in this MSDN article is useless as it requires custom rendering of the document to print.
I described the situation and how parts were implemented. That works fine on our environment: Windows Server 2008 R2, MS Office 2010 x32, Printers HP LaserJet P2055 and Ricoh Nashuatec DSm635. Tested with native and universal PCL6/PCL5e drivers: duplex and tray selection works as expected.
But after deployment the application to client, printers (HP LaserJet 4250 and Ricoh Aficio MP C7501) do printing always from default tray and without duplex. Tried few different drivers with exactly the same result.
In both environments printers are network printers. So to make them apply duplex setting, using printer driver, we needed to install local driver on server and make a local printer, as recommended my Microsoft on this support forum thread.
Though environments and printers used looks very similar, one works while other do not. Any help will be highly appreciated.
In case someone else needs it, I came up with a workaround, based on storing printer settings memory block in a binary file and then restoring it. The idea was described in this blog post, but it didn't work for me when simply copy-pasted (it worked only for some drivers and for some settings while other printing options were ignored).
So I remade it a bit so that now it can support all settings I've tried on any printer (with compatible driver) I've tested. Of course if you use driver of another printer for example it won't work.
The disadvantage of thi approach is of course that you should first set default printer preferences (in Control Panel) to what you need. That isn't always possible of course, but at least in some cases it can help.
So the full source code of a test util which is capable to store printer settings into a file, load this file again into printer and print a document using the specified settings file:
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Office.Interop.Word;
namespace PrintAdvancedTest
{
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pServerName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPrinterName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pShareName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPortName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pDriverName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pComment;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pSepFile;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPrintProcessor;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pDatatype;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pParameters;
public IntPtr pSecurityDescriptor;
public readonly Int32 Attributes;
public readonly Int32 Priority;
public readonly Int32 DefaultPriority;
public readonly Int32 StartTime;
public readonly Int32 UntilTime;
public readonly Int32 Status;
public readonly Int32 cJobs;
public readonly Int32 AveragePPM;
}
public class PrintSettings
{
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
//Constants for DEVMODE
// Constants for DocumentProperties
private const int DM_MODIFY = 8;
private const int DM_COPY = 2;
private const int DM_IN_BUFFER = DM_MODIFY;
private const int DM_OUT_BUFFER = DM_COPY;
// const intants for dmOrientation
private const int DMORIENT_PORTRAIT = 1;
private const int DMORIENT_LANDSCAPE = 2;
// const intants for dmPrintQuality
private const int DMRES_DRAFT = (-1);
private const int DMRES_HIGH = (-4);
private const int DMRES_LOW = (-2);
private const int DMRES_MEDIUM = (-3);
// const intants for dmTTOption
private const int DMTT_BITMAP = 1;
private const int DMTT_DOWNLOAD = 2;
private const int DMTT_DOWNLOAD_OUTLINE = 4;
private const int DMTT_SUBDEV = 3;
// const intants for dmColor
private const int DMCOLOR_COLOR = 2;
private const int DMCOLOR_MONOCHROME = 1;
// const intants for dmCollate
private const int DMCOLLATE_FALSE = 0;
private const int DMCOLLATE_TRUE = 1;
// const intants for dmDuplex
private const int DMDUP_HORIZONTAL = 3;
private const int DMDUP_SIMPLEX = 1;
private const int DMDUP_VERTICAL = 2;
//const for security access
private const int PRINTER_ACCESS_ADMINISTER = 0x4;
private const int PRINTER_ACCESS_USE = 0x8;
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const int PRINTER_ALL_ACCESS =
(STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER
| PRINTER_ACCESS_USE);
/* field selection bits */
private const int DM_ORIENTATION = 0x00000001;
private const int DM_PAPERSIZE = 0x00000002;
private const int DM_PAPERLENGTH = 0x00000004;
private const int DM_PAPERWIDTH = 0x00000008;
private const int DM_SCALE = 0x00000010;
private const int DM_POSITION = 0x00000020;
private const int DM_NUP = 0x00000040;
private const int DM_DISPLAYORIENTATION = 0x00000080;
private const int DM_COPIES = 0x00000100;
private const int DM_DEFAULTSOURCE = 0x00000200;
private const int DM_PRINTQUALITY = 0x00000400;
private const int DM_COLOR = 0x00000800;
private const int DM_DUPLEX = 0x00001000;
private const int DM_YRESOLUTION = 0x00002000;
private const int DM_TTOPTION = 0x00004000;
private const int DM_COLLATE = 0x00008000;
private const int DM_FORMNAME = 0x00010000;
private const int DM_LOGPIXELS = 0x00020000;
private const int DM_BITSPERPEL = 0x00040000;
private const int DM_PELSWIDTH = 0x00080000;
private const int DM_PELSHEIGHT = 0x00100000;
private const int DM_DISPLAYFLAGS = 0x00200000;
private const int DM_DISPLAYFREQUENCY = 0x00400000;
private const int DM_ICMMETHOD = 0x00800000;
private const int DM_ICMINTENT = 0x01000000;
private const int DM_MEDIATYPE = 0x02000000;
private const int DM_DITHERTYPE = 0x04000000;
private const int DM_PANNINGWIDTH = 0x08000000;
private const int DM_PANNINGHEIGHT = 0x10000000;
private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
static void Main(string[] args)
{
Dictionary<string, Action> commands = new Dictionary<string, Action>
{
{"save", PrinterPreferencesSave},
{"print", PrinterPreferencesPrint},
{"set", PrinterPreferencesSet},
{"info", PrinterInfo}
};
while (true)
{
Console.Write("Command ({0}): ", string.Join(", ", commands.Keys));
string command = Console.ReadLine();
Action action;
if (!commands.TryGetValue(command, out action))
{
Console.WriteLine("Invalid command");
}
else
{
action();
}
}
}
static void PrinterPreferencesSave()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
string testName;
while (true)
{
Console.Write("SAVE: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
getDevMode(printerName, string.Format(SettingsFileNameFormat, testName));
}
}
static void PrinterPreferencesPrint()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
Console.Write("Document to print: ");
string docToPrintPath = Console.ReadLine();
string testName;
while (true)
{
Console.Write("PRINT: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
string filePath = string.Format(SettingsFileNameFormat, testName);
if (!File.Exists(filePath))
{
Console.WriteLine("File {0} not exists", filePath);
return;
}
var success = setDevMode(printerName, filePath);
if (success)
{
PrintWordDocument(docToPrintPath, printerName);
}
}
}
static void PrinterPreferencesSet()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
string testName;
while (true)
{
Console.Write("SET: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
string filePath = string.Format(SettingsFileNameFormat, testName);
if (!File.Exists(filePath))
{
Console.WriteLine("File {0} not exists", filePath);
return;
}
var success = setDevMode(printerName, filePath);
if(!success)
{
Console.WriteLine("Failed");
}
}
}
private static void PrinterInfo()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
IntPtr hDevMode; // handle to the DEVMODE
IntPtr pDevMode; // pointer to the DEVMODE
DEVMODE devMode; // the actual DEVMODE structure
//var printController = new StandardPrintController();
PrinterSettings printerSettings = new PrinterSettings();
printerSettings.PrinterName = printerName;
// Get a handle to a DEVMODE for the default printer settings
hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);
// Obtain a lock on the handle and get an actual pointer so Windows won't
// move it around while we're futzing with it
pDevMode = GlobalLock(hDevMode);
// Marshal the memory at that pointer into our P/Invoke version of DEVMODE
devMode = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));
Dictionary<string, int> dmConstants = new Dictionary<string, int>
{
{"DM_ORIENTATION", 0x00000001},
{"DM_PAPERSIZE", 0x00000002},
{"DM_PAPERLENGTH", 0x00000004},
{"DM_PAPERWIDTH", 0x00000008},
{"DM_SCALE", 0x00000010},
{"DM_POSITION", 0x00000020},
{"DM_NUP", 0x00000040},
{"DM_DISPLAYORIENTATION", 0x00000080},
{"DM_COPIES", 0x00000100},
{"DM_DEFAULTSOURCE", 0x00000200},
{"DM_PRINTQUALITY", 0x00000400},
{"DM_COLOR", 0x00000800},
{"DM_DUPLEX", 0x00001000},
{"DM_YRESOLUTION", 0x00002000},
{"DM_TTOPTION", 0x00004000},
{"DM_COLLATE", 0x00008000},
{"DM_FORMNAME", 0x00010000},
{"DM_LOGPIXELS", 0x00020000},
{"DM_BITSPERPEL", 0x00040000},
{"DM_PELSWIDTH", 0x00080000},
{"DM_PELSHEIGHT", 0x00100000},
{"DM_DISPLAYFLAGS", 0x00200000},
{"DM_DISPLAYFREQUENCY", 0x00400000},
{"DM_ICMMETHOD", 0x00800000},
{"DM_ICMINTENT", 0x01000000},
{"DM_MEDIATYPE", 0x02000000},
{"DM_DITHERTYPE", 0x04000000},
{"DM_PANNINGWIDTH", 0x08000000},
{"DM_PANNINGHEIGHT", 0x10000000},
{"DM_DISPLAYFIXEDOUTPUT", 0x20000000},
};
Console.WriteLine("Allow set: {0}. Details: {1}", Convert.ToString(devMode.dmFields, 16), string.Join(",", dmConstants.Where(c=>(devMode.dmFields & c.Value)==c.Value).Select(c=>c.Key)));
//private const int DM_POSITION = 0x00000020;
//private const int DM_NUP = 0x00000040;
//private const int DM_DISPLAYORIENTATION = 0x00000080;
//private const int DM_DEFAULTSOURCE = 0x00000200;
//private const int DM_PRINTQUALITY = 0x00000400;
//private const int DM_COLOR = 0x00000800;
//private const int DM_YRESOLUTION = 0x00002000;
//private const int DM_TTOPTION = 0x00004000;
//private const int DM_FORMNAME = 0x00010000;
//private const int DM_LOGPIXELS = 0x00020000;
//private const int DM_BITSPERPEL = 0x00040000;
//private const int DM_PELSWIDTH = 0x00080000;
//private const int DM_PELSHEIGHT = 0x00100000;
//private const int DM_DISPLAYFLAGS = 0x00200000;
//private const int DM_DISPLAYFREQUENCY = 0x00400000;
//private const int DM_ICMMETHOD = 0x00800000;
//private const int DM_ICMINTENT = 0x01000000;
//private const int DM_MEDIATYPE = 0x02000000;
//private const int DM_DITHERTYPE = 0x04000000;
//private const int DM_PANNINGWIDTH = 0x08000000;
//private const int DM_PANNINGHEIGHT = 0x10000000;
//private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
WriteDevModePropertyInfo("DeviceName", devMode.dmDeviceName, null);
WriteDevModePropertyInfo("SpecVersion", devMode.dmSpecVersion.ToString(), null);
WriteDevModePropertyInfo("DriverVersion", devMode.dmDriverVersion.ToString(), null);
WriteDevModePropertyInfo("Size", devMode.dmSize.ToString(), null);
WriteDevModePropertyInfo("DriverExtra", devMode.dmDriverExtra.ToString(), null);
WriteDevModePropertyInfo("Orientation", devMode.dmOrientation.ToString(), (devMode.dmFields & DM_ORIENTATION) == DM_ORIENTATION);
WriteDevModePropertyInfo("PaperSize", devMode.dmPaperSize.ToString(), (devMode.dmFields & DM_PAPERSIZE) == DM_PAPERSIZE);
WriteDevModePropertyInfo("PaperLength", devMode.dmPaperLength.ToString(), (devMode.dmFields & DM_PAPERLENGTH) == DM_PAPERLENGTH);
WriteDevModePropertyInfo("PaperWidth", devMode.dmPaperWidth.ToString(), (devMode.dmFields & DM_PAPERWIDTH) == DM_PAPERWIDTH);
WriteDevModePropertyInfo("Scale", devMode.dmScale.ToString(), (devMode.dmFields & DM_SCALE) == DM_SCALE);
WriteDevModePropertyInfo("Copies", devMode.dmCopies.ToString(), (devMode.dmFields & DM_COPIES) == DM_COPIES);
WriteDevModePropertyInfo("Duplex", devMode.dmDuplex.ToString(), (devMode.dmFields & DM_DUPLEX) == DM_DUPLEX);
WriteDevModePropertyInfo("YResolution", devMode.dmYResolution.ToString(), null);
WriteDevModePropertyInfo("TTOption", devMode.dmTTOption.ToString(), null);
WriteDevModePropertyInfo("Collate", devMode.dmCollate.ToString(), (devMode.dmFields & DM_COLLATE) == DM_COLLATE);
WriteDevModePropertyInfo("FormName", devMode.dmFormName.ToString(), null);
WriteDevModePropertyInfo("UnusedPadding", devMode.dmUnusedPadding.ToString(), null);
WriteDevModePropertyInfo("BitsPerPel", devMode.dmBitsPerPel.ToString(), null);
WriteDevModePropertyInfo("PelsWidth", devMode.dmPelsWidth.ToString(), null);
WriteDevModePropertyInfo("PelsHeight", devMode.dmPelsHeight.ToString(), null);
WriteDevModePropertyInfo("DisplayFlags", devMode.dmDisplayFlags.ToString(), null);
WriteDevModePropertyInfo("DisplayFrequency", devMode.dmDisplayFlags.ToString(), null);
}
private static void WriteDevModePropertyInfo(string settingName, string value, bool? allowSet)
{
Console.WriteLine("{0} {1} {2}", allowSet.HasValue ? (allowSet.Value ? "+" : "-") : " ", settingName.PadRight(20, '.'), value);
}
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalFree(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalUnlock(IntPtr handle);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg,
IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel,
IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA",
SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool
OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr
pPrinter, int Command);
[DllImport("kernel32.dll")]
static extern IntPtr GlobalAlloc(uint uFlags, int dwBytes);
public static void getDevMode(string printerName, string filepath)
{
PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
IntPtr ptrZero = IntPtr.Zero;
IntPtr hPrinter;
IntPtr pDevMode = new IntPtr();
//get printer handle
OpenPrinter(printerName, out hPrinter, ref PrinterValues);
//allocate memory for ptr to devmode, 0 argument retrieves bytes required
int bytes = DocumentProperties(new IntPtr(0), hPrinter, printerName, ptrZero, ref pDevMode, 0);
pDevMode = GlobalAlloc(0, bytes);
//set the pointer
DocumentProperties(new IntPtr(0), hPrinter, printerName, pDevMode, ref ptrZero, DM_OUT_BUFFER);
//write the devMode to a file
using (FileStream fs = new FileStream(filepath, FileMode.Create))
{
for (int i = 0; i < bytes; i++)
{
fs.WriteByte(Marshal.ReadByte(pDevMode, i));
}
}
//free resources
GlobalFree(pDevMode);
ClosePrinter(hPrinter);
}
public static bool setDevMode(string printerName, string filepath)
{
if(!File.Exists(filepath))
{
return false;
}
IntPtr hPrinter;
int bytes = 0;
IntPtr pPInfo;
IntPtr pDevMode;
PRINTER_INFO_2 pInfo = new PRINTER_INFO_2();
PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
//retrieve the devmode from file
using (FileStream fs = new FileStream(filepath, FileMode.Open))
{
int length = Convert.ToInt32(fs.Length);
pDevMode = GlobalAlloc(0, length);
for (int i = 0; i < length; i++)
{
Marshal.WriteByte(pDevMode, i, (byte)fs.ReadByte());
}
}
//get printer handle
OpenPrinter(printerName, out hPrinter, ref PrinterValues);
//get bytes for printer info structure and allocate memory
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out bytes);
if (bytes == 0)
{
throw new Exception("Get Printer Failed");
}
pPInfo = GlobalAlloc(0, bytes);
//set pointer to printer info
GetPrinter(hPrinter, 2, pPInfo, bytes, out bytes);
//place the printer info structure
pInfo = (PRINTER_INFO_2)Marshal.PtrToStructure(pPInfo, typeof(PRINTER_INFO_2));
//insert the new devmode
pInfo.pDevMode = pDevMode;
pInfo.pSecurityDescriptor = IntPtr.Zero;
//set pointer to new printer info
Marshal.StructureToPtr(pInfo, pPInfo, true);
//update
SetPrinter(hPrinter, 2, pPInfo, 0);
//free resources
GlobalFree(pPInfo);
GlobalFree(pDevMode);
ClosePrinter(hPrinter);
return true;
}
private static void PrintWordDocument(string path, string printerName)
{
object readOnly = true;
object addToRecentFiles = false;
object visible = false;
object backgroundPrint = false;
object saveChanges = false;
object sourceFile = path;
var wordApplication = new Application();
var doc = wordApplication.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
AddToRecentFiles: ref addToRecentFiles,
Visible: ref visible);
wordApplication.ActivePrinter = printerName;
doc.Activate();
wordApplication.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
object _missing = Type.Missing;
doc.Close(ref saveChanges, ref _missing, ref _missing);
}
}
}
UPDATE 2018-12-04 (in 5,5 years): There was a nasty rare problem with Marshal.StructureToPtr call in this code and today I finally got an answer to that question (see comment from Hans Passant). I'm not able to verify if that actually works since I no longer work on that project, but it seems you may need to apply that fix if you try using this code.
Related
c# Balloon Tip Text: Remove Project text from notification
I am using Balloon tip text in C# and everything is working as expected. However whenever my notifications appear, there will be subtext that correlates to the project name. How do I remove this text? Notification image: notifyIcon1.Icon = new Icon(SystemIcons.Application, 40, 40); notifyIcon1.Visible = true; notifyIcon1.Text = "Application Installation"; notifyIcon1.BalloonTipText = "The App installaion has started."; notifyIcon1.BalloonTipIcon = ToolTipIcon.Info; notifyIcon1.BalloonTipTitle = "Test App Installation"; notifyIcon1.ShowBalloonTip(10000);
Okey so i think i have a start for you atleast. As you can see in the image below i managed to remove the name of the exectuable file that it was running from. I found a example here how to show Balloon tip like Windows 10 Balloon tip without stretching icon and the example from cokeman19 where you can add your own custom icon. Although this does not seem to work when you dont want the exectuable name at the bottom. If you want to do some changes i recommend you to look at https://msdn.microsoft.com/en-us/library/windows/desktop/bb773352(v=vs.85).aspx since it provied some nice hints on what to do. Here is the code that i made a few changes too so we get what we want. public class NotifyIconLarge : IDisposable { [DllImport("shell32.dll", CharSet = CharSet.Auto)] public static extern int Shell_NotifyIcon(int message, NOTIFYICONDATA pnid); [DllImport("Comctl32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr LoadIconWithScaleDown(IntPtr hinst, string pszName, int cx, int cy, out IntPtr phico); [DllImport("user32.dll", SetLastError = true)] static extern bool DestroyIcon(IntPtr hIcon); private const int NIF_LARGE_ICON = 0x00000040; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class NOTIFYICONDATA { public int cbSize = Marshal.SizeOf(typeof(NOTIFYICONDATA)); public IntPtr hWnd; public int uID; public int uFlags; public int uCallbackMessage; public IntPtr hIcon; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szTip; public int dwState; public int dwStateMask; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szInfo; public int uTimeoutOrVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string szInfoTitle; public int dwInfoFlags; Guid guidItem; public IntPtr hBalloonIcon; } private IntPtr _windowHandle; private IntPtr _hIcon; private bool _added; private int _id = 1; private string _tipText; public NotifyIconLarge(IntPtr windowHandle, string tipText) { _windowHandle = windowHandle; _tipText = tipText; IntPtr result = LoadIconWithScaleDown(IntPtr.Zero, "", 0, 0, out _hIcon); UpdateIcon(true); } private void UpdateIcon(bool showIconInTray) { NOTIFYICONDATA nOTIFYICONDATA = new NOTIFYICONDATA(); nOTIFYICONDATA.uCallbackMessage = 2048; nOTIFYICONDATA.uFlags = 1; nOTIFYICONDATA.hWnd = _windowHandle; nOTIFYICONDATA.uID = _id; nOTIFYICONDATA.hIcon = IntPtr.Zero; nOTIFYICONDATA.szTip = null; if (_hIcon != IntPtr.Zero) { nOTIFYICONDATA.uFlags |= 1; nOTIFYICONDATA.hIcon = _hIcon; } nOTIFYICONDATA.uFlags |= 4; nOTIFYICONDATA.szTip = _tipText; nOTIFYICONDATA.hBalloonIcon = _hIcon; if (showIconInTray) { if (!_added) { Shell_NotifyIcon(0, nOTIFYICONDATA); _added = true; } else { Shell_NotifyIcon(1, nOTIFYICONDATA); } } else { if (_added) { Shell_NotifyIcon(2, nOTIFYICONDATA); _added = false; } } } public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon) { NOTIFYICONDATA nOTIFYICONDATA = new NOTIFYICONDATA(); nOTIFYICONDATA.hWnd = _windowHandle; nOTIFYICONDATA.uID = _id; nOTIFYICONDATA.uFlags = 16; nOTIFYICONDATA.uTimeoutOrVersion = timeout; nOTIFYICONDATA.szInfoTitle = tipTitle; nOTIFYICONDATA.szInfo = tipText; switch (tipIcon) { case ToolTipIcon.None: nOTIFYICONDATA.dwInfoFlags = NIF_LARGE_ICON; break; case ToolTipIcon.Info: nOTIFYICONDATA.dwInfoFlags = 1; break; case ToolTipIcon.Warning: nOTIFYICONDATA.dwInfoFlags = 2; break; case ToolTipIcon.Error: nOTIFYICONDATA.dwInfoFlags = 3; break; } int ret = Shell_NotifyIcon(1, nOTIFYICONDATA); } public void RemoveFromTray() { UpdateIcon(false); if (_hIcon != IntPtr.Zero) DestroyIcon(_hIcon); } ~NotifyIconLarge() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Dispose(bool disposing) { RemoveFromTray(); } } So first you declare the NotifyIconLarge class somewhere. private NotifyIconLarge _nil; Then to create a notify popup you use the following code: _nil = new NotifyIconLarge(Handle, "Icon Tip"); _nil.ShowBalloonTip(10000, "Balloon Title", "Balloon Text", ToolTipIcon.None); When you are finished with the tray remove it: _nil.RemoveFromTray(); Credits to cokeman19 for most of the code
Windows form application to change wallpaper. But it changes to black
public partial class Form1 : Form { public string[] allFiles = new string[10]; [DllImport("user32.dll", CharSet =CharSet.Auto)] private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, string pvParam, uint fWinIni); const uint SPI_SETDESKWALLPAPER = 0x14; const uint SPIF_UPDATEINIFILE = 0x01; const uint SPIF_SENDWININICHANGE = 0x02; public Form1() { InitializeComponent(); SystemEvents.PowerModeChanged += OnPowerChange; } private void OnPowerChange(object sender, PowerModeChangedEventArgs e) { switch (e.Mode) { case PowerModes.Resume: var result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, #"F:\abc", SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); Console.WriteLine(result); string wp = GetWPPath(); Console.WriteLine(wp); break; case PowerModes.Suspend: var res = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, #"F:\abc", SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); break; } } private static string GetWPPath() { RegistryKey wallpaper = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", false); string wp_path = wallpaper.GetValue("WallPaper").ToString(); wallpaper.Close(); return wp_path; } I want to change the wallpaper when i resume laptop from sleep or hibernate. I also checked the registry key, it shows the wallpaper as the path I've set but the desktop background is just black. Is there some kind of reg keys that I have to change or something? Edit: I hardcoded the file as #"F:\abc", that's the problem. Changed it by mentioning the extension too like #"F:\abc.jpg" and it works. Anyways, I'm gonna change it to an input so shouldn't be a problem. Thanks to all of you.
I have tried to do it in console. It works for me. And later you can add your app to windows autoload. You must add using System.Runtime.InteropServices; class Program { [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); private static readonly int MAX_PATH = 260; private static readonly int SPI_GETDESKWALLPAPER = 0x73; private static readonly int SPI_SETDESKWALLPAPER = 0x14; private static readonly int SPIF_UPDATEINIFILE = 0x01; private static readonly int SPIF_SENDWININICHANGE = 0x02; static string GetDesktopWallpaper() { string wallpaper = new string('\0', MAX_PATH); SystemParametersInfo(SPI_GETDESKWALLPAPER, (int)wallpaper.Length, wallpaper, 0); return wallpaper.Substring(0, wallpaper.IndexOf('\0')); } static void SetDesktopWallpaper(string filename) { SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, filename, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); } static void Main() { Console.WriteLine("Enter name:"); //should be like - C:\img.jpg SetDesktopWallpaper(Console.ReadLine()); } }
Get mifare card serial number with WinSCard library
I am working on an application that required reading the mifare card serial number, the language I am working with is C#. I am new to mifare reader programming, so I am sorry for asking dumb question. At first I would like to know if there is a different between Mifare UID and Mifare Serial number. I have managed to get UID with the help of WinSCard library, but I cant figure it out how to get the card serial number which should be 10 digit numbers. I do appreciate if you could point me to the right direction. Thanks in advance for the help. Regards
C# signature of SCardTransmit method [StructLayout(LayoutKind.Sequential)] public struct SCARD_IO_REQUEST { public int dwProtocol; public int cbPciLength; } [DllImport("winscard.dll")] public static extern int SCardTransmit(int hCard, ref SCARD_IO_REQUEST pioSendRequest, ref byte SendBuff, int SendBuffLen, ref SCARD_IO_REQUEST pioRecvRequest, ref byte RecvBuff, ref int RecvBuffLen); Code Example for read UID of mifare card private SmartcardErrorCode GetUID(ref byte[] UID) { byte[] receivedUID = new byte[10]; UnsafeNativeMethods.SCARD_IO_REQUEST request = new UnsafeNativeMethods.SCARD_IO_REQUEST(); request.dwProtocol = 1; //SCARD_PROTOCOL_T1); request.cbPciLength = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UnsafeNativeMethods.SCARD_IO_REQUEST)); byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command for Mifare cards int outBytes = receivedUID.Length; int status = SCardTransmit(_hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref outBytes); UID = receivedUID.Take(8).ToArray(); return status; }
The Selected answer doesn't work on x64 enviroments. Here is a Full example code, tested and working on Windows 10 x64. What this does: Retrieve the List of Available Readers Selects to use the First available Reader Check if there is a Card in the reader and Connects to it. Transmits to the card the Command to retrieve its UID Converts the UID into a Hexadecimal string. using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace DXCutcsa.VO.Common { public class SmartCardReader { #region Atributos private bool _disposed = false; private IntPtr _ReaderContext = IntPtr.Zero; private string _ReaderName = string.Empty; private List<string> _AvailableReaders = new List<string>(); #endregion #region Win32 APIs [DllImport("WinScard.dll")] static extern int SCardEstablishContext(uint dwScope, IntPtr notUsed1, IntPtr notUsed2, out IntPtr phContext); [DllImport("WinScard.dll")] static extern int SCardReleaseContext(IntPtr phContext); [DllImport("WinScard.dll")] static extern int SCardConnect(IntPtr hContext, string cReaderName, uint dwShareMode, uint dwPrefProtocol, ref IntPtr phCard, ref IntPtr ActiveProtocol); [DllImport("WinScard.dll")] static extern int SCardDisconnect(IntPtr hCard, int Disposition); [DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)] static extern int SCardListReaders( IntPtr hContext, byte[] mszGroups, byte[] mszReaders, ref UInt32 pcchReaders); [DllImport("winscard.dll")] static extern int SCardStatus( uint hCard, IntPtr szReaderName, ref int pcchReaderLen, ref int pdwState, ref uint pdwProtocol, byte[] pbAtr, ref int pcbAtrLen); [DllImport("winscard.dll")] static extern int SCardTransmit( IntPtr hCard, ref SCARD_IO_REQUEST pioSendRequest, ref byte SendBuff, uint SendBuffLen, ref SCARD_IO_REQUEST pioRecvRequest, byte[] RecvBuff, ref uint RecvBuffLen); [DllImport("winscard.dll", SetLastError = true)] static extern int SCardGetAttrib( IntPtr hCard, // Valor retornado en funcion ScardConnect UInt32 dwAttrId, // Identificacion de atributos a obtener byte[] pbAttr, // Puntero al vector atributos recividos ref IntPtr pcbAttrLen // TamaƱo del vector ); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct ReaderState { public ReaderState(string sName) { this.szReader = sName; this.pvUserData = IntPtr.Zero; this.dwCurrentState = 0; this.dwEventState = 0; this.cbATR = 0; this.rgbATR = null; } internal string szReader; internal IntPtr pvUserData; internal uint dwCurrentState; internal uint dwEventState; internal uint cbATR; // count of bytes in rgbATR [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24, ArraySubType = UnmanagedType.U1)] internal byte[] rgbATR; } [StructLayout(LayoutKind.Sequential)] public struct SCARD_IO_REQUEST { public UInt32 dwProtocol; public UInt32 cbPciLength; } /*****************************************************************/ [DllImport("kernel32.dll", SetLastError = true)] private extern static IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll")] private extern static void FreeLibrary(IntPtr handle); [DllImport("kernel32.dll")] private extern static IntPtr GetProcAddress(IntPtr handle, string procName); #endregion #region Error codes public const uint S_SUCCESS = 0x00000000; public const uint F_INTERNAL_ERROR = 0x80100001; public const uint E_CANCELLED = 0x80100002; public const uint E_INVALID_HANDLE = 0x80100003; public const uint E_INVALID_PARAMETER = 0x80100004; public const uint E_INVALID_TARGET = 0x80100005; public const uint E_NO_MEMORY = 0x80100006; public const uint F_WAITED_TOO_LONG = 0x80100007; public const uint E_INSUFFICIENT_BUFFER = 0x80100008; public const uint E_UNKNOWN_READER = 0x80100009; public const uint E_TIMEOUT = 0x8010000A; public const uint E_SHARING_VIOLATION = 0x8010000B; public const uint E_NO_SMARTCARD = 0x8010000C; public const uint E_UNKNOWN_CARD = 0x8010000D; public const uint E_CANT_DISPOSE = 0x8010000E; public const uint E_PROTO_MISMATCH = 0x8010000F; public const uint E_NOT_READY = 0x80100010; public const uint E_INVALID_VALUE = 0x80100011; public const uint E_SYSTEM_CANCELLED = 0x80100012; public const uint F_COMM_ERROR = 0x80100013; public const uint F_UNKNOWN_ERROR = 0x80100014; public const uint E_INVALID_ATR = 0x80100015; public const uint E_NOT_TRANSACTED = 0x80100016; public const uint E_READER_UNAVAILABLE = 0x80100017; public const uint P_SHUTDOWN = 0x80100018; public const uint E_PCI_TOO_SMALL = 0x80100019; public const uint E_READER_UNSUPPORTED = 0x8010001A; public const uint E_DUPLICATE_READER = 0x8010001B; public const uint E_CARD_UNSUPPORTED = 0x8010001C; public const uint E_NO_SERVICE = 0x8010001D; public const uint E_SERVICE_STOPPED = 0x8010001E; public const uint E_UNEXPECTED = 0x8010001F; public const uint E_ICC_INSTALLATION = 0x80100020; public const uint E_ICC_CREATEORDER = 0x80100021; public const uint E_UNSUPPORTED_FEATURE = 0x80100022; public const uint E_DIR_NOT_FOUND = 0x80100023; public const uint E_FILE_NOT_FOUND = 0x80100024; public const uint E_NO_DIR = 0x80100025; public const uint E_NO_FILE = 0x80100026; public const uint E_NO_ACCESS = 0x80100027; public const uint E_WRITE_TOO_MANY = 0x80100028; public const uint E_BAD_SEEK = 0x80100029; public const uint E_INVALID_CHV = 0x8010002A; public const uint E_UNKNOWN_RES_MNG = 0x8010002B; public const uint E_NO_SUCH_CERTIFICATE = 0x8010002C; public const uint E_CERTIFICATE_UNAVAILABLE = 0x8010002D; public const uint E_NO_READERS_AVAILABLE = 0x8010002E; public const uint E_COMM_DATA_LOST = 0x8010002F; public const uint E_NO_KEY_CONTAINER = 0x80100030; public const uint W_UNSUPPORTED_CARD = 0x80100065; public const uint W_UNRESPONSIVE_CARD = 0x80100066; public const uint W_UNPOWERED_CARD = 0x80100067; public const uint W_RESET_CARD = 0x80100068; public const uint W_REMOVED_CARD = 0x80100069; public const uint W_SECURITY_VIOLATION = 0x8010006A; public const uint W_WRONG_CHV = 0x8010006B; public const uint W_CHV_BLOCKED = 0x8010006C; public const uint W_EOF = 0x8010006D; public const uint W_CANCELLED_BY_USER = 0x8010006E; public const uint W_CARD_NOT_AUTHENTICATED = 0x8010006F; #endregion #region Constructor public SmartCardReader() { } #endregion #region Metodos public long GetUID(ref byte[] UID) { long _result = 0; bool cardInserted = false; IntPtr _CardContext = IntPtr.Zero; IntPtr ActiveProtocol = IntPtr.Zero; // Establish Reader context: if (this._ReaderContext == IntPtr.Zero) { _result = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out this._ReaderContext); #region Get List of Available Readers uint pcchReaders = 0; int nullindex = -1; char nullchar = (char)0; // First call with 3rd parameter set to null gets readers buffer length. _result = SCardListReaders(this._ReaderContext, null, null, ref pcchReaders); byte[] mszReaders = new byte[pcchReaders]; // Fill readers buffer with second call. _result = SCardListReaders(this._ReaderContext, null, mszReaders, ref pcchReaders); // Populate List with readers. string currbuff = new ASCIIEncoding().GetString(mszReaders); int len = (int)pcchReaders; if (len > 0) { while (currbuff[0] != nullchar) { nullindex = currbuff.IndexOf(nullchar); // Get null end character. string reader = currbuff.Substring(0, nullindex); this._AvailableReaders.Add(reader); len = len - (reader.Length + 1); currbuff = currbuff.Substring(nullindex + 1, len); } } #endregion // Select the first reader: this._ReaderName = this._AvailableReaders[0]; } try { //Check if there is a Card in the reader: //dwShareMode: SCARD_SHARE_SHARED = 0x00000002 - This application will allow others to share the reader //dwPreferredProtocols: SCARD_PROTOCOL_T0 - Use the T=0 protocol (value = 0x00000001) if (this._ReaderContext != IntPtr.Zero) { _result = SCardConnect(this._ReaderContext, this._ReaderName, 0x00000002, 0x00000001, ref _CardContext, ref ActiveProtocol); if (_result == 0) { cardInserted = true; SCARD_IO_REQUEST request = new SCARD_IO_REQUEST() { dwProtocol = (uint)ActiveProtocol, cbPciLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(SCARD_IO_REQUEST)) }; byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //<- get UID command for iClass cards byte[] ret_Bytes = new byte[33]; uint sendLen = (uint)sendBytes.Length; uint ret_Len = (uint)ret_Bytes.Length; _result = SCardTransmit(_CardContext, ref request, ref sendBytes[0], sendLen, ref request, ret_Bytes, ref ret_Len); if (_result == 0) { UID = ret_Bytes.Take(4).ToArray(); //only take the first 8, the last 2 bytes are not part of the UID of the card string dataOut = byteToHexa(UID, UID.Length, true).Trim(); //Devolver la respuesta en Hexadecimal } } } } finally { SCardDisconnect(_CardContext, 0); SCardReleaseContext(this._ReaderContext); } return _result; } private string byteToHexa(byte[] byReadBuffer, int leng, bool bSpace) { string text2 = ""; for (short num1 = 0; num1 < leng; num1 = (short)(num1 + 1)) { short num2 = byReadBuffer[num1]; text2 = text2 + System.Convert.ToString(num2, 16).PadLeft(2, '0'); if (bSpace) { text2 = text2 + " "; } } return text2.ToUpper(); } //Get the address of Pci from "Winscard.dll". private IntPtr GetPciT0() { IntPtr handle = LoadLibrary("Winscard.dll"); IntPtr pci = GetProcAddress(handle, "g_rgSCardT0Pci"); FreeLibrary(handle); return pci; } #endregion }// Fin de la Clase } PInvoke docs helped a lot: https://www.pinvoke.net/default.aspx/winscard.scardtransmit
delete executing file on windows ce
i want to make a uninstaller on windows ce. The Problem is I want to delete the uninstaller itself after executed everything else. Is this possible somehow? Or is there someway to make a unistaller in another way?
You can just have the app move itself to the recycle bin. It's a pain because you have to P/Invoke to do this with an unintuative structure. This swatch should help with that. private bool Recycle(string path) { try { ShowProgress(string.Format("Moving {0} to Recycle bin.", path)); SHFILEOPSTRUCT sfo = new SHFILEOPSTRUCT(); sfo.hwnd = IntPtr.Zero; sfo.wFunc = FO_DELETE; sfo.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION; sfo.pFrom = path +'\0' + '\0'; sfo.pTo = null; sfo.fAnyOperationsAborted = false; sfo.hNameMappings = IntPtr.Zero; sfo.lpszProgressTitle = string.Empty; int ret = SHFileOperation(ref sfo); return (ret == 0); } catch (Exception ex) { ShowProgress(string.Format("Failed to move {0} to Recycle bin.", path)); ShowProgress(ex.ToString()); } return false; } // SHFileOperation wFunc and wFunc values public const uint FO_MOVE = 0x0001; public const uint FO_COPY = 0x0002; public const uint FO_DELETE = 0x0003; public const uint FO_RENAME = 0x0004; public const ushort FOF_MULTIDESTFILES = 0x0001; public const ushort FOF_CONFIRMMOUSE = 0x0002; public const ushort FOF_SILENT = 0x0004; // don't create progress/report public const ushort FOF_RENAMEONCOLLISION = 0x0008; public const ushort FOF_NOCONFIRMATION = 0x0010; // Don't prompt the user. public const ushort FOF_WANTMAPPINGHANDLE = 0x0020;// Fill in SHFILEOPSTRUCT.hNameMappings // Must be freed using SHFreeNameMappings public const ushort FOF_ALLOWUNDO = 0x0040; public const ushort FOF_FILESONLY = 0x0080; // on *.*, do only files public const ushort FOF_SIMPLEPROGRESS = 0x0100; // means don't show names of files public const ushort FOF_NOCONFIRMMKDIR = 0x0200; // don't confirm making any needed dirs public const ushort FOF_NOERRORUI = 0x0400; // don't put up error UI public const ushort FOF_NOCOPYSECURITYATTRIBS = 0x0800; // dont copy NT file Security Attributes public const ushort FOF_NORECURSION = 0x1000; // don't recurse ushorto directories. //[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] //If you use the above you may encounter an invalid memory access exception (when using ANSI //or see nothing (when using unicode) when you use FOF_SIMPLEPROGRESS flag. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SHFILEOPSTRUCT { public IntPtr hwnd; public uint wFunc; [MarshalAs(UnmanagedType.LPWStr)] public string pFrom; [MarshalAs(UnmanagedType.LPWStr)] public string pTo; public ushort fFlags; [MarshalAs(UnmanagedType.Bool)] public bool fAnyOperationsAborted; public IntPtr hNameMappings; [MarshalAs(UnmanagedType.LPWStr)] public string lpszProgressTitle; } [DllImport("ceshell.dll")] public static extern int SHFileOperation([In] ref SHFILEOPSTRUCT lpFileOp);
killer.cmd: :a del uninstaller.exe if exist uninstaller.exe goto a del killer.cmd Start it before exitting your uninstaller, so uninstaller.exe will be removed as soon as it's possible, and then killer.cmd is also removed. // Though, not sure if there are .cmds in CE.
Use Windows API from C# to set primary monitor
I'm trying to use the Windows API to set the primary monitor. It doesn't seem to work - my screen just flicks and nothing happens. public const int DM_ORIENTATION = 0x00000001; public const int DM_PAPERSIZE = 0x00000002; public const int DM_PAPERLENGTH = 0x00000004; public const int DM_PAPERWIDTH = 0x00000008; public const int DM_SCALE = 0x00000010; public const int DM_POSITION = 0x00000020; public const int DM_NUP = 0x00000040; public const int DM_DISPLAYORIENTATION = 0x00000080; public const int DM_COPIES = 0x00000100; public const int DM_DEFAULTSOURCE = 0x00000200; public const int DM_PRINTQUALITY = 0x00000400; public const int DM_COLOR = 0x00000800; public const int DM_DUPLEX = 0x00001000; public const int DM_YRESOLUTION = 0x00002000; public const int DM_TTOPTION = 0x00004000; public const int DM_COLLATE = 0x00008000; public const int DM_FORMNAME = 0x00010000; public const int DM_LOGPIXELS = 0x00020000; public const int DM_BITSPERPEL = 0x00040000; public const int DM_PELSWIDTH = 0x00080000; public const int DM_PELSHEIGHT = 0x00100000; public const int DM_DISPLAYFLAGS = 0x00200000; public const int DM_DISPLAYFREQUENCY = 0x00400000; public const int DM_ICMMETHOD = 0x00800000; public const int DM_ICMINTENT = 0x01000000; public const int DM_MEDIATYPE = 0x02000000; public const int DM_DITHERTYPE = 0x04000000; public const int DM_PANNINGWIDTH = 0x08000000; public const int DM_PANNINGHEIGHT = 0x10000000; public const int DM_DISPLAYFIXEDOUTPUT = 0x20000000; public const int ENUM_CURRENT_SETTINGS = -1; public const int CDS_UPDATEREGISTRY = 0x01; public const int CDS_TEST = 0x02; public const int CDS_SET_PRIMARY = 0x00000010; public const long DISP_CHANGE_SUCCESSFUL = 0; public const long DISP_CHANGE_RESTART = 1; public const long DISP_CHANGE_FAILED = -1; public const long DISP_CHANGE_BADMODE = -2; public const long DISP_CHANGE_NOTUPDATED = -3; public const long DISP_CHANGE_BADFLAGS = -4; public const long DISP_CHANGE_BADPARAM = -5; public const long DISP_CHANGE_BADDUALVIEW = -6; public static void SetPrimary(Screen screen) { DISPLAY_DEVICE d = new DISPLAY_DEVICE(); DEVMODE dm = new DEVMODE(); d.cb = Marshal.SizeOf(d); uint deviceID = 1; User_32.EnumDisplayDevices(null, deviceID, ref d, 0); // User_32.EnumDisplaySettings(d.DeviceName, 0, ref dm); dm.dmPelsWidth = 2560; dm.dmPelsHeight = 1600; dm.dmPositionX = screen.Bounds.Right; dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; User_32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, CDS_SET_PRIMARY, IntPtr.Zero); } I call the method like this: SetPrimary(Screen.AllScreens[1]) Any ideas?
Here is the full code based on ADBailey's solution: public class MonitorChanger { public static void SetAsPrimaryMonitor(uint id) { var device = new DISPLAY_DEVICE(); var deviceMode = new DEVMODE(); device.cb = Marshal.SizeOf(device); NativeMethods.EnumDisplayDevices(null, id, ref device, 0); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode); var offsetx = deviceMode.dmPosition.x; var offsety = deviceMode.dmPosition.y; deviceMode.dmPosition.x = 0; deviceMode.dmPosition.y = 0; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref deviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); device = new DISPLAY_DEVICE(); device.cb = Marshal.SizeOf(device); // Update remaining devices for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++) { if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id) { device.cb = Marshal.SizeOf(device); var otherDeviceMode = new DEVMODE(); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode); otherDeviceMode.dmPosition.x -= offsetx; otherDeviceMode.dmPosition.y -= offsety; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref otherDeviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); } device.cb = Marshal.SizeOf(device); } // Apply settings NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null); } } [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] public struct DEVMODE { public const int CCHDEVICENAME = 32; public const int CCHFORMNAME = 32; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)] [System.Runtime.InteropServices.FieldOffset(0)] public string dmDeviceName; [System.Runtime.InteropServices.FieldOffset(32)] public Int16 dmSpecVersion; [System.Runtime.InteropServices.FieldOffset(34)] public Int16 dmDriverVersion; [System.Runtime.InteropServices.FieldOffset(36)] public Int16 dmSize; [System.Runtime.InteropServices.FieldOffset(38)] public Int16 dmDriverExtra; [System.Runtime.InteropServices.FieldOffset(40)] public UInt32 dmFields; [System.Runtime.InteropServices.FieldOffset(44)] Int16 dmOrientation; [System.Runtime.InteropServices.FieldOffset(46)] Int16 dmPaperSize; [System.Runtime.InteropServices.FieldOffset(48)] Int16 dmPaperLength; [System.Runtime.InteropServices.FieldOffset(50)] Int16 dmPaperWidth; [System.Runtime.InteropServices.FieldOffset(52)] Int16 dmScale; [System.Runtime.InteropServices.FieldOffset(54)] Int16 dmCopies; [System.Runtime.InteropServices.FieldOffset(56)] Int16 dmDefaultSource; [System.Runtime.InteropServices.FieldOffset(58)] Int16 dmPrintQuality; [System.Runtime.InteropServices.FieldOffset(44)] public POINTL dmPosition; [System.Runtime.InteropServices.FieldOffset(52)] public Int32 dmDisplayOrientation; [System.Runtime.InteropServices.FieldOffset(56)] public Int32 dmDisplayFixedOutput; [System.Runtime.InteropServices.FieldOffset(60)] public short dmColor; // See note below! [System.Runtime.InteropServices.FieldOffset(62)] public short dmDuplex; // See note below! [System.Runtime.InteropServices.FieldOffset(64)] public short dmYResolution; [System.Runtime.InteropServices.FieldOffset(66)] public short dmTTOption; [System.Runtime.InteropServices.FieldOffset(68)] public short dmCollate; // See note below! [System.Runtime.InteropServices.FieldOffset(72)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)] public string dmFormName; [System.Runtime.InteropServices.FieldOffset(102)] public Int16 dmLogPixels; [System.Runtime.InteropServices.FieldOffset(104)] public Int32 dmBitsPerPel; [System.Runtime.InteropServices.FieldOffset(108)] public Int32 dmPelsWidth; [System.Runtime.InteropServices.FieldOffset(112)] public Int32 dmPelsHeight; [System.Runtime.InteropServices.FieldOffset(116)] public Int32 dmDisplayFlags; [System.Runtime.InteropServices.FieldOffset(116)] public Int32 dmNup; [System.Runtime.InteropServices.FieldOffset(120)] public Int32 dmDisplayFrequency; } public enum DISP_CHANGE : int { Successful = 0, Restart = 1, Failed = -1, BadMode = -2, NotUpdated = -3, BadFlags = -4, BadParam = -5, BadDualView = -6 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DISPLAY_DEVICE { [MarshalAs(UnmanagedType.U4)] public int cb; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceString; [MarshalAs(UnmanagedType.U4)] public DisplayDeviceStateFlags StateFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceID; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceKey; } [Flags()] public enum DisplayDeviceStateFlags : int { /// <summary>The device is part of the desktop.</summary> AttachedToDesktop = 0x1, MultiDriver = 0x2, /// <summary>The device is part of the desktop.</summary> PrimaryDevice = 0x4, /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary> MirroringDriver = 0x8, /// <summary>The device is VGA compatible.</summary> VGACompatible = 0x10, /// <summary>The device is removable; it cannot be the primary display.</summary> Removable = 0x20, /// <summary>The device has more display modes than its output devices support.</summary> ModesPruned = 0x8000000, Remote = 0x4000000, Disconnect = 0x2000000, } [Flags()] public enum ChangeDisplaySettingsFlags : uint { CDS_NONE = 0, CDS_UPDATEREGISTRY = 0x00000001, CDS_TEST = 0x00000002, CDS_FULLSCREEN = 0x00000004, CDS_GLOBAL = 0x00000008, CDS_SET_PRIMARY = 0x00000010, CDS_VIDEOPARAMETERS = 0x00000020, CDS_ENABLE_UNSAFE_MODES = 0x00000100, CDS_DISABLE_UNSAFE_MODES = 0x00000200, CDS_RESET = 0x40000000, CDS_RESET_EX = 0x20000000, CDS_NORESET = 0x10000000 } public class NativeMethods { [DllImport("user32.dll")] public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] // A signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter won't allow you to pass in IntPtr.Zero, so create an overload public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags); [DllImport("user32.dll")] public static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode); } [StructLayout(LayoutKind.Sequential)] public struct POINTL { public int x; public int y; }
I ran into exactly the same problem, both from C# and after following the advice here to try it in C++. I eventually discovered that the thing the Microsoft documentation doesn't make clear is that the request to set the primary monitor will be ignored (but with the operation reported as successful!) unless you also set the position of the monitor to (0, 0) on the DEVMODE struct. Of course, this means that you also need to shift the positions of your other monitors so that they stay in the same place relative to the new primary monitor. Per the documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx), call ChangeDisplaySettingsEx for each monitor with the CDS_NORESET flag and then make a final call with everything null. The following code worked for me: public static void SetAsPrimaryMonitor(uint id) { var device = new DISPLAY_DEVICE(); var deviceMode = new DEVMODE(); device.cb = Marshal.SizeOf(device); NativeMethods.EnumDisplayDevices(null, id, ref device, 0); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode); var offsetx = deviceMode.dmPosition.x; var offsety = deviceMode.dmPosition.y; deviceMode.dmPosition.x = 0; deviceMode.dmPosition.y = 0; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref deviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); device = new DISPLAY_DEVICE(); device.cb = Marshal.SizeOf(device); // Update remaining devices for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++) { if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id) { device.cb = Marshal.SizeOf(device); var otherDeviceMode = new DEVMODE(); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode); otherDeviceMode.dmPosition.x -= offsetx; otherDeviceMode.dmPosition.y -= offsety; NativeMethods.ChangeDisplaySettingsEx( device.DeviceName, ref otherDeviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); } device.cb = Marshal.SizeOf(device); } // Apply settings NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null); } Note that a signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter obviously won't allow you to pass in IntPtr.Zero. Create yourself two different signatures for the same extern call, i.e. [DllImport("user32.dll")] public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll")] public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
I can't really help you with the winapi-stuff but if you are using a Nvidia card you may have a look at the NVcontrolPanel Api Documentation Then you could make the secondary output your primary using rundll32.exe NvCpl.dll,dtcfg primary 2 Hope that will help you.
According to the documentation for ChangeDisplaySettingsEx, "the dmSize member must be initialized to the size, in bytes, of the DEVMODE structure." Furthermore, the EnumDisplaySettings documentation states, "Before calling EnumDisplaySettings, set the dmSize member to sizeof(DEVMODE), and set the dmDriverExtra member to indicate the size, in bytes, of the additional space available to receive private driver data". I don't see this happening in the code sample given in the question; that's one reason why it may be failing. Additionally, you might have errors in the definitions of the DEVMODE and DISPLAY_DEVICE structs, which were not included in the question. Roger Lipscombe's suggestion to get it working from C/C++ first is an excellent way to rule out this type of problem. Finally, check the return value from ChangeDisplaySettingsEx and see if that gives a clue as to why it might be failing.