Click here to Skip to main content
15,892,643 members
Home / Discussions / Visual Basic
   

Visual Basic

 
GeneralVB6 and API calls Pin
aslm6-Oct-04 3:50
aslm6-Oct-04 3:50 
GeneralRe: VB6 and API calls Pin
Anonymous6-Oct-04 12:24
Anonymous6-Oct-04 12:24 
GeneralProblem in "LookupAccountName" function Pin
zeemalik6-Oct-04 0:33
zeemalik6-Oct-04 0:33 
QuestionWH_CBT Global hook? Pin
Hadi Fakhreddine5-Oct-04 20:26
Hadi Fakhreddine5-Oct-04 20:26 
AnswerRe: WH_CBT Global hook? Pin
Anonymous6-Oct-04 11:03
Anonymous6-Oct-04 11:03 
GeneralRe: WH_CBT Global hook? Pin
Hadi Fakhreddine7-Oct-04 20:27
Hadi Fakhreddine7-Oct-04 20:27 
GeneralRe: WH_CBT Global hook? Pin
Anonymous11-Oct-04 9:26
Anonymous11-Oct-04 9:26 
GeneralUsing OpenPrinter/SetPrinter in Win2K3 Pin
cnurse5-Oct-04 20:05
cnurse5-Oct-04 20:05 
Pardon the big post...

I am using the code below to set my printer into Duplex mode, which has to be done via the driver as I sometimes want duplex printing in word, and sometimes I dont. Anyway, regardless of whether you think this can be done with System.Drawing.Printing or not, I want to limit this purely to "why do my API calls not work" as a worthwhile excercise in unmanaged code and interop...

Based on many articles I have seen on the web I came up with the class below, but it seems I am also suffering the same woes that every user who ever tried to switch duplex printing on, has suffered, and that it is hard to get it to work.

Why am I getting access denied as commented below?
Why do the docs say that OpenPrinter has to take a PRINTER_DEFAULTS byref, and when I pass it by ref, every thing breaks at runt time, like, I don't get a printer handle and OpenPrinter causes an Err.LastDllError of 5 (access denied).

I think you either know the answer to this one or not. I don't want speculcation and supposition, just hard tested solutions, coz the web is littered with suggestions that dont seem to work.

The fundamental problem seems to be that my code doesn't have the right security descriptior to use SetPrinter, even if I log on to my Windows 2003 server as an administrator.

Thanks guys, in advance for your patience and efforts!

''' TEST CODE FOR CLASS - put this in a form or module

Private Sub Test()
Dim lPrinter As New APIPrinter
Dim lName As String = lPrinter.DefaultPrinterName

lPrinter.Open(lName)
lPrinter.DuplexMode = APIPrinter.DuplexOption.LongEdge
lPrinter.Close()

End Sub

''' CODE FOR CLASS - put this in a spearate class VB file
Imports System.Runtime.InteropServices
Imports System.Text

Public Class APIPrinter
Implements IDisposable

#Region "WinApi"

#Region "Structures"

<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_DEFAULTS
<MarshalAs(UnmanagedType.LPStr)> Public pDatatype As String
Public pDevMode As IntPtr
Public DesiredAccess As Int32
End Structure

<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_INFO_2
<MarshalAs(UnmanagedType.LPStr)> Public pServerName As String
<MarshalAs(UnmanagedType.LPStr)> Public pPrinterName As String
<MarshalAs(UnmanagedType.LPStr)> Public pShareName As String
<MarshalAs(UnmanagedType.LPStr)> Public pPortName As String
<MarshalAs(UnmanagedType.LPStr)> Public pDriverName As String
<MarshalAs(UnmanagedType.LPStr)> Public pComment As String
<MarshalAs(UnmanagedType.LPStr)> Public pLocation As String
Public pDevMode As IntPtr
<MarshalAs(UnmanagedType.LPStr)> Public pSepFile As String
<MarshalAs(UnmanagedType.LPStr)> Public pPrintProcessor As String
<MarshalAs(UnmanagedType.LPStr)> Public pDatatype As String
<MarshalAs(UnmanagedType.LPStr)> Public pParameters As String
Public pSecurityDescriptor As Int32
Public Attributes As Int32
Public Priority As Int32
Public DefaultPriority As Int32
Public StartTime As Int32
Public UntilTime As Int32
Public Status As Int32
Public cJobs As Int32
Public AveragePPM As Int32
End Structure

