保存/恢复打印机 DevModes - wxPython/win32print [英] Saving / Restoring Printer DevModes - wxPython / win32print

查看:67
本文介绍了保存/恢复打印机 DevModes - wxPython/win32print的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

到目前为止,我已经找到了两种不同的方法来访问我认为从 wxPython 用户界面访问打印机 DevMode 的等效版本:

So far I've found two different ways to access what I believe are equivalent versions of the Printer DevMode from a wxPython User Interface:

window = wx.GetTopLevelWindows()[0].GetHandle()
name = self.itemMap['device'].GetValue() # returns a valid printer name.
handle = win32print.OpenPrinter(name)
dmin = None
dmout = pywintypes.DEVMODEType()
mode = DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT

res = win32print.DocumentProperties(window, handle, name, dmout, dmin, mode)

if res == 1:
  print dmout.DriverData

还有

dlg = wx.PrintDialog(self, dgData)

res = dlg.ShowModal()

if res == wx.ID_OK:
  print dlg.GetPrintDialogData().PrintData.GetPrivData()

这些二进制结构似乎包含控制设备输出行为的必要信息.这很好,只是它不能直接用于使用此存储的开发模式数据重新加载 PrintSetup 对话框.在第一种情况下,PyDEVMODE 对象包含许多需要手动设置的单独属性(PyDEVMODE 参考).在第二种情况下,有少数 Getter/Setter 方法可以控制某些属性,但不是全部(wxPrintData 参考).有没有人知道从实际的 DevMode(二进制数据)创建 Python Devmode 对象的方法(我将采用任何一种方法,差异是微不足道的)?我想避免必须手动存储/重置每个单独的属性,以便每次都以正确的状态重新打开对话框.

These to binary structures appear to contain the necessary information to control the device output behavior. This is fine and well, except that it can't be directly used to reload the PrintSetup dialogs with this stored devmode data. In the first case the PyDEVMODE object contains dozens of individual properties that need to be manually set (PyDEVMODE Reference). In the second case there are a handful of Getter / Setter methods that control some of the properties, but not all of them (wxPrintData Reference). Is anyone aware of a way to create a Python Devmode Object (I'll take either approach, the differences are trivial) from the actual DevMode (the binary data)? I'd like to avoid having to manually store / reset each individual attribute in order for the dialogs to re-open in the correct state every time.

推荐答案

目前似乎没有一种优雅的方法可以直接在 Python 中实现这一点.我能想到的最接近的是一个用 C++ 编写的 dll,我可以调用它.我最终得到了完整的二进制 DevMode 结构,并且可以从中重新加载.该 c++ dll 的代码如下所示:

It appears that at this point there's no elegant way to achieve this directly in Python. The closest I was able to come up with was a dll written in c++ that I'm able to call into. I end up with the full binary DevMode Structure, and can reload from it. The code for that c++ dll looks like this:

#include "stdafx.h"
#include <iobind/base64_policy.hpp>

#include <string>
#ifdef _UNICODE
    typedef std::wstring string_t;
#else
    typedef std::string string_t;
#endif
typedef std::string cstring;


extern "C" BOOL WINAPI DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved ) {
    switch ( dwReason ){
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls( hModule );
            break;
        case DLL_PROCESS_DETACH:
            break;
    }

    return TRUE;
}


extern "C" DOEXPORT int CleanupA( char *output ) {
    if ( output ) {
        free( output );
        output = NULL;
    }
    return 0;
}


extern "C" DOEXPORT int CleanupW( wchar_t *output ) {
    if ( output ) {
        free( output );
        output = NULL;
    }
    return 0;
}


