VBA Win32API Win64 API 共用 Spool Class Use Printer Spooler API

#Main Module
##仕様
これはExcelから他のアプリケーションに関連付けられているファイルを関連付けられたアプリーケーションで呼び出し、印刷させて、Spoolで印刷が終了したのを検知したら、そのアプリケーションを終了させるという動作を行います。今回はPublisherというマイナーなソフトですが、Winwordでも可能です。
しかしまだ想定外のバグやよくわかっていないところもあるので、責任は他のプログラムと同様負えません。VBAのWINAPIの資料はほとんどなく64に至っては全くないといっていい感じですから。

##重要な注意点　実行前に保存
これはバグを起こすとExcelが終了します(Excel2013以降はその後復活します)しかし、変更は反映されないこともあるので、必ず保存して実行してください。
##重要な注意点 SleepとFindWindow
メインモジュールにはスリープとFindWindowをPrivateで宣言してください。Classや他のモジュールでも使用するようになるとエラーを起こしかねないので念のためのPrivate宣言です。
###重要な注意点 1枚あたりの印刷の時間は長めに
この時1枚の印刷にかかる時間より基本の時間を長めにしてください。現在1枚あたり最大3分かかるとしています。写真などは5分かかる場合もあるでしょう。そういう場合には
`If iSpool = 180 * ((lngEndPage - lngStartPage + 1) * lngCopiesCount) Then Exit Do`
この180を1枚あたり5分かかるのであれば5*60=300にしてください。
なぜかというと印刷が終わる前にSpool判定を抜けると、Excelが落ちてしまうからです
また印刷を中止、強制終了にしても抜けます。なのでLoopを抜けたいときは印刷をプリンター側で中止してください。
すると正常終了します。
ダサい変数の名前ですが、長整数なのか長長整数なのか長点整数なのかわかりにくいのでお許しを。
###逆順は設定できない
計算がおかしくなるので順番に印刷します。
## TaskID
印刷させるためのファイルに紐づけられているアプリケーションのタスクIDを調べる必要があります。
これは下記プログラム内のURLに書いてある場合があります。
##共用の場合、ハンドルを分ける
ハンドルはLongPtrになるので、サブプロシージャでも条件付き編纂分岐があります。

```vb:Mainmodule
Option Explicit
'Main Module

#If VBA7 Then
'https://www.vba-ie.net/function/sleep.php
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If
#If VBA7 Then
'http://excel.syogyoumujou.com/memorandum/get_hwnd.html
    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As LongPtr
    Dim myHwnd As LongPtr
#Else
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, _
        ByVal lpWindowName As String) As Long
    Dim myHwnd As Long
#End If


Sub Main()
#If VBA7 Then
 Dim TaskId As LongPtr 'タスクID
 Dim hProc As LongPtr 'プロセスハンドル
#Else
 Dim TaskId As Long 'タスクID
 Dim hProc As Long 'プロセスハンドル
#End If
Dim iSpool As Long, clsSpool As clsWin32isPrintSpool: Set clsSpool = New clsWin32isPrintSpool
Dim pbApp As Publisher.Application
Dim objPbDoc As Publisher.Document
Dim lngStartPage As Long, lngEndPage As Long, lngCopiesCount As Long
' ----- StackOverFlow ------------
’ https://stackoverflow.com/questions/7007760/print-raw-text-from-vb-net-using-dot-matrix-printer/7008415#7008415
'Dim printerHandle As Long, retVal As Long
'Dim bytesWritten As Long, lDoc As Long
'Dim s1 As String, MyDocInfo As DOCINFO
' ----- StackOverFlow ------------

Set pbApp = New Publisher.Application: DoEvents: Sleep 500
TaskId = FindWindow("MSWinPub", vbNullString) 'Task ID Handle 'http://www.cpearson.com/excel/OfficeAppsWindowClasses.aspx
pbApp.Open "C:\Users\name\Documents\test.pub", True: pbApp.ActiveWindow.Visible = True
Set objPbDoc = pbApp.ActiveDocument: DoEvents: Sleep 500
lngStartPage = 1
lngEndPage = 1
lngCopiesCount = 1 '部数
objPbDoc.PrintOutEx From:=lngStartPage, To:=lngEndPage, Copies:=lngCopiesCount, PrintStyle:=Publisher.pbPrintStyleDefault: DoEvents: Sleep 1000
Sleep 2000
iSpool = 0
Do Until clsSpool.isPrinterSpool = False
Sleep 1000
iSpool = iSpool + 1: DoEvents
'1枚あたり最大3分かかるとしてスタートからエンドを引いて1を足す、これに部数をかける。これで総枚数が出るので、これを3分にかけてプリンターの終了を感知。
' 終了する前にループを抜けるとExcelが落ちる。なので長めに設定する
If iSpool = 180 * ((lngEndPage - lngStartPage + 1) * lngCopiesCount) Then Exit Do
Loop
'If MsgBox(i + 1 & "/" & UBound(arRow) + 1 & "枚目" & arCompany(i) & "の印刷が終わっていたらOKを押してください。これで終了する場合はキャンセルを押してください", vbOKCancel, "印刷中です") = vbCancel Then Exit Sub
objPbDoc.Close: DoEvents 'Publisherのドキュメントを無変更で閉じる(変更する場合はSaveを使う)
pbApp.Quit: DoEvents 'Publisherを終了させる
Set pbApp = Nothing: DoEvents 'Publisherのオブジェクトをいったん開放する
End Sub
```

##Class Module
clsWin32isPrintSpoolという名前にしてください。
これは、この２つからClassにしています。
https://okwave.jp/qa/q103563.html
https://oshiete.goo.ne.jp/qa/103563.html
主としてこれらのサイトを参考にして64Bit化しました
https://jkp-ads.com/Articles/apideclarations.asp
https://www.cadsharp.com/docs/Win32API_PtrSafe.txt
###ポイント：EnumJobs

```vb
' バッファの必要なサイズを取得
Call EnumJobs(lngPrinterHandle, lngJobInfo1FirstJob, lngJobInfo1EnumerateJob, lngJobInfo1Level, _
ByVal vbNullString, 0, lngJobInfo1Needed, lngJobInfo1Returned)
```

こことEnumjobsの宣言が適合していないとエラーになります
しかし、これで完全なのかわかりません。
いくつかのバリエーションがあります。



###ポイント EnumPrinterPropertySheets の64bit
これは探しても見つかりません。
このため他のDLLから共通する変数を調べ、その型に合わせました。