<StructLayout(LayoutKind.Sequential)> Public Structure DEVMODE
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public dmDeviceName As String
Public dmSpecVersion As Int32
Public dmDriverVersion As Int32
Public dmSize As Int32
Public dmDriverExtra As Int32
Public dmFields As Int32
Public dmOrientation As Int32
Public dmPaperSize As Int32
Public dmPaperLength As Int32
Public dmPaperWidth As Int32
Public dmScale As Int32
Public dmCopies As Int32
Public dmDefaultSource As Int32
Public dmPrintQuality As Int32
Public dmColor As Int32
Public dmDuplex As Int32
Public dmYResolution As Int32
Public dmTTOption As Int32
Public dmCollate As Int32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public dmFormName As String
Public dmUnusedPadding As Int32
Public dmBitsPerPel As Int32
Public dmPelsWidth As Int32
Public dmPelsHeight As Int32
Public dmDisplayFlags As Int32
Public dmDisplayFrequency As Int32
End Structure

#End Region

#Region "Constants"

Public Const DM_DUPLEX = &H1000&
Public Const DM_IN_BUFFER = DM_MODIFY
Public Const DM_MODIFY = 8
Public Const DM_PROMPT = 4
Public Const DM_OUT_BUFFER = DM_COPY
Public Const DM_COPY = 2
Public Const PRINTER_ACCESS_ADMINISTER = &H4
Public Const PRINTER_ACCESS_USE = &H8
Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
Public Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)

#End Region

' HELP!!!
' This is the way the docs indicate that OpenPrinter should be declared. but if I do it this way
' then the call fails as described in the code below.
'Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, ByRef phPrinter As Int32, ByRef pDefault As PRINTER_DEFAULTS) As Int32
' HELP!!!
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, ByRef phPrinter As Int32, ByVal pDefault As PRINTER_DEFAULTS) As Int32

Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Int32) As Int32
Private Declare Function PrinterProperties Lib "winspool.drv" (ByVal hWND As Int32, ByVal hPrinter As Int32) As Int32

Private Declare Function DocumentProperties Lib "winspool.drv" Alias "DocumentPropertiesA" (ByVal hwnd As Int32, ByVal hPrinter As Int32, ByVal pDeviceNameg As String, ByVal pDevModeOutput As IntPtr, ByRef pDevModeInput As IntPtr, ByVal ByValfMode As Int32) As Int32

Private Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Int32, ByVal Level As Int32, ByVal pPrinter As IntPtr, ByVal cbBuf As Int32, ByRef pcbNeeded As Int32) As Int32
Private Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" (ByVal hPrinter As Int32, ByVal Level As Int32, ByVal pPrinter As IntPtr, ByVal Command As Int32) As Int32
Private Declare Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" (ByVal lName As String, ByRef lBuffLen As Int32) As Int32

#End Region

#Region "Properties and Enumerations"

Public Enum DuplexOption
None
LongEdge
ShortEdge
End Enum

Private mPrinterHandle As Int32
Private mDeviceMode As New DEVMODE
Private mName As String
Private mDuplexOption As DuplexOption
Private mDevModeSize As Int32
Private mMemBuffer As IntPtr

Public Shared ReadOnly Property DefaultPrinterName() As String
Get
Dim lName As String = Space(1024)
Dim lBuffLen As Int32 = Len(lName)
GetDefaultPrinter(lName, lBuffLen)

Return lName
End Get
End Property

Public Property Name() As String
Get
Return mName
End Get
Set(ByVal Value As String)
mName = Value
End Set
End Property

Public Property DuplexMode() As DuplexOption
Get
GetProperties()

Select Case mDeviceMode.dmDuplex
Case 1
Return DuplexOption.ShortEdge

Case 2
Return DuplexOption.LongEdge

Case Else
Return DuplexOption.None

End Select
End Get
Set(ByVal Value As DuplexOption)
mDuplexOption = Value
mDeviceMode.dmFields = DM_DUPLEX

Select Case mDuplexOption
Case DuplexOption.LongEdge
mDeviceMode.dmDuplex = 2

Case DuplexOption.ShortEdge
mDeviceMode.dmDuplex = 3

Case Else
mDeviceMode.dmDuplex = 1
End Select

SetProperties()
End Set
End Property

#End Region

Public Sub Open(ByVal pPrinterName As String)
Dim lDefaults As PRINTER_DEFAULTS
lDefaults.DesiredAccess = PRINTER_ALL_ACCESS
lDefaults.pDatatype = vbNullString
lDefaults.pDevMode = IntPtr.Zero

' HELP!!!
' If OpenPrinter uses ... ByRef pDefault As PRINTER_DEFAULTS then
' why does this call fail with Err.LastDllError = 5 (access denied)
' HELP!!!
Dim lRetCode As Integer = OpenPrinter(pPrinterName, mPrinterHandle, lDefaults)

If lRetCode = 0 Then
lRetCode = Err.LastDllError
End If

If Err.LastDllError = 5 Then
mPrinterHandle = 0
Else
If mPrinterHandle <> 0 Then
mDevModeSize = DocumentProperties(0, mPrinterHandle, pPrinterName, IntPtr.Zero, IntPtr.Zero, 0)

If mDevModeSize > 0 Then
mMemBuffer = Marshal.AllocCoTaskMem(mDevModeSize)
GetProperties()

