Добрый день!
Я пишу программку на C#, задача которой — изменение настроек принтера с помощью функции WinAPI DocumentProperties. Точнее, я хочу изменить приватные настройки драйвера принтера, путем изменения битового содержимого памяти, полученного при считывании настроек.
Вот код, который я использую:
public enum DevModeOption
{
DM_UPDATE = 1,
DM_COPY = 2,
DM_PROMPT = 4,
DM_MODIFY = 8,
DM_IN_BUFFER = DM_MODIFY,
DM_IN_PROMPT = DM_PROMPT,
DM_OUT_BUFFER = DM_COPY,
DM_OUT_DEFAULT = DM_UPDATE,
}
[DllImport("WinSpool.drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
static extern unsafe int DocumentProperties(IntPtr hWnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceName,
IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
public void SetPrinterData(IntPtr formHandle, string PrinterName, List<DifferByteInfo> differBytes)
{
PrinterSettings psSettings = new PrinterSettings();
psSettings.PrinterName = PrinterName;
IntPtr ipDevMode = psSettings.GetHdevmode(psSettings.DefaultPageSettings);
IntPtr pDevMode = GlobalLock(ipDevMode);
IntPtr ipDevModeData = Marshal.AllocHGlobal(0);
try
{
int nSize = DocumentProperties(formHandle, IntPtr.Zero, psSettings.PrinterName, pDevMode, pDevMode, 0);
ipDevModeData = Marshal.AllocHGlobal(nSize);
DocumentProperties(formHandle, IntPtr.Zero, psSettings.PrinterName, ipDevModeData, pDevMode,
(int)DevModeOption.DM_OUT_BUFFER);
DEVMODE d2 = (DEVMODE)Marshal.PtrToStructure(ipDevModeData, typeof(DEVMODE));
foreach (DifferByteInfo b in differBytes)
{
Marshal.WriteByte(ipDevModeData, d2.dmSize + b.index, b.value);
}
//DocumentProperties(formHandle, IntPtr.Zero, psSettings.PrinterName, IntPtr.Zero, ipDevModeData,(int)DevModeOption.DM_MODIFY);
//DocumentProperties(formHandle, IntPtr.Zero, psSettings.PrinterName, ipDevModeData, ipDevModeData,
// (int) DevModeOption.DM_IN_BUFFER + (int) DevModeOption.DM_OUT_BUFFER);
DocumentProperties(formHandle, IntPtr.Zero, psSettings.PrinterName, IntPtr.Zero, ipDevModeData, (int)DevModeOption.DM_IN_BUFFER);
GlobalUnlock(ipDevMode);
}
finally
{
GlobalFree(ipDevMode);
Marshal.FreeHGlobal(ipDevModeData);
}
}
К сожалению он не работает. Подскажите, пожалуйста, в чем может быть дело?
С уважением, Николай.
Думаю, решение уже нашлось. Но т.к. я тоже с этим провел почти весь день, и начинал я с Ваших набросок, вот что у меня получилось.
Пришлось всеже использовать SetPrinter. Может кто еще сюда заглянет, подскажет другой метод.
private uint PRINTER_ALL_ACCESS = 0x00000004 | 0x00000008;
...........
.........
.......
..........
private unsafe void button2_Click(object sender, EventArgs e)
{
PrinterDefaults pd = new PrinterDefaults();
pd.pDatatype = UIntPtr.Zero;
pd.pDevMode = UIntPtr.Zero;
pd.DesiredAccess = PRINTER_ALL_ACCESS;
PrinterSettings.StringCollection printers = PrinterSettings.InstalledPrinters;
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = printers[3];
IntPtr printerHandle;
bool result = OpenPrinter(printers[3], out printerHandle,ref pd);
IntPtr prS;
int hDEVMODE = DocumentProperties(this.Handle, printerHandle, printers[3], IntPtr.Zero, IntPtr.Zero, 0);
prS = GlobalAlloc(0, hDEVMODE);
IntPtr pDEVMODE = GlobalLock(prS);
int dwRet = DocumentProperties(this.Handle,
printerHandle,
printers[3],
pDEVMODE,
IntPtr.Zero,
2|4);
PrinterSettings nPS;
if (dwRet < 0)
{
GlobalUnlock(pDEVMODE);
GlobalFree(prS);
ClosePrinter(printerHandle);
return;
}
else
{
nPS = new PrinterSettings();
nPS.SetHdevmode(pDEVMODE);
}
GlobalUnlock(pDEVMODE);
GlobalFree(prS);
Byte* b = (Byte*)nPS.GetHdevmode();
bool r = SetPrinter(printerHandle, 8, b, 0);
ClosePrinter(printerHandle);
GlobalFree((IntPtr)b);
}
}