Всем доброго времени суток, суть моей проблемы вот в чем:
По работе необходимо написать внешнюю программу/скрипт, который бы изменял настройки принтера (пользователи нынче пошли ленивые, не знают/могут где-что нужно переключать чтобы поменять ориентацию при печати документа). Т.о. изменяться должны настройки принтера по-умолчанию. Пробовал использовать скрипты на VBS, наподобие:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colInstalledPrinters = objWMIService.ExecQuery _
("Select * from Win32_PrinterConfiguration")
For Each objPrinter in colInstalledPrinters
Wscript.Echo "Name: " & objPrinter.Name
objPrinter.Orientation=2
objPrinter.put_
Next
Но все свелось к:
автор Unfortunately, that technique won't work. The Win32_PrinterConfiguration properties are read-only.
Тогда я попробовал провернуть все через драйвер winspool.drv как указано ниже:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
Option Explicit
Private Const CCHDEVICENAME = 32
Private Const CCHFORMNAME = 32
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const PRINTER_ACCESS_ADMINISTER = &H4
Private Const PRINTER_ACCESS_USE = &H8
Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or _
PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
Private Const DM_MODIFY = 8
Private Const DM_IN_BUFFER = DM_MODIFY
Private Const DM_COPY = 2
Private Const DM_OUT_BUFFER = DM_COPY
Private Const DMORIENT_PORTRAIT = 1
Private Const DMORIENT_LANDSCAPE = 2
Private Const DM_ORIENTATION = &H1
Private Type DEVMODE
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
dmLogPixels As Integer
dmBitsPerPel As Long
dmPelsWidth As Long
dmPelsHeight As Long
dmDisplayFlags As Long
dmDisplayFrequency As Long
dmICMMethod As Long
dmICMIntent As Long
dmMediaType As Long
dmDitherType As Long
dmReserved1 As Long
dmReserved2 As Long
End Type
Private Type PRINTER_DEFAULTS
pDatatype As String
pDevMode As Long
DesiredAccess As Long
End Type
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _
(ByVal pPrinterName As String, phPrinter As Long, pDefault As _
PRINTER_DEFAULTS) As Long
Private Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" _
(ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, ByVal Command _
As Long) As Long
Private Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" _
(ByVal hPrinter As Long, ByVal Level As Long, pPrinter As Any, ByVal cbBuf As _
Long, pcbNeeded As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (hpvDest As _
Any, hpvSource As Any, ByVal cbCopy As Long)
Private Declare Function ClosePrinter Lib "winspool.drv" (ByValhPrinter 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, ByVal pDevModeOutput As Any, ByVal pDevModeInput As _
Any, ByVal fMode As Long) As Long
Public Sub SetOrientation(NewOrientation As Long, Optional ByVal m_hwnd As Long)
'On Error GoTo eh
Dim PrinterHandle As Long
Dim PrinterName As String
Dim MyString As String
Dim pd As PRINTER_DEFAULTS
Dim lpDevMode As DEVMODE
Dim Result As Long
Dim Needed As Long
Dim pFullDevMode As Long
Dim pi2_buffer() As Long
PrinterName = Printer.DeviceName
If PrinterName = "" Then
Exit Sub
End If
pd.pDatatype = vbNullString
pd.pDevMode = 0&
pd.DesiredAccess = PRINTER_ALL_ACCESS
Result = OpenPrinter(PrinterName, PrinterHandle, pd)
Result = GetPrinter(PrinterHandle, 2, ByVal 0&, 0, Needed)
ReDim pi2_buffer((Needed \ 4))
Result = GetPrinter(PrinterHandle, 2, pi2_buffer(0), Needed, Needed)
pFullDevMode = pi2_buffer(7)
Call CopyMemory(lpDevMode, ByVal pFullDevMode, Len(lpDevMode))
lpDevMode.dmOrientation = NewOrientation
lpDevMode.dmFields = DM_ORIENTATION
Call CopyMemory(ByVal pFullDevMode, lpDevMode, Len(lpDevMode))
Result = DocumentProperties(m_hwnd, PrinterHandle, PrinterName, ByVal _
pFullDevMode, ByVal pFullDevMode, DM_IN_BUFFER Or DM_OUT_BUFFER)
Result = SetPrinter(PrinterHandle, 2, pi2_buffer(0), 0&)
Call ClosePrinter(PrinterHandle)
Dim p As Printer
For Each p In Printers
If p.DeviceName = PrinterName Then
Set Printer = p
Exit For
End If
Next p
Printer.Orientation = lpDevMode.dmOrientation
Exit Sub
eh:
Label2.Caption = "Error occured during executing"
End Sub
Процедура отрабатывает корректно и при вызове с нужными параметрами изменяет ориентацию листа принтера по-умолчанию. Но только если запускать "от имени Администратора" или в среде разработки (Microsoft Visual Basic 6-Portable). Если вызывать исполнение этой программы из другой или просто запускать из директории, то ничего не происходит.
В ходе дебаггинга, выяснилось что проблема в получении дексриптора принтера (
):
1.
Result = OpenPrinter(PrinterName, PrinterHandle, pd)
При вызове не "от имени администратора", в
Result возвращается 0, а в
PrinterHandle соответственно не пишется дексриптор. (вот тут про функцию:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162751(v=vs.85).aspx )
Что можно с этим сделать? По какой причине функция так себя ведет? Заранее спасибо!
(П.С. До этого момента c VB почти не работал, поэтому большая просьба писать советы как можно подробней)