Есть ли в PrinterSettings.GetHdevmode () ошибка? - PullRequest
8 голосов
/ 13 марта 2010

Я бы хотел иметь возможность изменять свойства принтера без вызова окна свойств принтера ...

Использование функции DocumentProperties (импортированной из winspool.drv) до сих пор не удавалось, потому что, хотя диалоговое окно легко скрыть, кажется, что значение, возвращаемое PrinterSettings.GetHdevmode (), не отражает PrinterSettings, который вызывает его, но вместо этого значение из предыдущих свойств принтера возвращает ОК. Например, это дает мне предыдущие (неправильные) значения из последнего вызова свойств вместо значений, которые должны быть у объекта PrinterSettings:

IntPtr hdevmode = PrinterSettings.GetHdevmode(PrinterSettings.DefaultPageSettings);
PrinterSettings.SetHdevmode(hdevmode);
PrinterSettings.DefaultPageSettings.SetHdevmode(hdevmode);

Так есть ли в GetHdevmode ошибка или это то, что он должен делать? Есть ли обходной путь для C # или у кого-нибудь есть информация об этом? Мне было трудно даже найти информацию по теме.

Заранее благодарим за понимание.

EDIT: Я не хотел делать это слишком личной проблемой, но, надеюсь, наличие всей информации в этом случае может дать ответ, который будет полезным решением и для других.

Вот C ++ DLL, которую я написал, чтобы обойти эту проблему. В настоящее время он не работает - он изменяет другую память, такую ​​как копии, и не может изменить «базовый» размер бумаги. Я думал, что все, что мне нужно было сделать, это указать флаг буфера для внесения изменений?

extern "C" __declspec(dllexport) DEVMODE* __stdcall GetRealHDevMode(int width, int height, char *printerName, DEVMODE* inDevMode)
    {
//declare handles and variables
HANDLE printerHandle;
LPHANDLE printerHandlePointer(&printerHandle);

//get printer handle pointer
OpenPrinter((LPWSTR)printerName, printerHandlePointer, NULL);

//Get size needed for public and private devmode data and declare devmode structure
size_t devmodeSize = DocumentProperties(NULL, printerHandle, (LPWSTR)printerName, NULL, NULL, 0);
DEVMODE* devmode = reinterpret_cast<DEVMODE*>(new char[devmodeSize + sizeof(DEVMODE) + sizeof(inDevMode->dmDriverExtra)]);

//lock memory
GlobalLock(devmode);

//fill the out buffer
DocumentProperties(NULL, printerHandle, (LPWSTR)printerName, devmode, NULL, DM_OUT_BUFFER);

//change the values as required
devmode->dmPaperWidth = width;
devmode->dmPaperLength = height;
devmode->dmPaperSize = DMPAPER_USER;

devmode->dmFields &= ~DM_PAPERSIZE;
devmode->dmFields &= ~DM_PAPERLENGTH;
devmode->dmFields &= ~DM_PAPERWIDTH;
devmode->dmFields |= (DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH);

//input flag on now to put the changes back in
DocumentProperties(NULL, printerHandle, (LPWSTR)printerName, devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER);

//unlock memory
GlobalUnlock(devmode);

//return the devmode that was used to alter the settings
return devmode;
    }

Я подумал, что кода C ++ было достаточно для изменения настроек, поэтому все, что я делаю в C #, это:

public PrinterSettings ChangePrinterProperties(PrinterSettings inPrinterSettings)
    {
        IntPtr TemphDevMode = inPrinterSettings.GetHdevmode(inPrinterSettings.DefaultPageSettings);
        IntPtr hDevMode = GetRealHDevMode((int)(inPrinterSettings.DefaultPageSettings.PaperSize.Width * 2.54F),
            (int)(inPrinterSettings.DefaultPageSettings.PaperSize.Height * 2.54F),
            inPrinterSettings.PrinterName, TemphDevMode);
        GlobalFree(hDevMode);
        return inPrinterSettings;
    }

ОБНОВЛЕНИЕ: Немного изменили порядок с помощью dmPaperSize и dmFields. Улучшенные результаты; еще не совсем там.

ОБНОВЛЕНИЕ 2: Хорошо, я нашел страницу Microsoft, которая говорит, что документация неверна. MSDN говорит, что нужно установить dmPaperSize в 0, когда вы хотите указать ширину и высоту, тогда как исправление службы поддержки Microsoft говорит, чтобы установить его в DMPAPER_USER. http://support.microsoft.com/kb/108924

1 Ответ

2 голосов
/ 02 апреля 2010

Существуют 2 проблемы с указанием формата бумаги в DEVMODE:

(1) Если вы указываете DM_PAPERWIDTH или DM_PAPERLENGTH или оба, вы НЕ ДОЛЖНЫ также устанавливать бит DM_PAPERSIZE. Это зависит от драйвера принтера, но многие драйверы игнорируют DM_PAPERLENGTH / WIDTH в приведенном выше коде.

(2) Многие драйверы вообще не поддерживают DM_PAPERLENGTH / WIDTH. С такими драйверами вы просто не можете установить размер бумаги, как вы пытаетесь сделать выше. Вы можете выбрать только один из предопределенных dmPaperSizes.

Вы можете использовать DeviceCapabilities (DC_FIELDS), чтобы определить, поддерживает ли ваш драйвер DM_PAPERLENGTH / WIDTH.

Вы можете использовать DeviceCapabilities (DC_PAPERS) для перечисления допустимых dmPaperSizes.

...