この時点で、これをPythonで直接実現するためのエレガントな方法はないようです。私が思いつくことができる最も近いのは、私が呼び出せるC++で書かれたdllでした。私は、完全なバイナリDevMode構造で終わり、そこからリロードすることができます。そのC++のdllのコードは次のようになります。
Pythonで
#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->lpfnSetupHook = SetupHookProc; //removed: doing things differently, don't like how this was working
}
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;
}
、それはそうのように呼ばれています:
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