Name = pPrinterName
End If
End If
End If
End Sub

Public Sub Close()
If mPrinterHandle > 0 Then
ClosePrinter(mPrinterHandle)
Marshal.FreeCoTaskMem(mMemBuffer)
End If

mPrinterHandle = 0
End Sub

Private Sub GetProperties()
If mPrinterHandle > 0 Then
Dim lRetCode As Integer = DocumentProperties(0, mPrinterHandle, mName, mMemBuffer, IntPtr.Zero, DM_OUT_BUFFER)

If lRetCode > 0 Then
mDeviceMode = Marshal.PtrToStructure(mMemBuffer, mDeviceMode.GetType)
End If

End If
End Sub

Public Sub SetProperties()
If mPrinterHandle > 0 Then
Dim lRetCode As Integer

mDeviceMode.dmOrientation = 2
mDeviceMode.dmDuplex = 2

Marshal.StructureToPtr(mDeviceMode, mMemBuffer, True)
lRetCode = DocumentProperties(0, mPrinterHandle, mName, mMemBuffer, mMemBuffer, DM_IN_BUFFER Or DM_OUT_BUFFER)

Dim lSharedStat As Boolean = SetSharedSettings()
lRetCode = DocumentProperties(0, mPrinterHandle, mName, mMemBuffer, mMemBuffer, DM_IN_BUFFER Or DM_OUT_BUFFER Or DM_PROMPT)
End If
End Sub

Private Function SetSharedSettings() As Boolean
Dim lBuffLen As Int32
Dim lRetCode As Int32 = GetPrinter(mPrinterHandle, 2, IntPtr.Zero, 0, lBuffLen)

If lBuffLen > 0 Then
Dim lBytesRead As Int32
Dim lBuff As IntPtr = Marshal.AllocCoTaskMem(lBuffLen)
lRetCode = GetPrinter(mPrinterHandle, 2, lBuff, lBuffLen, lBytesRead)

If lRetCode > 0 Then
Dim lInfo As PRINTER_INFO_2

lInfo = Marshal.PtrToStructure(lBuff, lInfo.GetType)
lInfo.pDevMode = mMemBuffer
lInfo.pSecurityDescriptor = 0
Marshal.StructureToPtr(lInfo, lBuff, True)

' HELP!!!
' This always fails with Err.LastDllError = 5 (access denied)
' This makes me think that there is someting wrong with the
' security descriptor.
' HELP!!!
lRetCode = SetPrinter(mPrinterHandle, 2, lBuff, 0)

If lRetCode <= 0 Then
lRetCode = Err.LastDllError
End If

Marshal.FreeCoTaskMem(lBuff)
Return True
End If
End If

Return False

End Function

Public Sub Dispose() Implements System.IDisposable.Dispose
If mPrinterHandle > 0 Then
Close()
End If
End Sub
End Class


Nursey
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
Anonymous6-Oct-04 8:31
Anonymous6-Oct-04 8:31 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
cnurse6-Oct-04 18:36
cnurse6-Oct-04 18:36 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
Anonymous6-Oct-04 19:05
Anonymous6-Oct-04 19:05 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
cnurse6-Oct-04 19:30
cnurse6-Oct-04 19:30 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
cnurse6-Oct-04 20:02
cnurse6-Oct-04 20:02 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
Anonymous6-Oct-04 20:51
Anonymous6-Oct-04 20:51 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
cnurse6-Oct-04 21:00
cnurse6-Oct-04 21:00 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
Anonymous6-Oct-04 21:07
Anonymous6-Oct-04 21:07 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
cnurse6-Oct-04 19:05
cnurse6-Oct-04 19:05 
GeneralRe: Using OpenPrinter/SetPrinter in Win2K3 Pin
Anonymous6-Oct-04 19:11
Anonymous6-Oct-04 19:11 
GeneralCheckbox Unchecks Itself Pin
Baraholka5-Oct-04 15:36
Baraholka5-Oct-04 15:36 
GeneralRe: Checkbox Unchecks Itself Pin
MohammadAmiry6-Oct-04 5:31
MohammadAmiry6-Oct-04 5:31 
Generaldatepicker Pin
Paps25-Oct-04 11:11
Paps25-Oct-04 11:11 
GeneralRe: datepicker Pin
Anonymous5-Oct-04 11:29
Anonymous5-Oct-04 11:29 
QuestionHow to optimize image transfer Pin
tommy_tanaka5-Oct-04 9:40
tommy_tanaka5-Oct-04 9:40 
AnswerRe: How to optimize image transfer Pin
Dave Kreskowiak5-Oct-04 11:07
mveDave Kreskowiak5-Oct-04 11:07 
GeneralRe: How to optimize image transfer Pin
tommy_tanaka6-Oct-04 0:11
tommy_tanaka6-Oct-04 0:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.