```vb
Option Explicit
' Class Name = "clsWin32isPrintSpool"

#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If
' Type definitions for Windows' basic types.
Private Const ANYSIZE_ARRAY = 1
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

Private Type RECTL
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

Private Type POINTAPI
x As Long
y As Long
End Type

Private Type POINTL
x As Long
y As Long
End Type

Private Type Size
cx As Long
cy As Long
End Type

Private Type POINTS
x As Integer
y As Integer
End Type
#If VBA7 Then
Private Type MSG
hwnd As LongPtr
message As Long
wParam As LongPtr
lParam As LongPtr
time As Long
pt As POINTAPI
End Type
#Else
Private Type MSG
hwnd As Long
message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type
#End If
Private Const DELETE = &H10000
Private Const READ_CONTROL = &H20000
Private Const WRITE_DAC = &H40000
Private Const WRITE_OWNER = &H80000
Private Const SYNCHRONIZE = &H100000

Private Const STANDARD_RIGHTS_READ = (READ_CONTROL)
Private Const STANDARD_RIGHTS_WRITE = (READ_CONTROL)
Private Const STANDARD_RIGHTS_EXECUTE = (READ_CONTROL)
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const STANDARD_RIGHTS_ALL = &H1F0000
' Define the well known values for CreateNamedPipe nMaxInstances
Private Const PIPE_UNLIMITED_INSTANCES = 255

' Define the Security Quality of Service bits to be passed
' into CreateFile
Private Const SECURITY_CONTEXT_TRACKING = &H40000
Private Const SECURITY_EFFECTIVE_ONLY = &H80000

Private Const SECURITY_SQOS_PRESENT = &H100000
Private Const SECURITY_VALID_SQOS_FLAGS = &H1F0000
#If VBA7 Then
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As LongPtr
bInheritHandle As Long
End Type
Private Type OVERLAPPED
Internal As LongPtr
InternalHigh As LongPtr
offset As Long
OffsetHigh As Long
hEvent As LongPtr
End Type
Private Type PROCESS_INFORMATION
hProcess As LongPtr
hThread As LongPtr
dwProcessId As Long
dwThreadId As Long
End Type
#Else
Private Type OVERLAPPED
Internal As Long
InternalHigh As Long
offset As Long
OffsetHigh As Long
hEvent As Long
End Type

Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Boolean
End Type
Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type
#End If


Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type

Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type

' Clipboard Metafile Picture Structure
Private Type HANDLETABLE
objectHandle(1) As Long
End Type

Private Type METARECORD
rdSize As Long
rdFunction As Integer
rdParm(1) As Integer
End Type


Private Type METAFILEPICT
mm As Long
xExt As Long
yExt As Long
hMF As Long
End Type

Private Type METAHEADER
mtType As Integer
mtHeaderSize As Integer
mtVersion As Integer
mtSize As Long
mtNoObjects As Integer
mtMaxRecord As Long
mtNoParameters As Integer
End Type

Private Type ENHMETARECORD
iType As Long
nSize As Long
dParm(1) As Long
End Type

Private Type SIZEL
cx As Long
cy As Long
End Type

Private Type ENHMETAHEADER
iType As Long
nSize As Long
rclBounds As RECTL
rclFrame As RECTL
dSignature As Long
nVersion As Long
nBytes As Long
nRecords As Long
nHandles As Integer
sReserved As Integer
nDescription As Long
offDescription As Long
nPalEntries As Long
szlDevice As SIZEL
szlMillimeters As SIZEL
End Type

Private Type TEXTMETRIC
tmHeight As Long
tmAscent As Long
tmDescent As Long
tmInternalLeading As Long
tmExternalLeading As Long
tmAveCharWidth As Long
tmMaxCharWidth As Long
tmWeight As Long
tmOverhang As Long
tmDigitizedAspectX As Long
tmDigitizedAspectY As Long
tmFirstChar As Byte
tmLastChar As Byte
tmDefaultChar As Byte
tmBreakChar As Byte
tmItalic As Byte
tmUnderlined As Byte
tmStruckOut As Byte
tmPitchAndFamily As Byte
tmCharSet As Byte
End Type
' //////////////////////////////////////////////////////////////////////
' //
' ACL and ACE //
' //
' //////////////////////////////////////////////////////////////////////

'
' Define an ACL and the ACE format. The structure of an ACL header
' followed by one or more ACEs. Pictorally the structure of an ACL header
' is as follows:
'
' The current AclRevision is defined to be ACL_REVISION.
'
' AclSize is the size, in bytes, allocated for the ACL. This includes
' the ACL header, ACES, and remaining free space in the buffer.
'
' AceCount is the number of ACES in the ACL.
'

' begin_ntddk begin_ntifs
' This is the *current* ACL revision

Private Const ACL_REVISION = (2)

' This is the history of ACL revisions. Add a new one whenever
' ACL_REVISION is updated

Private Const ACL_REVISION1 = (1)
Private Const ACL_REVISION2 = (2)

Private Type ACL
AclRevision As Byte
Sbz1 As Byte
AclSize As Integer
AceCount As Integer
Sbz2 As Integer
End Type

#If VBA7 Then
Private Type SECURITY_DESCRIPTOR
Revision As Byte
Sbz1 As Byte
Control As Integer
Owner As LongPtr
Group As LongPtr
Sacl As ACL
Dacl As ACL
End Type
#Else
Private Type SECURITY_DESCRIPTOR
Revision As Byte
Sbz1 As Byte
Control As Long
Owner As Long
Group As Long
Sacl As ACL
Dacl As ACL
End Type
#End If
' //////////////////////////////////////////////////////////////////////
' //
' SECURITY_DESCRIPTOR //
' //
' //////////////////////////////////////////////////////////////////////
'
' Define the Security Descriptor and related data types.
' This is an opaque data structure.
'

' begin_ntddk begin_ntifs
'
' Current security descriptor revision value
'

Private Const SECURITY_DESCRIPTOR_REVISION = (1)
Private Const SECURITY_DESCRIPTOR_REVISION1 = (1)

' end_ntddk

'
' Minimum length, in bytes, needed to build a security descriptor
' (NOTE: This must manually be kept consistent with the)
' (sizeof(SECURITY_DESCRIPTOR) )
'

Private Const SECURITY_DESCRIPTOR_MIN_LENGTH = (20)



Private Const SE_OWNER_DEFAULTED = &H1
Private Const SE_GROUP_DEFAULTED = &H2
Private Const SE_DACL_PRESENT = &H4
Private Const SE_DACL_DEFAULTED = &H8
Private Const SE_SACL_PRESENT = &H10
Private Const SE_SACL_DEFAULTED = &H20
Private Const SE_SELF_RELATIVE = &H8000

' size of a device name string
Private Const CCHDEVICENAME = 32

' size of a form name string
Private Const CCHFORMNAME = 32
#If VBA7 Then
Private Type DEVMODE
dmDeviceName(0 To CCHDEVICENAME - 1) As Byte 'dmDeviceName(0 To CCHDEVICENAME - 1) As Byte
dmSpecVersion As Integer
dmDriverVersion As Integer
dmSize As Integer
dmDriverExtra As Integer
dmFields As Long
dmOrientation As Integer
dmPaperSize As Integer
dmPaperLength As Integer
dmPaperWidth As Integer
dmScale As Integer
dmCopies As Integer
dmDefaultSource As Integer
dmPrintQuality As Integer
dmColor As Integer
dmDuplex As Integer
dmYResolution As Integer
dmTTOption As Integer
dmCollate As Integer
dmFormName As String * CCHFORMNAME 'dmFormName(0 To CCHFORMNAME - 1) As Byte
dmUnusedPadding As Integer
dmBitsPerPel As Long
dmPelsWidth As Long
dmPelsHeight As Long
dmDisplayFlags As Long
dmDisplayFrequency As Long
'#if(WINVER >= 0x0400)
'dmICMMethod As Long 'Win 32 版は以下dwPanningHeight As Long まで宣言なし
'dmICMIntent As Long
'dmMediaType As Long
'dmDitherType As Long
'dmReserved1 As Long
'dmReserved2 As Long
' #if (WINVER >= 0x0500) || (_WIN32_WINNT >= _WIN32_WINNT_NT4)
'dwPanningWidth As Long
'dwPanningHeight As Long
' #endif
'#endif /* WINVER >= 0x0400 */
End Type
#Else
Private Type DEVMODE
dmDeviceName(0 To CCHDEVICENAME - 1) As Byte 'dmDeviceName As String * CCHDEVICENAME 'とするものあり
dmSpecVersion As Integer
dmDriverVersion As Integer
dmSize As Integer
dmDriverExtra As Integer
dmFields As Long
dmOrientation As Integer
dmPaperSize As Integer
dmPaperLength As Integer
dmPaperWidth As Integer
dmScale As Integer
dmCopies As Integer
dmDefaultSource As Integer
dmPrintQuality As Integer
dmColor As Integer
dmDuplex As Integer
dmYResolution As Integer
dmTTOption As Integer
dmCollate As Integer
dmFormName As String * CCHFORMNAME 'dmFormName(0 To CCHFORMNAME - 1) As Byte
dmUnusedPadding As Integer
dmBitsPerPel As Integer
dmPelsWidth As Long
dmPelsHeight As Long
dmDisplayFlags As Long
dmDisplayFrequency As Long
End Type
#End If
#If VBA7 Then
Private Declare PtrSafe Function GetProfileString Lib "kernel32" Alias "GetProfileStringA" (ByVal lpAppName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long) As Long
#Else
Private Declare Function GetProfileString Lib "kernel32" Alias "GetProfileStringA" (ByVal lpAppName As String, _
ByVal lpKeyName As String, ByVal lpDefault As String, _
ByVal lpReturnedString As String, ByVal nSize As Long) As Long
#End If
' ある位置から別の位置にメモリブロックを移動する関数の宣言
#If VBA7 Then
Private Declare PtrSafe Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As LongPtr)

#Else
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)
#End If
' -------------
' Print APIs
' -------------
#If VBA7 Then
Private Type PRINTER_INFO_1
flags As LongPtr
pDescription As String
pName As String
pComment As String
End Type
#Else
Private Type PRINTER_INFO_1
flags As Long
pDescription As String 'https://oshiete.goo.ne.jp/qa/8018928.html はpDescription As String pName As String pComment As String としている
pName As String
pComment As String
End Type

#End If
Private Type PRINTER_INFO_2
pServerName As String
pPrinterName As String
pShareName As String
pPortName As String
pDriverName As String
pComment As String
pLocation As String
pDevMode As DEVMODE
pSepFile As String
pPrintProcessor As String
pDatatype As String
pParameters As String
pSecurityDescriptor As SECURITY_DESCRIPTOR
Attributes As Long
Priority As Long
DefaultPriority As Long
StartTime As Long
UntilTime As Long
Status As Long
cJobs As Long
AveragePPM As Long
End Type

Private Type PRINTER_INFO_3
pSecurityDescriptor As SECURITY_DESCRIPTOR
End Type

Private Const PRINTER_CONTROL_PAUSE = 1
Private Const PRINTER_CONTROL_RESUME = 2
Private Const PRINTER_CONTROL_PURGE = 3

Private Const PRINTER_STATUS_PAUSED = &H1
Private Const PRINTER_STATUS_ERROR = &H2
Private Const PRINTER_STATUS_PENDING_DELETION = &H4
Private Const PRINTER_STATUS_PAPER_JAM = &H8
Private Const PRINTER_STATUS_PAPER_OUT = &H10
Private Const PRINTER_STATUS_MANUAL_FEED = &H20
Private Const PRINTER_STATUS_PAPER_PROBLEM = &H40
Private Const PRINTER_STATUS_OFFLINE = &H80
Private Const PRINTER_STATUS_IO_ACTIVE = &H100
Private Const PRINTER_STATUS_BUSY = &H200
Private Const PRINTER_STATUS_PRINTING = &H400
Private Const PRINTER_STATUS_OUTPUT_BIN_FULL = &H800
Private Const PRINTER_STATUS_NOT_AVAILABLE = &H1000
Private Const PRINTER_STATUS_WAITING = &H2000
Private Const PRINTER_STATUS_PROCESSING = &H4000
Private Const PRINTER_STATUS_INITIALIZING = &H8000
Private Const PRINTER_STATUS_WARMING_UP = &H10000
Private Const PRINTER_STATUS_TONER_LOW = &H20000
Private Const PRINTER_STATUS_NO_TONER = &H40000
Private Const PRINTER_STATUS_PAGE_PUNT = &H80000
Private Const PRINTER_STATUS_USER_INTERVENTION = &H100000
Private Const PRINTER_STATUS_OUT_OF_MEMORY = &H200000
Private Const PRINTER_STATUS_DOOR_OPEN = &H400000

Private Const PRINTER_ATTRIBUTE_QUEUED = &H1
Private Const PRINTER_ATTRIBUTE_DIRECT = &H2
Private Const PRINTER_ATTRIBUTE_DEFAULT = &H4
Private Const PRINTER_ATTRIBUTE_SHARED = &H8
Private Const PRINTER_ATTRIBUTE_NETWORK = &H10
Private Const PRINTER_ATTRIBUTE_HIDDEN = &H20
Private Const PRINTER_ATTRIBUTE_LOCAL = &H40

Private Const NO_PRIORITY = 0
Private Const MAX_PRIORITY = 99
Private Const MIN_PRIORITY = 1
Private Const DEF_PRIORITY = 1

Private Type JOB_INFO_1
JobId As Long
pPrinterName As String
pMachineName As String
pUserName As String
pDocument As String
pDatatype As String
pStatus As String
Status As Long
Priority As Long
Position As Long
TotalPages As Long
PagesPrinted As Long
Submitted As SYSTEMTIME
End Type

Private Type JOB_INFO_2
JobId As Long
pPrinterName As String
pMachineName As String
pUserName As String
pDocument As String
pNotifyName As String
pDatatype As String
pPrintProcessor As String
pParameters As String
pDriverName As String
pDevMode As DEVMODE
pStatus As String
pSecurityDescriptor As SECURITY_DESCRIPTOR
Status As Long
Priority As Long
Position As Long
StartTime As Long
UntilTime As Long
TotalPages As Long
Size As Long
Submitted As SYSTEMTIME
time As Long
PagesPrinted As Long
End Type

Private Const JOB_CONTROL_PAUSE = 1
Private Const JOB_CONTROL_RESUME = 2
Private Const JOB_CONTROL_CANCEL = 3
Private Const JOB_CONTROL_RESTART = 4

Private Const JOB_STATUS_PAUSED = &H1
Private Const JOB_STATUS_ERROR = &H2
Private Const JOB_STATUS_DELETING = &H4
Private Const JOB_STATUS_SPOOLING = &H8
Private Const JOB_STATUS_PRINTING = &H10
Private Const JOB_STATUS_OFFLINE = &H20
Private Const JOB_STATUS_PAPEROUT = &H40
Private Const JOB_STATUS_PRINTED = &H80
Private Const JOB_STATUS_DELETED = &H100
Private Const JOB_STATUS_BLOCKED_DEVQ = &H200
'Private Const JOB_STATUS_USER_INTERVENTION = &H400 ' Windows 95 Only
Private Const JOB_POSITION_UNSPECIFIED = 0

Private Type ADDJOB_INFO_1
Path As String
JobId As Long
End Type

Private Type DRIVER_INFO_1
pName As String
End Type

Private Type DRIVER_INFO_2
cVersion As Long
pName As String
pEnvironment As String
pDriverPath As String
pDataFile As String
pConfigFile As String
End Type

Private Type DOC_INFO_1
pDocName As String
pOutputFile As String
pDatatype As String
End Type

Private Type FORM_INFO_1
pName As String
Size As SIZEL
ImageableArea As RECTL
End Type

Private Const FORM_BUILTIN = &H1

Private Type PRINTPROCESSOR_INFO_1
pName As String
End Type

Private Type PORT_INFO_1
pName As String
End Type

Private Type MONITOR_INFO_1
pName As String
End Type

Private Type MONITOR_INFO_2
pName As String
pEnvironment As String
pDLLName As String
End Type

Private Type DATATYPES_INFO_1
pName As String
End Type

Private Type PRINTER_DEFAULTS
pDatatype As String
pDevMode As DEVMODE
DesiredAccess As Long
End Type

Private Type PRINTER_INFO_4
pPrinterName As String
pServerName As String
Attributes As Long
End Type

Private Type PRINTER_INFO_5
pPrinterName As String
pPortName As String
Attributes As Long
DeviceNotSelectedTimeout As Long
TransmissionRetryTimeout As Long
End Type

Private Const PRINTER_CONTROL_SET_STATUS = 4
Private Const PRINTER_ATTRIBUTE_WORK_OFFLINE = &H400
Private Const PRINTER_ATTRIBUTE_ENABLE_BIDI = &H800
Private Const JOB_CONTROL_DELETE = 5
Private Const JOB_STATUS_USER_INTERVENTION = &H10000

Private Type DRIVER_INFO_3
cVersion As Long
pName As String ' QMS 810
pEnvironment As String ' Win32 x86
pDriverPath As String ' c:\drivers\pscript.dll
pDataFile As String ' c:\drivers\QMS810.PPD
pConfigFile As String ' c:\drivers\PSCRPTUI.DLL
pHelpFile As String ' c:\drivers\PSCRPTUI.HLP
pDependentFiles As String '
pMonitorName As String ' "PJL monitor"
pDefaultDataType As String ' "EMF"
End Type

Private Type DOC_INFO_2
pDocName As String
pOutputFile As String
pDatatype As String
dwMode As Long
JobId As Long
End Type

Private Const DI_CHANNEL = 1 ' start direct read/write channel,
Private Const DI_READ_SPOOL_JOB = 3

Private Type PORT_INFO_2
pPortName As String
pMonitorName As String
pDescription As String
fPortType As Long
Reserved As Long
End Type

Private Const PORT_TYPE_WRITE = &H1
Private Const PORT_TYPE_READ = &H2
Private Const PORT_TYPE_REDIRECTED = &H4
Private Const PORT_TYPE_NET_ATTACHED = &H8
#If VBA7 And Win64 Then
Private Declare PtrSafe Function Enumprinters Lib "winspool.drv" Alias "EnumPrintersA" _
(ByVal flags As LongPtr, ByVal Name As String, ByVal Level As LongPtr, pPrinterEnum As Byte, _
ByVal cdBuf As LongPtr, pcbNeeded As LongPtr, pcReturned As LongPtr) As Long
#Else
Private Declare Function Enumprinters Lib "winspool.drv" Alias "EnumPrintersA" _
(ByVal flags As Long, ByVal Name As String, ByVal Level As Long, pPrinterEnum As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
#End If
#If VBA7 Then
Private Declare PtrSafe Function EnumPrinterPropertySheets Lib "winspool.drv" (hPrinter As LongPtr, hwnd As LongPtr, lpfnAdd As Long, ByVal lParam As LongPtr) As Long
#Else
'http://note.phyllo.net/?eid=1106226
Private Declare Function EnumPrinterPropertySheets Lib "winspool.drv" (hPrinter As Long, hwnd As Long, lpfnAdd As Long, ByVal lParam As Long) As Long
#End If
Private Const PRINTER_ENUM_DEFAULT = &H1
Private Const PRINTER_ENUM_LOCAL = &H2
Private Const PRINTER_ENUM_CONNECTIONS = &H4
Private Const PRINTER_ENUM_FAVORITE = &H4
Private Const PRINTER_ENUM_NAME = &H8
Private Const PRINTER_ENUM_REMOTE = &H10
Private Const PRINTER_ENUM_SHARED = &H20
Private Const PRINTER_ENUM_NETWORK = &H40

Private Const PRINTER_ENUM_EXPAND = &H4000
Private Const PRINTER_ENUM_CONTAINER = &H8000

Private Const PRINTER_ENUM_ICONMASK = &HFF0000
Private Const PRINTER_ENUM_ICON1 = &H10000
Private Const PRINTER_ENUM_ICON2 = &H20000
Private Const PRINTER_ENUM_ICON3 = &H40000
Private Const PRINTER_ENUM_ICON4 = &H80000
Private Const PRINTER_ENUM_ICON5 = &H100000
Private Const PRINTER_ENUM_ICON6 = &H200000
Private Const PRINTER_ENUM_ICON7 = &H400000
Private Const PRINTER_ENUM_ICON8 = &H800000

'Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, _
phPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long
' プリンタのオブジェクトハンドルを取得する関数の宣言
#If VBA7 Then
Private Declare PtrSafe Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal pPrinterName As String, phPrinter As LongPtr, pDefault As Any) As Long ' pDefault As AnyはpDefault As PRINTER_DEFAULTSとする場合あり
Private Declare PtrSafe Function ResetPrinter Lib "winspool.drv" Alias "ResetPrinterA" (ByVal hPrinter As LongPtr, pDefault As PRINTER_DEFAULTS) As Long

Private Declare PtrSafe Function SetJob Lib "winspool.drv" Alias "SetJobA" (ByVal hPrinter As LongPtr, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal Command As Long) As Long
Private Declare PtrSafe Function GetJob Lib "winspool.drv" Alias "GetJobA" (ByVal hPrinter As LongPtr, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
'Private Declare PtrSafe Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As LongPtr, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare PtrSafe Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As LongPtr, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal Level As Long, pJob As Any, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare PtrSafe Function AddPrinter Lib "winspool.drv" Alias "AddPrinterA" (ByVal pName As String, ByVal Level As Long, pPrinter As Any) As LongPtr

Private Declare PtrSafe Function AddPrinterDriver Lib "winspool.drv" Alias "AddPrinterDriverA" (ByVal pName As String, ByVal Level As Long, pDriverInfo As Any) As Long

Private Declare PtrSafe Function EnumPrinterDrivers Lib "winspool.drv" Alias "EnumPrinterDriversA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, pDriverInfo As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcRetruned As Long) As Long
Private Declare PtrSafe Function GetPrinterDriver Lib "winspool.drv" Alias "GetPrinterDriverA" (ByVal hPrinter As LongPtr, ByVal pEnvironment As String, ByVal Level As Long, pDriverInfo As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare PtrSafe Function GetPrinterDriverDirectory Lib "winspool.drv" Alias "GetPrinterDriverDirectoryA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, pDriverDirectory As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare PtrSafe Function DeletePrinterDriver Lib "winspool.drv" Alias "DeletePrinterDriverA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pDriverName As String) As Long

Private Declare PtrSafe Function AddPrintProcessor Lib "winspool.drv" Alias "AddPrintProcessorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pPathName As String, ByVal pPrintProcessorName As String) As Long
Private Declare PtrSafe Function EnumPrintProcessors Lib "winspool.drv" Alias "EnumPrintProcessorsA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, pPrintProcessorInfo As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare PtrSafe Function GetPrintProcessorDirectory Lib "winspool.drv" Alias "GetPrintProcessorDirectoryA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, ByVal pPrintProcessorInfo As String, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare PtrSafe Function EnumPrintProcessorDatatypes Lib "winspool.drv" Alias "EnumPrintProcessorDatatypesA" (ByVal pName As String, ByVal pPrintProcessorName As String, ByVal Level As Long, pDatatypes As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcRetruned As Long) As Long
Private Declare PtrSafe Function DeletePrintProcessor Lib "winspool.drv" Alias "DeletePrintProcessorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pPrintProcessorName As String) As Long

Private Declare PtrSafe Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrinter As LongPtr, ByVal Level As Long, pDocInfo As Byte) As Long
Private Declare PtrSafe Function StartPagePrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr) As Long
Private Declare PtrSafe Function WritePrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr, pBuf As Any, ByVal cdBuf As Long, pcWritten As Long) As Long
Private Declare PtrSafe Function EndPagePrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr) As Long
Private Declare PtrSafe Function AbortPrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr) As Long
Private Declare PtrSafe Function ReadPrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr, pBuf As Any, ByVal cdBuf As Long, pNoBytesRead As Long) As Long
Private Declare PtrSafe Function EndDocPrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr) As Long

Private Declare PtrSafe Function AddJob Lib "winspool.drv" Alias "AddJobA" (ByVal hPrinter As LongPtr, ByVal Level As Long, pData As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare PtrSafe Function ScheduleJob Lib "winspool.drv" (ByVal hPrinter As LongPtr, ByVal JobId As Long) As Long
Private Declare PtrSafe Function PrinterProperties Lib "winspool.drv" (ByVal hwnd As LongPtr, ByVal hPrinter As LongPtr) As Long
'Private Declare PtrSafe Function DocumentProperties Lib "winspool.drv" Alias "DocumentPropertiesA" (ByVal hwnd As LongPtr, ByVal hPrinter As LongPtr, ByVal pDeviceName As String, pDevModeOutput As DEVMODE, pDevModeInput As DEVMODE, ByVal fMode As Long) As Long
'Private Declare PtrSafe Function AdvancedDocumentProperties Lib "winspool.drv" Alias "AdvancedDocumentPropertiesA" (ByVal hwnd As LongPtr, ByVal hPrinter As LongPtr, ByVal pDeviceName As String, pDevModeOutput As DEVMODE, pDevModeInput As DEVMODE) As Long

Private Declare PtrSafe Function GetPrinterData Lib "winspool.drv" Alias "GetPrinterDataA" (ByVal hPrinter As LongPtr, ByVal pValueName As String, pType As Long, pData As Byte, ByVal nSize As Long, pcbNeeded As Long) As Long
Private Declare PtrSafe Function SetPrinterData Lib "winspool.drv" Alias "SetPrinterDataA" (ByVal hPrinter As LongPtr, ByVal pValueName As String, ByVal dwType As Long, pData As Byte, ByVal cbData As Long) As Long
Private Declare PtrSafe Function WaitForPrinterChange Lib "winspool.drv" (ByVal hPrinter As LongPtr, ByVal flags As Long) As LongPtr
#Else
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal pPrinterName As String, phPrinter As Long, pDefault As Any) As Long
Private Declare Function ResetPrinter Lib "winspool.drv" Alias "ResetPrinterA" (ByVal hPrinter As Long, pDefault As PRINTER_DEFAULTS) As Long
Private Declare Function SetJob Lib "winspool.drv" Alias "SetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal Command As Long) As Long
Private Declare Function GetJob Lib "winspool.drv" Alias "GetJobA" (ByVal hPrinter As Long, ByVal JobId As Long, ByVal Level As Long, pJob As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As Long, _
ByVal FirstJob As Long, ByVal NoJobs As Long, _
ByVal Level As Long, pJob As Any, _
ByVal cdBuf As Long, pcbNeeded As Long, _
pcReturned As Long) As Long 'pJob As Byte > pJob As Any
Private Declare Function AddPrinter Lib "winspool.drv" Alias "AddPrinterA" (ByVal pName As String, _
ByVal Level As Long, pPrinter As Byte) As Long
Private Declare Function AddPrinterDriver Lib "winspool.drv" Alias "AddPrinterDriverA" (ByVal pName As String, ByVal Level As Long, pDriverInfor As Byte) As Long
Private Declare Function EnumPrinterDrivers Lib "winspool.drv" Alias "EnumPrinterDriversA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, pDriverInfo As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcRetruned As Long) As Long
Private Declare Function GetPrinterDriver Lib "winspool.drv" Alias "GetPrinterDriverA" (ByVal hPrinter As Long, ByVal pEnvironment As String, ByVal Level As Long, pDriverInfo As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare Function GetPrinterDriverDirectory Lib "winspool.drv" Alias "GetPrinterDriverDirectoryA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, pDriverDirectory As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare Function DeletePrinterDriver Lib "winspool.drv" Alias "DeletePrinterDriverA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pDriverName As String) As Long

Private Declare Function AddPrintProcessor Lib "winspool.drv" Alias "AddPrintProcessorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pPathName As String, ByVal pPrintProcessorName As String) As Long
Private Declare Function EnumPrintProcessors Lib "winspool.drv" Alias "EnumPrintProcessorsA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, pPrintProcessorInfo As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare Function GetPrintProcessorDirectory Lib "winspool.drv" Alias "GetPrintProcessorDirectoryA" (ByVal pName As String, ByVal pEnvironment As String, ByVal Level As Long, ByVal pPrintProcessorInfo As String, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare Function EnumPrintProcessorDatatypes Lib "winspool.drv" Alias "EnumPrintProcessorDatatypesA" (ByVal pName As String, ByVal pPrintProcessorName As String, ByVal Level As Long, pDatatypes As Byte, ByVal cdBuf As Long, pcbNeeded As Long, pcRetruned As Long) As Long
Private Declare Function DeletePrintProcessor Lib "winspool.drv" Alias "DeletePrintProcessorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pPrintProcessorName As String) As Long

Private Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, pDocInfo As Byte) As Long
Private Declare Function StartPagePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Private Declare Function WritePrinter Lib "winspool.drv" (ByVal hPrinter As Long, pBuf As Any, ByVal cdBuf As Long, pcWritten As Long) As Long
Private Declare Function EndPagePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Private Declare Function AbortPrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Private Declare Function ReadPrinter Lib "winspool.drv" (ByVal hPrinter As Long, pBuf As Any, ByVal cdBuf As Long, pNoBytesRead As Long) As Long
Private Declare Function EndDocPrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Private Declare Function AddJob Lib "winspool.drv" Alias "AddJobA" (ByVal hPrinter As Long, ByVal Level As Long, pData As Byte, ByVal cdBuf As Long, pcbNeeded As Long) As Long
Private Declare Function ScheduleJob Lib "winspool.drv" (ByVal hPrinter As Long, ByVal JobId As Long) As Long
Private Declare Function PrinterProperties Lib "winspool.drv" (ByVal hwnd As Long, ByVal hPrinter As Long) As Long
'Private Declare Function DocumentProperties Lib "winspool.drv" Alias "DocumentPropertiesA" (ByVal hwnd As Long, ByVal hPrinter As Long, ByVal pDeviceName As String, pDevModeOutput As DEVMODE, pDevModeInput As DEVMODE, ByVal fMode As Long) As Long
'Private Declare Function AdvancedDocumentProperties Lib "winspool.drv" Alias "AdvancedDocumentPropertiesA" (ByVal hwnd As Long, ByVal hPrinter As Long, ByVal pDeviceName As String, pDevModeOutput As DEVMODE, pDevModeInput As DEVMODE) As Long

Private Declare Function GetPrinterData Lib "winspool.drv" Alias "GetPrinterDataA" (ByVal hPrinter As Long, ByVal pValueName As String, pType As Long, pData As Byte, ByVal nSize As Long, pcbNeeded As Long) As Long
Private Declare Function SetPrinterData Lib "winspool.drv" Alias "SetPrinterDataA" (ByVal hPrinter As Long, ByVal pValueName As String, ByVal dwType As Long, pData As Byte, ByVal cbData As Long) As Long
Private Declare Function WaitForPrinterChange Lib "winspool.drv" (ByVal hPrinter As Long, ByVal flags As Long) As Long
#End If

Private Const PRINTER_CHANGE_ADD_PRINTER = &H1
Private Const PRINTER_CHANGE_SET_PRINTER = &H2
Private Const PRINTER_CHANGE_DELETE_PRINTER = &H4
Private Const PRINTER_CHANGE_PRINTER = &HFF
Private Const PRINTER_CHANGE_ADD_JOB = &H100
Private Const PRINTER_CHANGE_SET_JOB = &H200
Private Const PRINTER_CHANGE_DELETE_JOB = &H400
Private Const PRINTER_CHANGE_WRITE_JOB = &H800
Private Const PRINTER_CHANGE_JOB = &HFF00
Private Const PRINTER_CHANGE_ADD_FORM = &H10000
Private Const PRINTER_CHANGE_SET_FORM = &H20000
Private Const PRINTER_CHANGE_DELETE_FORM = &H40000
Private Const PRINTER_CHANGE_FORM = &H70000
Private Const PRINTER_CHANGE_ADD_PORT = &H100000
Private Const PRINTER_CHANGE_CONFIGURE_PORT = &H200000
Private Const PRINTER_CHANGE_DELETE_PORT = &H400000
Private Const PRINTER_CHANGE_PORT = &H700000
Private Const PRINTER_CHANGE_ADD_PRINT_PROCESSOR = &H1000000
Private Const PRINTER_CHANGE_DELETE_PRINT_PROCESSOR = &H4000000
Private Const PRINTER_CHANGE_PRINT_PROCESSOR = &H7000000
Private Const PRINTER_CHANGE_ADD_PRINTER_DRIVER = &H10000000
Private Const PRINTER_CHANGE_DELETE_PRINTER_DRIVER = &H40000000
Private Const PRINTER_CHANGE_PRINTER_DRIVER = &H70000000
Private Const PRINTER_CHANGE_TIMEOUT = &H80000000
Private Const PRINTER_CHANGE_ALL = &H7777FFFF

#If VBA7 Then
Private Declare PtrSafe Function PrinterMessageBox Lib "winspool.drv" Alias "PrinterMessageBoxA" (ByVal hPrinter As LongPtr, ByVal error As Long, ByVal hwnd As LongPtr, ByVal pText As String, ByVal pCaption As String, ByVal dwType As Long) As Long
#Else
Private Declare Function PrinterMessageBox Lib "winspool.drv" Alias "PrinterMessageBoxA" (ByVal hPrinter As Long, ByVal error As Long, ByVal hwnd As Long, ByVal pText As String, ByVal pCaption As String, ByVal dwType As Long) As Long
#End If
Private Const PRINTER_ERROR_INFORMATION = &H80000000
Private Const PRINTER_ERROR_WARNING = &H40000000
Private Const PRINTER_ERROR_SEVERE = &H20000000

Private Const PRINTER_ERROR_OUTOFPAPER = &H1
Private Const PRINTER_ERROR_JAM = &H2
Private Const PRINTER_ERROR_OUTOFTONER = &H4
#If VBA7 Then
Private Declare PtrSafe Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As LongPtr) As Long
Private Declare PtrSafe Function DeleteForm Lib "winspool.drv" Alias "DeleteFormA" (ByVal hPrinter As LongPtr, ByVal pFormName As String) As Long
Private Declare PtrSafe Function GetForm Lib "winspool.drv" Alias "GetFormA" (ByVal hPrinter As LongPtr, ByVal pFormName As String, ByVal Level As Long, pForm As Byte, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Private Declare PtrSafe Function SetForm Lib "winspool.drv" Alias "SetFormA" (ByVal hPrinter As LongPtr, ByVal pFormName As String, ByVal Level As Long, pForm As Byte) As Long
Private Declare PtrSafe Function EnumForms Lib "winspool.drv" Alias "EnumFormsA" (ByVal hPrinter As LongPtr, ByVal Level As Long, pForm As Byte, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long


Private Declare PtrSafe Function EnumMonitors Lib "winspool.drv" Alias "EnumMonitorsA" (ByVal pName As String, ByVal Level As Long, pMonitors As Byte, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare PtrSafe Function AddMonitor Lib "winspool.drv" Alias "AddMonitorA" (ByVal pName As String, ByVal Level As Long, pMonitors As Byte) As Long
Private Declare PtrSafe Function DeleteMonitor Lib "winspool.drv" Alias "DeleteMonitorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pMonitorName As String) As Long

Private Declare PtrSafe Function EnumPorts Lib "winspool.drv" Alias "EnumPortsA" (ByVal pName As String, ByVal Level As Long, ByVal lpbPorts As LongPtr, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare PtrSafe Function AddPort Lib "winspool.drv" Alias "AddPortA" (ByVal pName As String, ByVal hwnd As LongPtr, ByVal pMonitorName As String) As Long
Private Declare PtrSafe Function ConfigurePort Lib "winspool.drv" Alias "ConfigurePortA" (ByVal pName As String, ByVal hwnd As LongPtr, ByVal pPortName As String) As Long
Private Declare PtrSafe Function DeletePort Lib "winspool.drv" Alias "DeletePortA" (ByVal pName As String, ByVal hwnd As LongPtr, ByVal pPortName As String) As Long
Private Declare PtrSafe Function AddPrinterConnection Lib "winspool.drv" Alias "AddPrinterConnectionA" (ByVal pName As String) As Long

Private Declare PtrSafe Function DeletePrinterConnection Lib "winspool.drv" Alias "DeletePrinterConnectionA" (ByVal pName As String) As Long
Private Declare PtrSafe Function ConnectToPrinterDlg Lib "winspool.drv" (ByVal hwnd As LongPtr, ByVal flags As Long) As LongPtr
#Else
Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long
Private Declare Function AddForm Lib "winspool.drv" Alias "AddFormA" (ByVal hPrinter As Long, ByVal Level As Long, pForm As Byte) As Long
Private Declare Function DeleteForm Lib "winspool.drv" Alias "DeleteFormA" (ByVal hPrinter As Long, ByVal pFormName As String) As Long
Private Declare Function GetForm Lib "winspool.drv" Alias "GetFormA" (ByVal hPrinter As Long, ByVal pFormName As String, ByVal Level As Long, pForm As Byte, ByVal cbBuf As Long, pcbNeeded As Long) As Long
Private Declare Function SetForm Lib "winspool.drv" Alias "SetFormA" (ByVal hPrinter As Long, ByVal pFormName As String, ByVal Level As Long, pForm As Byte) As Long
Private Declare Function EnumForms Lib "winspool.drv" Alias "EnumFormsA" (ByVal hPrinter As Long, ByVal Level As Long, pForm As Byte, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long

Private Declare Function EnumMonitors Lib "winspool.drv" Alias "EnumMonitorsA" (ByVal pName As String, ByVal Level As Long, pMonitors As Byte, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare Function AddMonitor Lib "winspool.drv" Alias "AddMonitorA" (ByVal pName As String, ByVal Level As Long, pMonitors As Byte) As Long
Private Declare Function DeleteMonitor Lib "winspool.drv" Alias "DeleteMonitorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pMonitorName As String) As Long

Private Declare Function EnumPorts Lib "winspool.drv" Alias "EnumPortsA" (ByVal pName As String, ByVal Level As Long, ByVal lpbPorts As Long, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long) As Long
Private Declare Function AddPort Lib "winspool.drv" Alias "AddPortA" (ByVal pName As String, ByVal hwnd As Long, ByVal pMonitorName As String) As Long
Private Declare Function ConfigurePort Lib "winspool.drv" Alias "ConfigurePortA" (ByVal pName As String, ByVal hwnd As Long, ByVal pPortName As String) As Long
Private Declare Function DeletePort Lib "winspool.drv" Alias "DeletePortA" (ByVal pName As String, ByVal hwnd As Long, ByVal pPortName As String) As Long

Private Declare Function AddPrinterConnection Lib "winspool.drv" Alias "AddPrinterConnectionA" (ByVal pName As String) As Long
Private Declare Function DeletePrinterConnection Lib "winspool.drv" Alias "DeletePrinterConnectionA" (ByVal pName As String) As Long
Private Declare Function ConnectToPrinterDlg Lib "winspool.drv" (ByVal hwnd As Long, ByVal flags As Long) As Long
#End If
Private Type PROVIDOR_INFO_1
pName As String
pEnvironment As String
pDLLName As String
End Type
#If VBA7 Then
Private Declare PtrSafe Function AddPrintProvidor Lib "winspool.drv" Alias "AddPrintProvidorA" (ByVal pName As String, ByVal Level As Long, pProvidorInfo As Byte) As Long
Private Declare PtrSafe Function DeletePrintProvidor Lib "winspool.drv" Alias "DeletePrintProvidorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pPrintProvidorName As String) As Long
#Else
Private Declare Function AddPrintProvidor Lib "winspool.drv" Alias "AddPrintProvidorA" (ByVal pName As String, ByVal Level As Long, pProvidorInfo As Byte) As Long
Private Declare Function DeletePrintProvidor Lib "winspool.drv" Alias "DeletePrintProvidorA" (ByVal pName As String, ByVal pEnvironment As String, ByVal pPrintProvidorName As String) As Long
#End If
Private Const SERVER_ACCESS_ADMINISTER = &H1
Private Const SERVER_ACCESS_ENUMERATE = &H2

Private Const PRINTER_ACCESS_ADMINISTER = &H4
Private Const PRINTER_ACCESS_USE = &H8

Private Const JOB_ACCESS_ADMINISTER = &H10

' Access rights for print servers

Private Const SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or SERVER_ACCESS_ADMINISTER Or SERVER_ACCESS_ENUMERATE)
Private Const SERVER_READ = (STANDARD_RIGHTS_READ Or SERVER_ACCESS_ENUMERATE)
Private Const SERVER_WRITE = (STANDARD_RIGHTS_WRITE Or SERVER_ACCESS_ADMINISTER Or SERVER_ACCESS_ENUMERATE)
Private Const SERVER_EXECUTE = (STANDARD_RIGHTS_EXECUTE Or SERVER_ACCESS_ENUMERATE)

' Access rights for printers
Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Private Const PRINTER_READ = (STANDARD_RIGHTS_READ Or PRINTER_ACCESS_USE)
Private Const PRINTER_WRITE = (STANDARD_RIGHTS_WRITE Or PRINTER_ACCESS_USE)
Private Const PRINTER_EXECUTE = (STANDARD_RIGHTS_EXECUTE Or PRINTER_ACCESS_USE)

' Access rights for jobs
Private Const JOB_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or JOB_ACCESS_ADMINISTER)
Private Const JOB_READ = (STANDARD_RIGHTS_READ Or JOB_ACCESS_ADMINISTER)
Private Const JOB_WRITE = (STANDARD_RIGHTS_WRITE Or JOB_ACCESS_ADMINISTER)
Private Const JOB_EXECUTE = (STANDARD_RIGHTS_EXECUTE Or JOB_ACCESS_ADMINISTER)

#If VBA7 Then
Private Declare PtrSafe Function lstrcat Lib "kernel32" Alias "lstrcatA" (ByVal lpString1 As String, ByVal lpString2 As String) As LongPtr
Private Declare PtrSafe Function lstrcpyn Lib "kernel32" Alias "lstrcpynA" (ByVal lpString1 As String, ByVal lpString2 As String, ByVal iMaxLength As Long) As LongPtr
Private Declare PtrSafe Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, ByVal lpString2 As String) As LongPtr
#Else
Private Declare Function lstrcat Lib "kernel32" Alias "lstrcatA" (ByVal lpString1 As String, ByVal lpString2 As String) As Long
Private Declare Function lstrcpyn Lib "kernel32" Alias "lstrcpynA" (ByVal lpString1 As String, ByVal lpString2 As String, ByVal iMaxLength As Long) As Long
Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, ByVal lpString2 As String) As Long
#End If
#If VBA7 Then
Private hHandle As LongPtr
#Else
Private hHandle As Long
#End If

'通常使うプリンタの取得
Function getConstantPrinter() As String
Dim strSection As String
Dim strKey As String
Dim strDefault As String
Dim strBuff As String * 1024

' セクションを指定
strSection = "windows"

' キーを指定
strKey = "device"

' デフォルト値を指定
strDefault = ""

' 取得
Call GetProfileString(strSection, strKey, strDefault, strBuff, Len(strBuff))
getConstantPrinter = Left(strBuff, InStr(strBuff, ",") - 1)
End Function
Private Sub GetPrinterSpoolInfo()
Dim strPrinterDeviceName As String
#If VBA7 Then
Dim lngPrinterHandle As LongPtr
#Else
Dim lngPrinterHandle As Long
#End If
Dim lngJobInfo1FirstJob As Long
Dim lngJobInfo1EnumerateJob As Long
Dim lngJobInfo1Level As Long
Dim lngJobInfo1Needed As Long
Dim lngJobInfo1Returned As Long
Dim bytJobInfo1Buffer() As Byte
Dim udtJobInfo1() As JOB_INFO_1
Dim lngJobInfo1Count As Long
Dim bytDocumentBuffer(64) As Byte
Dim strDocument() As String
Dim strStatus() As String
' 通常使うプリンタ名を取得
strPrinterDeviceName = getConstantPrinter

' プリンタのオブジェクトハンドルを取得
hHandle = OpenPrinter(strPrinterDeviceName, lngPrinterHandle, ByVal vbNullString)
' 最初に列挙する印刷ジョブを指定
lngJobInfo1FirstJob = 0
' 列挙する印刷ジョブの総数を指定
lngJobInfo1EnumerateJob = 99
' 構造体のレベルを指定
lngJobInfo1Level = 1
' バッファの必要なサイズを取得
Call EnumJobs(lngPrinterHandle, lngJobInfo1FirstJob, lngJobInfo1EnumerateJob, lngJobInfo1Level, _
ByVal vbNullString, 0, lngJobInfo1Needed, lngJobInfo1Returned)
' 印刷ジョブが存在する場合は
If lngJobInfo1Needed > 0 Then
' バッファを確保
ReDim bytJobInfo1Buffer(lngJobInfo1Needed - 1)
ReDim udtJobInfo1(lngJobInfo1Needed - 1)
ReDim strUserName(lngJobInfo1Needed - 1)
ReDim strDocument(lngJobInfo1Needed - 1)
ReDim strStatus(lngJobInfo1Needed - 1)
' 印刷ジョブの情報を取得
Call EnumJobs(lngPrinterHandle, lngJobInfo1FirstJob, lngJobInfo1EnumerateJob, lngJobInfo1Level, bytJobInfo1Buffer(0), _
lngJobInfo1Needed, lngJobInfo1Needed, lngJobInfo1Returned)
' 印刷ジョブが取得できた場合は
If lngJobInfo1Returned > 0 Then
' 取得した印刷ジョブの情報を構造体へ移動
MoveMemory udtJobInfo1(0), bytJobInfo1Buffer(0), Len(udtJobInfo1(0)) * lngJobInfo1Returned

' プリンタドライバ情報を切り出し
For lngJobInfo1Count = 0 To lngJobInfo1Returned - 1
With udtJobInfo1(lngJobInfo1Count)
' ドキュメント名のアドレスを取得
Call lstrcpy(bytDocumentBuffer(0), ByVal .pDocument)
' ドキュメント名をバイト型から文字列へ変換
strDocument(lngJobInfo1Count) = StrConv(bytDocumentBuffer(), vbUnicode)
' 印刷ジョブの状態を取得
strStatus(lngJobInfo1Count) = ""
If .Status And JOB_STATUS_PAUSED Then:
If .Status And JOB_STATUS_ERROR Then:
If .Status And JOB_STATUS_DELETING Then:
If .Status And JOB_STATUS_SPOOLING Then:
If .Status And JOB_STATUS_PRINTING Then:
If .Status And JOB_STATUS_OFFLINE Then:
If .Status And JOB_STATUS_PAPEROUT Then:
If .Status And JOB_STATUS_PRINTED Then:
If .Status And JOB_STATUS_DELETED Then:
If .Status And JOB_STATUS_BLOCKED_DEVQ Then:
If .Status And JOB_STATUS_USER_INTERVENTION Then: strStatus(lngJobInfo1Count) = strStatus(lngJobInfo1Count) & "/ユーザ介在"
' 印刷ジョブを表示
Debug.Print .JobId & "-" & _
Left(strDocument(lngJobInfo1Count), _
InStr(strDocument(lngJobInfo1Count), vbNullChar) - 1) & vbTab & _
strStatus(lngJobInfo1Count)
End With
Next lngJobInfo1Count
Else
Debug.Print "印刷ジョブが取得できません。"
End If
Else
Debug.Print "印刷ジョブはありません。"
End If
' プリンタオブジェクトをクローズ
Call ClosePrinter(lngPrinterHandle)
End Sub
Property Let clsSleep(lngSleep As LongPtr)
Sleep lngSleep
End Property

Property Get isPrinterSpool() As Boolean
Dim strPrinterDeviceName As String
#If VBA7 Then
Dim lngPrinterHandle As LongPtr
#Else
Dim lngPrinterHandle As Long
#End If
Dim lngJobInfo1FirstJob As Long
Dim lngJobInfo1EnumerateJob As Long
Dim lngJobInfo1Level As Long
Dim lngJobInfo1Needed As Long
Dim lngJobInfo1Returned As Long
Dim bytJobInfo1Buffer() As Byte
Dim udtJobInfo1() As JOB_INFO_1
Dim lngJobInfo1Count As Long
Dim bytDocumentBuffer(64) As Byte
Dim strDocument() As String
Dim strStatus() As String
' 通常使うプリンタ名を取得
strPrinterDeviceName = getConstantPrinter

' プリンタのオブジェクトハンドルを取得
hHandle = OpenPrinter(strPrinterDeviceName, lngPrinterHandle, ByVal vbNullString)
' 最初に列挙する印刷ジョブを指定
lngJobInfo1FirstJob = 0
' 列挙する印刷ジョブの総数を指定
lngJobInfo1EnumerateJob = 99
' 構造体のレベルを指定
lngJobInfo1Level = 1
' バッファの必要なサイズを取得
'Call EnumJobs(lngPrinterHandle, lngJobInfo1FirstJob, lngJobInfo1EnumerateJob, lngJobInfo1Level, _
ByVal vbNullString, 0, lngJobInfo1Needed, lngJobInfo1Returned)
'Call EnumJobs(lngPrinterHandle, lngJobInfo1Count, lngJobInfo1EnumerateJob, lngJobInfo1Level, 0, 0, lngJobInfo1Needed, lngJobInfo1Returned)
Call EnumJobs(lngPrinterHandle, lngJobInfo1FirstJob, lngJobInfo1EnumerateJob, lngJobInfo1Level, 0, _
lngJobInfo1Needed, lngJobInfo1Needed, lngJobInfo1Returned)
' 印刷ジョブが存在する場合は
If lngJobInfo1Needed > 0 Then
' バッファを確保
ReDim bytJobInfo1Buffer(lngJobInfo1Needed - 1)
ReDim udtJobInfo1(lngJobInfo1Needed - 1)
ReDim strUserName(lngJobInfo1Needed - 1)
ReDim strDocument(lngJobInfo1Needed - 1)
ReDim strStatus(lngJobInfo1Needed - 1)
' 印刷ジョブの情報を取得
Call EnumJobs(lngPrinterHandle, lngJobInfo1FirstJob, lngJobInfo1EnumerateJob, lngJobInfo1Level, bytJobInfo1Buffer(0), _
lngJobInfo1Needed, lngJobInfo1Needed, lngJobInfo1Returned)
' 印刷ジョブが取得できた場合は
If lngJobInfo1Returned > 0 Then
' 取得した印刷ジョブの情報を構造体へ移動
MoveMemory udtJobInfo1(0), bytJobInfo1Buffer(0), Len(udtJobInfo1(0)) * lngJobInfo1Returned

' プリンタドライバ情報を切り出し
For lngJobInfo1Count = 0 To lngJobInfo1Returned - 1
With udtJobInfo1(lngJobInfo1Count)
' ドキュメント名のアドレスを取得
Call lstrcpy(bytDocumentBuffer(0), ByVal .pDocument)
' ドキュメント名をバイト型から文字列へ変換
strDocument(lngJobInfo1Count) = StrConv(bytDocumentBuffer(), vbUnicode)
' 印刷ジョブの状態を取得
strStatus(lngJobInfo1Count) = ""
If .Status And JOB_STATUS_PAUSED Then:
If .Status And JOB_STATUS_ERROR Then:
If .Status And JOB_STATUS_DELETING Then:
If .Status And JOB_STATUS_SPOOLING Then:
If .Status And JOB_STATUS_PRINTING Then:
If .Status And JOB_STATUS_OFFLINE Then:
If .Status And JOB_STATUS_PAPEROUT Then:
If .Status And JOB_STATUS_PRINTED Then:
If .Status And JOB_STATUS_DELETED Then:
If .Status And JOB_STATUS_BLOCKED_DEVQ Then:
If .Status And JOB_STATUS_USER_INTERVENTION Then: strStatus(lngJobInfo1Count) = strStatus(lngJobInfo1Count) & "/ユーザ介在"
' 印刷ジョブを表示
Debug.Print .JobId & "-" & _
Left(strDocument(lngJobInfo1Count), _
InStr(strDocument(lngJobInfo1Count), vbNullChar) - 1) & vbTab & _
strStatus(lngJobInfo1Count)
End With
Next lngJobInfo1Count
isPrinterSpool = True
Else
' Debug.Print "印刷ジョブが取得できません。"
isPrinterSpool = False
End If
Else
' Debug.Print "印刷ジョブはありません。"
isPrinterSpool = False
End If
' プリンタオブジェクトをクローズ
Call ClosePrinter(lngPrinterHandle)
End Property
```