extern "C" DOEXPORT int printer_setup( 
        void *handle, const TCHAR *printer_in, const char *input,
        int local_only, TCHAR **printer, char **output ) 
{
    HWND hwnd = (HWND)handle;   
    HRESULT hResult = 0;

    LPPRINTDLG pPD = NULL;
    LPPRINTPAGERANGE pPageRanges = NULL;

    // Allocate structure.
    pPD = (LPPRINTDLG)GlobalAlloc(GPTR, sizeof(PRINTDLG));
    if (!pPD) return E_OUTOFMEMORY;

    //  Initialize structure.
    pPD->lStructSize = sizeof(PRINTDLG);
    pPD->hwndOwner = hwnd;

    pPD->hDevMode = NULL;
    if ( input ){
        std::string dec = iobind::encode( input, iobind::from_base64_p );
        if ( !dec.empty() ) {
            HGLOBAL devmode = pPD->hDevMode = ::GlobalAlloc(GPTR, dec.size());
            if ( devmode ){         
                LPDEVMODE src = (LPDEVMODE)&dec[0];
                memcpy( devmode, src, dec.size() );
            }
        }
    }

    pPD->hDevNames = NULL;
    if ( printer_in ){
        HGLOBAL printer = pPD->hDevNames = ::GlobalAlloc(GPTR, sizeof(DEVNAMES)+_tcslen(printer_in)*sizeof(TCHAR)+sizeof(TCHAR));
        if ( printer ){
            LPDEVNAMES dv = (LPDEVNAMES)printer;
            dv->wDefault = 0;
            dv->wDriverOffset = 0;
            dv->wOutputOffset = 0;
            dv->wDeviceOffset = sizeof(DEVNAMES)/sizeof(TCHAR);
            TCHAR *dest = (TCHAR *)(unsigned long)dv + dv->wDeviceOffset;
            _tcscpy( dest, printer_in );
        }
    }

    pPD->hDC = NULL;
    pPD->Flags = PD_PRINTSETUP;

    if ( local_only ) {
        pPD->Flags |= /*PD_ENABLESETUPHOOK |*/ PD_NONETWORKBUTTON;
    }

    pPD->nMinPage = 1;
    pPD->nMaxPage = 1000;
    pPD->nCopies = 1;
    pPD->hInstance = 0;
    pPD->lpPrintTemplateName = NULL;

    //  Invoke the Print property sheet.
    hResult = PrintDlg(pPD);
    if ( hResult != 0 ) {
        if ( pPD->hDevMode ) {
            LPDEVMODE devmode = (LPDEVMODE)::GlobalLock( pPD->hDevMode );
            size_t size = devmode->dmSize + devmode->dmDriverExtra;
            if ( output ) {
                std::string tmp;
                tmp.resize( size );
                memcpy( &tmp[0], devmode, tmp.size() );

                std::string enc = iobind::encode( tmp, iobind::to_base64_p );
                *output = _strdup( enc.c_str() );
            }
            ::GlobalUnlock( pPD->hDevMode );
        }

        if ( pPD->hDevNames ) {
            LPDEVNAMES devnames = (LPDEVNAMES)::GlobalLock( pPD->hDevNames );
            TCHAR *device = (TCHAR *)(unsigned long)devnames + devnames->wDeviceOffset;
            *printer = _tcsdup(device);
            ::GlobalUnlock( pPD->hDevNames );
        }
    }
    else {
        DWORD dlgerr = ::CommDlgExtendedError();
        hResult = dlgerr;
    }

    if (pPD->hDC != NULL) {
        DeleteDC( pPD->hDC );
    }
    if (pPD->hDevMode != NULL) { 
        GlobalFree( pPD->hDevMode );
    }
    if (pPD->hDevNames != NULL) {
        GlobalFree( pPD->hDevNames );
    }
    return hResult;
}

在 Python 中,它是这样调用的:

In Python, it's called into like so:

client = ctypes.cdll.LoadLibrary(os.path.join(myDir, 'rpmclient.dll'))
client.printer_setup.argtypes = [ctypes.c_void_p,
                                 ctypes.c_wchar_p,
                                 ctypes.c_char_p,
                                 ctypes.c_int32,
                                 ctypes.POINTER(ctypes.c_wchar_p),
                                 ctypes.POINTER(ctypes.c_char_p)]

client.printer_setup.restype = ctypes.c_int32
client.CleanupA.argtypes = [ctypes.c_char_p]
client.CleanupA.restype = ctypes.c_int32
client.CleanupW.argtypes = [ctypes.c_wchar_p]
client.CleanupW.restype = ctypes.c_int32

p_in = ctypes.c_wchar_p(self.itemMap['device'].GetValue())
p_out = ctypes.c_wchar_p()

d_in = ctypes.c_char_p(getattr(self, 'devmode', ''))
d_out = ctypes.c_char_p()

res = client.printer_setup(self.GetHandle(),
                           p_in,
                           d_in,
                           False,
                           p_out,
                           d_out)

if res == 0:
  return

if res > 1:
  # Error display code here.

  return

self.devmode = d_out.value

这篇关于保存/恢复打印机 DevModes - wxPython/win32print的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