PythonからWindows Spoolerをctypesで叩く

#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""\
Utility class for wrapping Winspool.drv with ctypes.

GetPrinter function
http://msdn.microsoft.com/en-us/library/windows/desktop/dd144911(v=vs.85).aspx

PRINTER_INFO_1 structure
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162844(v=vs.85).aspx
"""
__author__ = "Youhei Sakurai"
__copyright__ = "(C) 2013 Youhei Sakurai"
__email__ = "sakurai dot youhei at gmail dot com"
__license__ = "MIT"
__version__ = "0.0.1"

import ctypes
import ctypes.wintypes
LPTSTR = ctypes.c_char_p

class PRINTER_INFO_1(ctypes.Structure):
  _fields_ = [
    ("Flags", ctypes.wintypes.DWORD),
    ("pDescription", LPTSTR),
    ("pName", LPTSTR),
    ("pComment", LPTSTR),
  ]
  PrinterEnumFlags = {
    0x00004000: "PRINTER_ENUM_EXPAND",
    0x00008000: "PRINTER_ENUM_CONTAINER",
    0x00010000: "PRINTER_ENUM_ICON1",
    0x00020000: "PRINTER_ENUM_ICON2",
    0x00040000: "PRINTER_ENUM_ICON3",
    0x00080000: "PRINTER_ENUM_ICON4",
    0x00100000: "PRINTER_ENUM_ICON5",
    0x00200000: "PRINTER_ENUM_ICON6",
    0x00400000: "PRINTER_ENUM_ICON7",
    0x00800000: "PRINTER_ENUM_ICON8",
    "PRINTER_ENUM_EXPAND": 0x00004000,
    "PRINTER_ENUM_CONTAINER": 0x00008000,
    "PRINTER_ENUM_ICON1": 0x00010000,
    "PRINTER_ENUM_ICON2": 0x00020000,
    "PRINTER_ENUM_ICON3": 0x00040000,
    "PRINTER_ENUM_ICON4": 0x00080000,
    "PRINTER_ENUM_ICON5": 0x00100000,
    "PRINTER_ENUM_ICON6": 0x00200000,
    "PRINTER_ENUM_ICON7": 0x00400000,
    "PRINTER_ENUM_ICON8": 0x00800000,
  }

class WinSool(object):
  def __init__(self):
    self.winspool = ctypes.WinDLL("Winspool.drv")

  def get_PRINTER_INFO_1(self, printer_name):
    hPrinter=ctypes.wintypes.HANDLE()
    dwNeeded=ctypes.wintypes.DWORD()
    ret = self.winspool.OpenPrinterA(
      ctypes.c_char_p(printer_name), ctypes.byref(hPrinter), None)
    if ret==0:
      raise Exception, "OpenPrinterA failed"
    ret = self.winspool.GetPrinterA(
      hPrinter, 1, None, 0, ctypes.byref(dwNeeded))
    if ret==0:
      pass # Always failed as expected
    Printer=(ctypes.c_ubyte*dwNeeded.value)()
    ret = self.winspool.GetPrinterA(
      hPrinter, 1, ctypes.byref(Printer), dwNeeded, ctypes.byref(dwNeeded))
    if ret==0:
      raise Exception, "GetPrinterA failed"
    pInfo = ctypes.cast(Printer, ctypes.POINTER(PRINTER_INFO_1))
    pName = pInfo.contents.pName
    pDescription = pInfo.contents.pDescription
    pComment = pInfo.contents.pComment
    Flags = []
    for k,v in PRINTER_INFO_1.PrinterEnumFlags.items():
      if type(k)==int:
        if k & pInfo.contents.Flags > 0:
          Flags.append(v)
    ret = self.winspool.ClosePrinter(hPrinter)
    if ret==0:
      raise Exception, "ClosePrinter failed"
    return (Flags, pDescription, pName, pComment)

if __name__=="__main__":
  winspool = WinSool()
  print winspool.get_PRINTER_INFO_1("TestPrinter")

実行結果

C:\>test.py
(['PRINTER_ENUM_ICON8'], 'TestPrinter,FX ApeosPort-IV C3375,', 'TestPrinter', '')