#参考資料
##[印刷プロバイダーの概要](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/print/introduction-to-print-providers)
>Print Providersは、ローカルまたはリモートの印刷デバイスに印刷ジョブの指導を担当します。 または、開始、停止、およびサーバーの印刷キューを列挙するなど、印刷キューの管理操作を担当します。 印刷のプロバイダーは、プリント サーバーの高度なマシンに依存しない、オペレーティング システムに依存しないビューを定義します。

>すべての印刷プロバイダー実装の共通セットをプロバイダーの機能を印刷します。 これらの機能は、一連の API 関数は、スプーラーのルーター (Spoolss.dll) によって呼び出されるによって定義されます。

>***印刷プロバイダーによって定義されているほとんどの関数では、入力としてプリンター ハンドルが必要とします。 ***スプーラ クライアントが呼び出すことによってプリンター ハンドルを取得するようになりました(Microsoft Windows SDK のドキュメントで説明) Winspool.drv でを呼び出し、API サーバー (Spoolsv.exe)。 スプーラのルーター (Spoolss.dll) が各印刷プロバイダーを呼び出すようになりましたうち 1 つがプリンター ハンドルを提供し、印刷プロバイダーを示す戻り値が指定されたプリンター名を認識するまで、機能します。 ルーターは、API サーバーにし、独自のハンドルを返します。 ルーターのハンドルには、プリンター ハンドルとプロバイダーのハンドルの両方が含まれています。 このハンドルは、アプリケーションからの後続の呼び出しは、適切なプロバイダーやプリンターに向けることができるように、アプリケーションに返されます。

