Как я могу сохранить и восстановить `PrinterSettings`?

У меня есть приложение, которое мы хотим сохранить PrinterSettings пользователь выбирает реестр, а затем восстанавливает их, когда мы готовы к печати. Есть ли способ сериализации PrinterSettings?

1 ответ

Решение

Целостность PrinterSettings - включая специфические параметры поставщика - можно сохранить, сохранив HDEVMODE структура получена через PrinterSettings.GetHdevmode(), затем восстановлен через PrinterSettings.SetHdevmode(IntPtr),

Класс ниже добавит два метода расширения для сохранения и восстановления PrinterSettings и из byte массив.

Предостережение: некоторые драйверы принтеров не имеют обратной или прямой совместимости и могут аварийно завершить работу при использовании постоянных данных из другой версии или архитектуры драйвера.

Пример использования:

PrinterSettings CurrentSettings;
const string myAppKeyName = @"Software\MyApplicationName";
const string printerSettingValueName = "PrinterSettings"

// save
using (var sk = Registry.CurrentUser.CreateSubKey(myAppKeyName))
{
    sk.SetValue(printerSettingValueName, this.CurrentSettings.GetDevModeData(), RegistryValueKind.Binary);
}

// restore
using (var sk = Registry.CurrentUser.CreateSubKey(myAppKeyName))
{
    var data = sk.GetValue(printerSettingValueName, RegistryValueKind.Binary) as byte[];

    this.CurrentSettings = new PrinterSettings();
    if (data != null)
    {
        this.CurrentSettings.SetDevModeData(data);
    }
}

Реализация:

static class PrinterSettingsExtensions
{
    public static byte[] GetDevModeData(this PrinterSettings settings)
    {
        //Contract.Requires(settings != null);

        byte[] devModeData;
        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
            // cer since hDevMode is not a SafeHandle
        }
        finally
        {
            var hDevMode = settings.GetHdevmode();
            try
            {
                IntPtr pDevMode = NativeMethods.GlobalLock(hDevMode);
                try
                {
                    var devMode = (NativeMethods.DEVMODE)Marshal.PtrToStructure(
                        pDevMode, typeof(NativeMethods.DEVMODE));

                    var devModeSize = devMode.dmSize + devMode.dmDriverExtra;
                    devModeData = new byte[devModeSize];
                    Marshal.Copy(pDevMode, devModeData, 0, devModeSize);
                }
                finally
                {
                    NativeMethods.GlobalUnlock(hDevMode);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(hDevMode);
            }
        }
        return devModeData;
    }

    public static void SetDevModeData(this PrinterSettings settings, byte[] data)
    {
        //Contract.Requires(settings != null);
        //Contract.Requires(data != null);
        //Contract.Requires(data.Length >= Marshal.SizeOf(typeof(NativeMethods.DEVMODE)));

        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
            // cer since AllocHGlobal does not return SafeHandle
        }
        finally
        {
            var pDevMode = Marshal.AllocHGlobal(data.Length);
            try
            {
                // we don't have to worry about GlobalLock since AllocHGlobal only uses LMEM_FIXED
                Marshal.Copy(data, 0, pDevMode, data.Length);
                var devMode = (NativeMethods.DEVMODE)Marshal.PtrToStructure(
                        pDevMode, typeof(NativeMethods.DEVMODE));

                // The printer name must match the original printer, otherwise an AV will be thrown
                settings.PrinterName = devMode.dmDeviceName;

                // SetHDevmode creates a copy of the devmode, so we don't have to keep ours around
                settings.SetHdevmode(pDevMode);
            }
            finally
            {
                Marshal.FreeHGlobal(pDevMode);
            }
        }
    }
}

static class NativeMethods
{
    private const string Kernel32 = "kernel32.dll";

    [DllImport(Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern IntPtr GlobalLock(IntPtr handle);

    [DllImport(Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern bool GlobalUnlock(IntPtr handle);

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Auto)]
    public struct DEVMODE
    {
        private const int CCHDEVICENAME = 32;
        private const int CCHFORMNAME = 32;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
        public string dmDeviceName;
        public short dmSpecVersion;
        public short dmDriverVersion;
        public short dmSize;
        public short dmDriverExtra;
        public int dmFields;

        public int dmPositionX;
        public int dmPositionY;
        public int dmDisplayOrientation;
        public int dmDisplayFixedOutput;

        public short dmColor;
        public short dmDuplex;
        public short dmYResolution;
        public short dmTTOption;
        public short dmCollate;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
        public string dmFormName;
        public short dmLogPixels;
        public int dmBitsPerPel;
        public int dmPelsWidth;
        public int dmPelsHeight;
        public int dmDisplayFlags;
        public int dmDisplayFrequency;
        public int dmICMMethod;
        public int dmICMIntent;
        public int dmMediaType;
        public int dmDitherType;
        public int dmReserved1;
        public int dmReserved2;
        public int dmPanningWidth;
        public int dmPanningHeight;
    }
}

Связанные с:

Другие вопросы по тегам