>マイクロソフトは、次の Windows 2000 以降のプロバイダーの印刷を提供します。(略)
Win32spl.dll
Windows ネットワーク印刷プロバイダー。 ハンドルの印刷ジョブのリモート Win32 に送られます (NT-ベースのオペレーティング システムまたは Windows をワークグループの) サーバー。 リモート サーバーで、ジョブが到着すると、サーバーのローカルの印刷プロバイダーに渡されます。

##上記で使用している関数をC#ベースで解説しているもの
[印刷プロバイダーによって定義されている関数](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/print/functions-defined-by-print-providers)
>警告  以降 Windows 10 では、サード パーティの印刷プロバイダーをサポートする Api は非推奨とされます。 Microsoft には、サード パーティの印刷プロバイダーに他の投資はお勧めしません。 さらに、Windows 8 および v4 印刷ドライバー モデルが使用可能な新しい製品では、サード パーティの印刷プロバイダーが作成や v4 印刷ドライバーを使用するキューを管理します。

>このトピックでは、すべての印刷のプロバイダーが提供できる機能を一覧表示します。 これらの関数のほとんどは、Microsoft Windows SDK ドキュメントで説明します。 関数は、Windows Driver Kit (WDK) で説明されている、関数名は、関連付けられている参照ページへのリンクを提供します。

>すべての印刷プロバイダーは、上記のすべての関数のポインターを提供する必要があります。 ただし、ほとんどのベンダーから提供された印刷プロバイダーは、関数で定義されている操作の多くをサポートする必要はありません「部分的なプロバイダー」です。 関数ポインターの多くは、そのため、 NULLします。 部分的な印刷プロバイダーの詳細については、次を参照してください。ネットワーク印刷のプロバイダーを記述します。

>サポートする必要がある関数は次の関数のリストで、"Required"ラベル付けされます。

>すべての印刷プロバイダーは、初期化関数をエクスポートする必要があります InitializePrintProvidorします。 その他のすべての関数へのポインターを指定する必要があります、 PRINTPROVIDOR 構造体。 (これら 2 つの名前は、スペルが間違っているが、ヘッダー ファイル、Winsplp.h で表示される名前との一貫性に注意してください)。

>関数は、グループに分割し、次のセクションに表示されます。


[Docs Windows ハードウェア Windows ドライバー ドライバー テクノロジ 印刷 ](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/print/)
プリンター ドライバー設計ガイド
以下対象にページが続く。

[[SDK32]SetPrinter() でのプリンタ設定の変更方法](https://support.microsoft.com/ja-jp/help/140285/how-to-modify-printer-settings-by-using-setprinter)
>概要
SetPrinter は、Windows 95 と Windows NT での新しい API で、アプリケーションからさまざまなプリンタの属性を変更できるようにするものです。しかし、SetPrinter を正しく呼び出すためには、いくつかの準備が必要となります。この資料では、その方法を紹介します。
詳細
SetPrinter() の引数は、以下のとおりです。
hPrinter
最初の引数は、設定を変更するプリンタのハンドルです。このハンドルは、OpenPrinter() で取得することができます。
dwLevel
2 番目の引数には、SetPrinter() に渡すデータの構造体のタイプを指定します。

>Windows95 では、0,1,2,5 のいずれかに、Windows NT では、0,1,2,3,4,5 のいずれかになります。これらの番号は、3 番目の引数に渡す構造体 (PRINTER_INFO_n) のタイプに対応します。
lpbPrinter
3 番目の引数は、PRINTER_INFO_n 構造体で、n は 2 番目の引数の値に対応します。

>この引数は、単純に構造体のサイズのバッファではないため、混乱することがあります。

>構造体は、デバイスに依存しない情報を含みますが、デバイスに依存する情報も含まれます。そのため、バッファのサイズを判断する作業が必要となります。これは、GetPrinter() で行なうことができます。この関数が、pcbNeeded に必要なサイズを設定します。

>また、構造体はたくさんの情報を持ちますが、アプリケーションは、そのほとんどのメンバの値を関知しません。そのため、必要な部分のみを変更して、その他の値は、2 回目の GetPrinter() が設定した値を使用します。

>dwCommand
4 番目の引数は、印刷の中止や再開、すべてのジョブの削除などプリンタのステータスを変更させるために使用します。

>これらは、lpbPrinter と違い一度に複数の指定は行ないません。この資料では、プリンタの状態については触れませんので、サンプルでもこの引数にはゼロを指定しています。
DEVMODE について
pDevMode で指定される DEVMODE 構造体の値を変更する場合、pDevMode->dmFields フラグでアプリケーションが変更することができるフィールドを確認します。GetPrinter() で、pDevMode の値を取得して、DEVMODE の値を変更する前に、dmFields を確認することができます。

>また、DEVMODE 構造体のデバイスに依存しないメンバの値を変更することは、デバイスに依存するメンバへも影響を及ぼします。SetPrinter() を呼び出す前に、DocumentProperties() を呼び出し SetPrinter() に渡す DEVMODE 構造体を作成します。

>サンプルコード

```c++
   HGLOBAL hGlobal = NULL;
   HGLOBAL hGlobal2 = NULL;
   HANDLE hPrinter = NULL;
   DWORD dwNeeded = 0;
   PRINTER_INFO_2 *pi2 = NULL;
   PRINTER_DEFAULTS pd;
   BOOL bFlag;
   LONG lFlag;

   /* プリンタのハンドルをオープン
   (Windows NT の場合、SetPrinter にはすべての権限 (ALL_ACCESS) が必要になります)
   */

   ZeroMemory(&pd, sizeof(pd));
   pd.DesiredAccess = PRINTER_ALL_ACCESS;
   bFlag = OpenPrinter("My Printer", &hPrinter, &pd);
   if (!bFlag || (hPrinter== NULL))
      goto ABORT;

   /* 最初の GetPrinter() で、PRINTER_INFO_2 全体を格納するのに必要なバッファの
      サイズを取得します。この呼び出しでは、FALSE が返ることに注意してください。
    */

   GetPrinter(hPrinter, 2, 0, 0, &dwNeeded);
   if (dwNeeded == 0)
      goto ABORT;

   /* PRINTER_INFO_2 に十分なスペースの確保 */

   hGlobal = GlobalAlloc(GHND, dwNeeded);
   if (hGlobal == NULL)
      goto ABORT;
   pi2 = (PRINTER_INFO_2 *)GlobalLock(hGlobal);
   if (pi2 == NULL)
      goto ABORT;

   /* 2 回目の GetPrinter() の呼び出しで、現在の設定値を取得します。
      アプリケーションでは必要な個所のみ変更することになります。
    */

   bFlag = GetPrinter(hPrinter, 2, (LPBYTE)pi2, dwNeeded, &dwNeeded);
   if (!bFlag)
      goto ABORT;

   /* もし GetPrinter で、DEVMODE が取得できなかった場合、DocumentProperties で
      取得する 
    */

   if (!pi2->pDevMode)
   {
      dwNeeded = DocumentProperties(hwnd, hPrinter,
                 "My Printer",
                 NULL, NULL, 0);
      if (dwNeeded <= 0)
         goto ABORT;

      hGlobal2 = GlobalAlloc(GHND, dwNeeded);
      if (!hGlobal2)
         goto ABORT;
      pi2->pDevMode = (DEVMODE *)GlobalLock(hGlobal2);
      if (!pi2->pDevMode)
         goto ABORT;

      lFlag = DocumentProperties(hwnd, hPrinter,
              "My Printer",
              pi2->pDevMode, NULL,
              DM_OUT_BUFFER);
      if (lFlag != IDOK)
         goto ABORT;
   }
   /* DEVMODE の変更 */
   pi2->pDevMode->dmFields = DM_ORIENTATION;
   pi2->pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
   /* DEVMODE のデバイス依存部分のアップデート */
   lFlag = DocumentProperties(hwnd, hPrinter,
            "My Printer",
            pi2->pDevMode, pi2->pDevMode,
            DM_IN_BUFFER | DM_OUT_BUFFER);
   if (lFlag != IDOK)
      goto ABORT;
   /* プリンタ情報のアップデート */
   bFlag = SetPrinter(hPrinter, 2, (LPBYTE)pi2, 0);
   if (!bFlag)
      /* ドライバがサポートしていないか、変更の失敗 */
      goto ABORT;
   /* 後処理 */
   ABORT:
      if (hGlobal2 != NULL) {
        if (pi2->pDevMode)
          GlobalUnlock(hGlobal2);
        GlobalFree(hGlobal2);
      }
      if (pi2 != NULL)
         GlobalUnlock(hGlobal);
      if (hGlobal != NULL)
         GlobalFree(hGlobal);
      if (hPrinter != NULL)
         ClosePrinter(hPrinter);
```

>関連情報
この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID
140285 (最終更新日 1998-12-09) をもとに作成したものです

##まとめ的というかまとまっているもの
[プリンタと印刷ジョブの状態の取得方法](https://support.microsoft.com/ja-jp/help/160129/how-to-get-the-status-of-a-printer-and-a-print-job)
>概要
プリンタと印刷ジョブの状態は、ジョブを印刷する (スプールから取り出す) ときに、Win32 スプーラによって更新されます。それ以外の場合、プリンタが印刷しないままで状態情報が報告されないときは、プリンタはアイドル状態で印刷可能であると見なされます。
詳細
Win32 API では、"プリンタ" とは、プリンタ ドライバ、プリント キュー、およびプリンタ装置との入出力の経路から構成されます。オペレーティング システムは、プリンタ装置を、単にこのシステムの "プリンタ" によって生成され、転送される印刷ジョブの出力先と見なします。この資料での "プリンタ" は、このシステムのプリンタを意味します。


##もう少しやさしめ
[010_PRINTER_INFO 構造体とプリンタの列挙](http://mrxray.on.coocan.jp/Delphi/plSamples/010_Printer_Info_Structure.htm)
Delphiの解説の方がまだわかりやすいという状況

###[Win32API 指定されたプリンタのプリンタドライバ情報を取得するs-kita.hatenablog.com](http://s-kita.hatenablog.com/entry/20110601/1306940662)
DRIVER_INFO_3構造体の定義のみを示す。
このほか
[Win32API プリンタの構成要素を列挙する EnumPrinterDatas-kita.hatenablog.com](http://s-kita.hatenablog.com/entry/20120227/1330353801)
プリンタドライバ情報を取得するためには、GetPrinterDriver関数を用いる。
プリンタドライバ情報を取得する手順としては、
1.まずOpenPrinter関数でプリンタオブジェクトのハンドルを取得する
2.次に、取得したプリンタオブジェクトのハンドルを用いてGetPrinterDriver関数を呼び出す。
3.最後に、プリンタオブジェクトのハンドルを使い終わったらClosePrinter関数を用いてハンドルを閉じる。

[Win32API プリンタ情報を取得する](http://s-kita.hatenablog.com/entry/20110703/1309674327)
プリンタ情報を取得するためには、GetPrinter関数を用いる。
GetPrinter関数でプリンタ情報を取得するためには、以下の３つの手順が必要となる