This message was discovered on microsoft.public.dotnet.framework.interop.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.
| manofbluz |
I need the VB.NET equivalent to this KB article.
|
|
| |
| |
| Wei-Dong XU [MSFT] (VIP) |
Hi,
So far as I know, there is no one VB.net version of this kb article. However, from my experience, you can devellop one VB project according to this article and open them in VB.net. VB.net will convert the old VB code into VB.net automatcially.
Please feel free to let me know if you have any question.
Best Regards, Wei-Dong Xu Microsoft Product Support Services Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
|
|
| |
| |
| manofbluz |
I doubt it will convert API calls - that would be a break from MS tradition. Is there another way to set the printer to duplex using .NET objects while still using Word automation PrintOut() to print the document?
"Wei-Dong XU [MSFT]" wrote:
[Original message clipped]
|
|
| |
| |
| Wei-Dong XU [MSFT] (VIP) |
Hi,
I'd suggest there is one excellent P/Invoke site for .Net: http://www.pinvoke.net/
This site has almost all the Win32 api declaration for you, powered by Adam Nathan, the author of <<.NET & COM Interop>>.
For your issue, I prepare the VB.net declaration of these Win 32 api and structure from the kb article 237043 for you below: '---VB.net declaration---------------------------------------- <StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_DEFAULTS Public pDatatype As String Public pDevMode As DEVMODE Public DesiredAccess As Integer End Structure
<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_INFO_2 Public pServerName As String Public pPrinterName As String Public pShareName As String Public pPortName As String Public pDriverName As String Public pComment As String Public pLocation As String Public pDevMode As DEVMODE Public pSepFile As String Public pPrintProcessor As String Public pDatatype As String Public pParameters As String Public pSecurityDescriptor As SECURITY_DESCRIPTOR Public Attributes As Integer Public Priority As Integer Public DefaultPriority As Integer Public StartTime As Integer Public UntilTime As Integer Public Status As Integer Public cJobs As Integer Public AveragePPM As Integer End Structure
<StructLayout(LayoutKind.Sequential)> Public Structure DEVMODE <MarshalAs(UnmanagedType.ByValTStr,SizeConst:= CCHDEVICENAME)> Public dmDeviceName As String Public dmSpecVersion As Integer Public dmDriverVersion As Integer Public dmSize As Integer Public dmDriverExtra As Integer Public dmFields As Integer Public dmOrientation As Integer Public dmPaperSize As Integer Public dmPaperLength As Integer Public dmPaperWidth As Integer Public dmScale As Integer Public dmCopies As Integer Public dmDefaultSource As Integer Public dmPrintQuality As Integer Public dmColor As Integer Public dmDuplex As Integer Public dmYResolution As Integer Public dmTTOption As Integer Public dmCollate As Integer <MarshalAs(UnmanagedType.ByValTStr,SizeConst:= CCHFORMNAME)> Public dmFormName As String Public dmUnusedPadding As Integer Public dmBitsPerPel As Integer Public dmPelsWidth As Integer Public dmPelsHeight As Integer Public dmDisplayFlags As Integer Public dmDisplayFrequency As Integer End Structure
Public Const DM_DUPLEX = &H1000& Public Const DM_IN_BUFFER = DM_MODIFY 'Public Const DM_MODIFY = 8
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) ' Public Const STANDARD_RIGHTS_REQUIRED = &HF0000 ' Public Const PRINTER_ACCESS_ADMINISTER = &H4 ' Public Const PRINTER_ACCESS_USE = &H8
Public Declare Function ClosePrinter Lib "winspool.drv" Alias "ClosePrinter" (ByVal hPrinter As Integer) As Integer Public Declare Function DocumentProperties Lib "winspool.drv" Alias "DocumentPropertiesA" (ByVal hwnd As Integer, ByVal hPrinter As Integer, ByVal pDeviceName As String,<MarshalAs(UnmanagedType.Struct)> ByRef pDevModeOutput As DEVMODE,<MarshalAs(UnmanagedType.Struct)> ByRef pDevModeInput As DEVMODE, ByVal fMode As Integer) As Integer Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" (ByVal hPrinter As Integer, ByVal Level As Integer, pPrinter As Any, ByVal cbBuf As Integer, pcbNeeded As Integer) As Integer Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Integer,<MarshalAs(UnmanagedType.Struct)> ByRef pDefault As PRINTER_DEFAULTS) As Integer Public Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" (ByVal hPrinter As Integer, ByVal Level As Integer, pPrinter As Byte, ByVal Command As Integer) As Integer Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Integer)
Please feel free to let me know if you have any further question.
Best Regards, Wei-Dong Xu Microsoft Product Support Services Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
|
|
| |
| |
| manofbluz |
Thanks, but I'm still having trouble. Here's the code I have so far. Please paste it into VS so you can see the Tasks that need resolving. I'll summarize:
1. VB.NET does not like the Any data type in the Function declarations - I don't know what to change to. 2. the VarPtr function is not defined. This function is from the original KB but the code is not actually in the article, so I don't know what the function does. 3. can't convert Integer to SECURITY_DESCRIPTOR
line of code: pInfo.pSecurityDescriptor = 0
between the two lines of asterisks is the code I have so far ************************* Option Explicit On Imports System Imports System.Runtime.InteropServices Module Module1
<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_DEFAULTS Public pDatatype As String Public pDevMode As DEVMODE Public DesiredAccess As Integer End Structure <StructLayout(LayoutKind.Sequential)> Public Structure SECURITY_DESCRIPTOR 'added this whole structure Public Revision As Byte Public Sbz1 As Byte Public Control As Long Public Owner As Long Public Group As Long Public sACL As ACL Public Dacl As ACL End Structure <StructLayout(LayoutKind.Sequential)> Public Structure ACL 'added this whole structure Public AclRevision As Byte Public Sbz1 As Byte Public AclSize As Integer Public AceCount As Integer Public Sbz2 As Integer End Structure
<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_INFO_2 Public pServerName As String Public pPrinterName As String Public pShareName As String Public pPortName As String Public pDriverName As String Public pComment As String Public pLocation As String Public pDevMode As DEVMODE Public pSepFile As String Public pPrintProcessor As String Public pDatatype As String Public pParameters As String Public pSecurityDescriptor As SECURITY_DESCRIPTOR Public Attributes As Integer Public Priority As Integer Public DefaultPriority As Integer Public StartTime As Integer Public UntilTime As Integer Public Status As Integer Public cJobs As Integer Public AveragePPM As Integer End Structure
<StructLayout(LayoutKind.Sequential)> Public Structure DEVMODE <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> _ Public dmDeviceName As String Public dmSpecVersion As Integer Public dmDriverVersion As Integer Public dmSize As Integer Public dmDriverExtra As Integer Public dmFields As Integer Public dmOrientation As Integer Public dmPaperSize As Integer Public dmPaperLength As Integer Public dmPaperWidth As Integer Public dmScale As Integer Public dmCopies As Integer Public dmDefaultSource As Integer Public dmPrintQuality As Integer Public dmColor As Integer Public dmDuplex As Integer Public dmYResolution As Integer Public dmTTOption As Integer Public dmCollate As Integer <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHFORMNAME)> _ Public dmFormName As String Public dmUnusedPadding As Integer Public dmBitsPerPel As Integer Public dmPelsWidth As Integer Public dmPelsHeight As Integer Public dmDisplayFlags As Integer Public dmDisplayFrequency As Integer End Structure
Public Const CCHDEVICENAME As Integer = 32 'added this Public Const CCHFORMNAME As Integer = 32 'added this Public Const DM_DUPLEX = &H1000& Public Const DM_MODIFY = 8 Public Const DM_IN_BUFFER = DM_MODIFY Public Const DM_COPY = 2 Public Const DM_OUT_BUFFER = DM_COPY 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)
Public Declare Function ClosePrinter Lib "winspool.drv" Alias _ "ClosePrinter" (ByVal hPrinter As Integer) As Integer
Public Declare Function DocumentProperties Lib "winspool.drv" Alias _ "DocumentPropertiesA" (ByVal hwnd As Integer, ByVal hPrinter As Integer, _ ByVal pDeviceName As String, <MarshalAs(UnmanagedType.Struct)> ByRef _ pDevModeOutput As DEVMODE, <MarshalAs(UnmanagedType.Struct)> ByRef _ pDevModeInput As DEVMODE, ByVal fMode As Integer) As Integer
Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterA" _ (ByVal hPrinter As Integer, ByVal Level As Integer, ByVal pPrinter As Any, ByVal _ cbBuf As Integer, ByVal pcbNeeded As Integer) As Integer
Public Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" _ (ByVal pPrinterName As String, ByVal phPrinter As _ Integer, <MarshalAs(UnmanagedType.Struct)> ByRef pDefault As _ PRINTER_DEFAULTS) As Integer
Public Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" _ (ByVal hPrinter As Integer, ByVal Level As Integer, ByVal pPrinter As Byte, ByVal _ Command As Integer) As Integer
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Integer)
' ================================================================== ' SetPrinterDuplex ' ' Programmatically set the Duplex flag for the specified printer ' driver's default properties. ' ' Returns: True on success, False on error. (An error will also
' display a message box. This is done for informational value ' only. You should modify the code to support better error ' handling in your production application.) ' ' Parameters: ' sPrinterName - The name of the printer to be used. ' ' nDuplexSetting - One of the following standard settings: ' 1 = None ' 2 = Duplex on long edge (book) ' 3 = Duplex on short edge (legal) ' ' ================================================================== Public Function SetPrinterDuplex(ByVal sPrinterName As String, _ ByVal nDuplexSetting As Integer) As Boolean
Dim hPrinter As Integer Dim pd As PRINTER_DEFAULTS Dim pinfo As PRINTER_INFO_2 Dim dm As DEVMODE
Dim yDevModeData() As Byte Dim yPInfoMemory() As Byte Dim nBytesNeeded As Integer Dim nRet As Long, nJunk As Long On Error GoTo cleanup
If (nDuplexSetting < 1) Or (nDuplexSetting > 3) Then MsgBox("Error: dwDuplexSetting is incorrect.") Exit Function End If
pd.DesiredAccess = PRINTER_ALL_ACCESS nRet = OpenPrinter(sPrinterName, hPrinter, pd) If (nRet = 0) Or (hPrinter = 0) Then If Err.LastDllError = 5 Then MsgBox("Access denied -- See the article for more info.") Else MsgBox("Cannot open the printer specified " & _ "(make sure the printer name is correct).") End If Exit Function End If
nRet = DocumentProperties(0, hPrinter, sPrinterName, dm, dm, 0) If (nRet < 0) Then MsgBox("Cannot get the size of the DEVMODE structure.") GoTo cleanup End If
ReDim yDevModeData(nRet + 100) nRet = DocumentProperties(0, hPrinter, sPrinterName, _ VarPtr(yDevModeData(0)), 0, DM_OUT_BUFFER)
If (nRet < 0) Then MsgBox("Cannot get the DEVMODE structure.") GoTo cleanup End If
Call CopyMemory(dm, yDevModeData(0), Len(dm))
If Not CBool(dm.dmFields And DM_DUPLEX) Then MsgBox("You cannot modify the duplex flag for this printer " & _ "because it does not support duplex or the driver " & _ "does not support setting it from the Windows API.") GoTo cleanup End If
dm.dmDuplex = nDuplexSetting Call CopyMemory(yDevModeData(0), dm, Len(dm))
nRet = DocumentProperties(0, hPrinter, sPrinterName, _ VarPtr(yDevModeData(0)), VarPtr(yDevModeData(0)), _ DM_IN_BUFFER Or DM_OUT_BUFFER)
If (nRet < 0) Then MsgBox("Unable to set duplex setting to this printer.") GoTo cleanup End If
Call GetPrinter(hPrinter, 2, 0, 0, nBytesNeeded) If (nBytesNeeded = 0) Then GoTo cleanup
ReDim yPInfoMemory(nBytesNeeded + 100)
nRet = GetPrinter(hPrinter, 2, yPInfoMemory(0), nBytesNeeded, nJunk) If (nRet = 0) Then MsgBox("Unable to get shared printer settings.") GoTo cleanup End If
Call CopyMemory(pinfo, yPInfoMemory(0), Len(pinfo)) pinfo.pDevMode = VarPtr(yDevModeData(0)) pinfo.pSecurityDescriptor = 0 Call CopyMemory(yPInfoMemory(0), pinfo, Len(pinfo))
nRet = SetPrinter(hPrinter, 2, yPInfoMemory(0), 0) If (nRet = 0) Then MsgBox("Unable to set shared printer settings.") End If
SetPrinterDuplex = CBool(nRet)
cleanup: If (hPrinter <> 0) Then Call ClosePrinter(hPrinter)
End Function
End Module
****************************** "Wei-Dong XU [MSFT]" wrote:
[Original message clipped]
|
|
| |
| |
| [MSFT] (VIP) |
For question 1: Visual Basic 6 allowed you to declare parameters As Any, meaning that data of any data type could be used. Visual Basic .NET requires that you use a specific data type for all declare statements. Normally, we can declare as:
ByRef Destination As Object
For question 2: There is no VarPtr function in VB.net, but you can use following code instead:
Public Function VarPtr(ByVal o As Object) As IntPtr
Dim GC As System.Runtime.InteropServices.GCHandle = System.Runtime.InteropServices.GCHandle.Alloc(o, System.Runtime.InteropServices.GCHandleType.Pinned)
Dim ret As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return New IntPtr(ret)
End Function
For question 3: pInfo.pSecurityDescriptor = nothing
Anyway, I think there is a .NET way to set the printer's Duplex Property without call APIs. you may take a look at following to see if it will help:
PrinterSettings.Duplex Property http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/ frlrfsystemdrawingprintingprintersettingsclassduplextopic.asp
Hope this help,
Luke
|
|
| |
| |
| manofbluz |
Thanks, Luke, but I'm still having an issue. First, as far as using the .Net printing classes, I already Googled that and found someone who already tried doing what I'm asking about. Apparently, you can't get to the printer settings unless you have a document object (makes sense), but unfortunately you can't assign a Word automation document to the .Net PrintDocument object.
So, I think we're stuck having to resolve this via the API. I made the changes you suggested, but now everywhere I'm calling the VarPtr function, I'm getting the message: "Value of type System.IntPtr cannot be converted to Module1.DEVMODE"
Also, in the second call to the DocumentProperties function:
Redim yDevModeData(nRet + 100) nRet = DocumentProperties(0, hPrinter, sPrinterName, VarPtr(yDevModeData(0), 0, DM_OUT_BUFFER)
..Net objects to the second to the last argument, saying: "Value of type 'Integer' cannot be converted to Module1.DEVMODE"
Please advise. I appreciate the help, as I'm lost with the API, and converting my existing application to VB.Net hinges on being able to print out these Word documents, sometimes in duplex mode, sometimes not.
Thanks.
"[MSFT]" wrote:
[Original message clipped]
|
|
| |
| |
| [MSFT] (VIP) |
I composed a complete sameple for you, you may try it and let me know if there are further question:
Imports System Imports System.Runtime.InteropServices
Module Module1
<DllImport("kernel32.dll", EntryPoint:="GetLastError", _ SetLastError:=False, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ Public Function GetLastError() As Int32 End Function
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", SetLastError:=True, _ ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ Public Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="DocumentPropertiesA", SetLastError:=True, _ ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ Public Function DocumentProperties(ByVal hwnd As IntPtr, ByVal hPrinter As IntPtr, _ <MarshalAs(UnmanagedType.LPStr)> ByVal pDeviceNameg As String, _ ByVal pDevModeOutput As IntPtr, ByRef pDevModeInput As IntPtr, ByVal fMode As Integer) As Integer
End Function
<DllImport("winspool.Drv", EntryPoint:="GetPrinterA", SetLastError:=True, _ ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ Public Function GetPrinter(ByVal hPrinter As IntPtr, ByVal dwLevel As Int32, _ ByVal pPrinter As IntPtr, ByVal dwBuf As Int32, ByRef dwNeeded As Int32) As Boolean End Function
Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, ByRef phPrinter As IntPtr, ByRef pDefault As PRINTER_DEFAULTS) As Integer
<DllImport("winspool.Drv", EntryPoint:="SetPrinterA", ExactSpelling:=True, SetLastError:=True)> _ Public Function SetPrinter(ByVal hPrinter As IntPtr, ByVal Level As Integer, ByVal pPrinter As IntPtr, ByVal Command As Integer) As Boolean End Function
<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_DEFAULTS Public pDatatype As IntPtr Public pDevMode As IntPtr Public DesiredAccess As Integer End Structure
'<StructLayout(LayoutKind.Sequential)> Public Structure PRINTER_DEFAULTS ' Public pDatatype As String ' Public pDevMode As DEVMODE ' Public DesiredAccess As Integer '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 IntPtr 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
Public Const CCDEVICENAME As Short = 32 Public Const CCFORMNAME As Short = 32
<StructLayout(LayoutKind.Sequential)> Public Structure DEVMODE <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCDEVICENAME)> Public dmDeviceName As String Public dmSpecVersion As Short Public dmDriverVersion As Short Public dmSize As Short Public dmDriverExtra As Short Public dmFields As Integer
Public dmOrientation As Short Public dmPaperSize As Short Public dmPaperLength As Short Public dmPaperWidth As Short Public dmScale As Short Public dmCopies As Short Public dmDefaultSource As Short Public dmPrintQuality As Short
Public dmColor As Short Public dmDuplex As Short Public dmYResolution As Short Public dmTTOption As Short Public dmCollate As Short
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCFORMNAME)> Public dmFormName As String
Public dmUnusedPadding As Short Public dmBitsPerPel As Short Public dmPelsWidth As Integer Public dmPelsHeight As Integer Public dmDisplayFlags As Integer Public dmDisplayFrequency As Integer End Structure
'<StructLayout(LayoutKind.Sequential)> Public Structure SECURITY_DESCRIPTOR 'added this whole structure ' Public Revision As Byte ' Public Sbz1 As Byte ' Public Control As Long ' Public Owner As Long ' Public Group As Long ' Public sACL As ACL ' Public Dacl As ACL 'End Structure
'<StructLayout(LayoutKind.Sequential)> Public Structure ACL 'added this whole structure ' Public AclRevision As Byte ' Public Sbz1 As Byte ' Public AclSize As Integer ' Public AceCount As Integer ' Public Sbz2 As Integer 'End Structure
Public Const DM_DUPLEX = &H1000& Public Const DM_MODIFY = 8
Public Const DM_COPY = 2 Public Const DM_IN_BUFFER = 8 Public Const DM_OUT_BUFFER = 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)
Public Const CCHDEVICENAME As Integer = 32 'added this Public Const CCHFORMNAME As Integer = 32 'added this
' ================================================================== ' SetPrinterDuplex ' ' Programmatically set the Duplex flag for the specified printer ' driver's default properties. ' ' Returns: True on success, False on error. (An error will also
' display a message box. This is done for informational value ' only. You should modify the code to support better error ' handling in your production application.) ' ' Parameters: ' sPrinterName - The name of the printer to be used. ' ' nDuplexSetting - One of the following standard settings: ' 1 = None ' 2 = Duplex on long edge (book) ' 3 = Duplex on short edge (legal) ' ' ================================================================== Public Function SetPrinterDuplex(ByVal sPrinterName As String, _ ByVal nDuplexSetting As Integer) As Boolean
Dim hPrinter As IntPtr
Dim pd As PRINTER_DEFAULTS
Dim pinfo As PRINTER_INFO_2 = New PRINTER_INFO_2 Dim dm As DEVMODE = New DEVMODE
Dim ptrDM As IntPtr Dim ptrPrinterInfo As IntPtr Dim sizeOfDevMode As Integer = 0 Dim lastError As Integer Dim yDevModeData() As Byte Dim yPInfoMemory() As Byte Dim nBytesNeeded As Integer Dim nRet As Integer Dim nJunk As Int32
If (nDuplexSetting < 1) Or (nDuplexSetting > 3) Then MsgBox("Error: dwDuplexSetting is incorrect.") Exit Function End If
pd.DesiredAccess = PRINTER_ALL_ACCESS nRet = OpenPrinter(sPrinterName, hPrinter, pd) If (nRet = 0) Or (hPrinter.ToInt32 = 0) Then If Err.LastDllError = 5 Then MsgBox("Access denied -- See the article for more info.") Else MsgBox("Cannot open the printer specified " & _ "(make sure the printer name is correct).") End If Exit Function End If
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, IntPtr.Zero, 0) If (nRet < 0) Then MsgBox("Cannot get the size of the DEVMODE structure.") GoTo cleanup End If
Dim iparg As IntPtr = Marshal.AllocCoTaskMem(nRet + 100)
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, iparg, IntPtr.Zero, DM_OUT_BUFFER)
If (nRet < 0) Then MsgBox("Cannot get the DEVMODE structure.") GoTo cleanup End If
dm = Marshal.PtrToStructure(iparg, dm.GetType)
If Not CBool(dm.dmFields And DM_DUPLEX) Then MsgBox("You cannot modify the duplex flag for this printer " & _ "because it does not support duplex or the driver " & _ "does not support setting it from the Windows API.") GoTo cleanup End If
dm.dmDuplex = nDuplexSetting
Marshal.StructureToPtr(dm, iparg, True)
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pinfo.pDevMode, pinfo.pDevMode, DM_IN_BUFFER Or DM_OUT_BUFFER)
If (nRet < 0) Then MsgBox("Unable to set duplex setting to this printer.") GoTo cleanup End If
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, nBytesNeeded)
If (nBytesNeeded = 0) Then GoTo cleanup
ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded + 100)
nRet = GetPrinter(hPrinter, 2, ptrPrinterInfo, nBytesNeeded, nJunk)
If (nRet = 0) Then MsgBox("Unable to get shared printer settings.") GoTo cleanup End If
pinfo = Marshal.PtrToStructure(ptrPrinterInfo, pinfo.GetType)
pinfo.pDevMode = iparg pinfo.pSecurityDescriptor = IntPtr.Zero Marshal.StructureToPtr(pinfo, ptrPrinterInfo, True)
Dim o As New ClassLibrary1.Class1
o.SetPrinterDuplex(sPrinterName, 2)
hPrinter = o.hPrinter ptrPrinterInfo = o.ptrPrinterInfo
nRet = SetPrinter(hPrinter, 2, ptrPrinterInfo, 0)
MsgBox(GetLastError())
If (nRet = 0) Then MsgBox("Unable to set shared printer settings.") End If
SetPrinterDuplex = CBool(nRet)
cleanup: If (hPrinter.ToInt32 <> 0) Then Call ClosePrinter(hPrinter)
End Function
End Module
|
|
| |
| |
| manofbluz |
Thanks, again, Luke, but I think you forgot to paste in some code. In the middle of the SetPrinterDuplex function, you instantiate a class for which you didn't include the code:
Dim o As New ClassLibrary1.Class1
"[MSFT]" wrote:
[Original message clipped]
|
|
| |
| |
| [MSFT] (VIP) |
Sorry. I forgot to remove some debug code. Following code is not necessary:
Dim o As New ClassLibrary1.Class1
o.SetPrinterDuplex(sPrinterName, 2)
hPrinter = o.hPrinter ptrPrinterInfo = o.ptrPrinterInfo
Please remove them and test again.
Thanks,
Luke
|
|
| |
| |
| manofbluz |
I'm sorry, too. I forgot to tell you that I had already commented out those lines and tried it. The code runs fine but the document doesn't actually duplex. So, I wanted to make sure those lines weren't necessary.
I orginally got "Access Denied" so I did what the article said and installed the network printer locally. I've tried the code against two different printers, an HP and a Canon and neither works. Does this actually work for you when used in conjunction with Word Automation?
"[MSFT]" wrote:
[Original message clipped]
|
|
| |
| |
| [MSFT] (VIP) |
Hello,
VB.NET app may get some interop problem when performing API calls. Is C# code good for you? I also have a sample which work fine on my computer. I paste here and you may try it. To embed it in your VB project, you may add a C# class library project and reference it in VB project.
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Runtime.InteropServices; using System.Drawing.Printing;
namespace setprintertest { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null;
public Form1() { // // Required for Windows Form Designer support // InitializeComponent();
// // TODO: Add any constructor code after InitializeComponent call // }
/// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); }
#region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(112, 176); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(80, 32); this.button1.TabIndex = 0; this.button1.Text = "button1"; this.button1.Click += new System.EventHandler(this.button1_Click); // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.button1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false);
} #endregion
/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); }
[DllImport("kernel32.dll", EntryPoint="GetLastError", SetLastError=false, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] internal static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint="ClosePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="DocumentPropertiesA", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall )] private static extern int DocumentProperties (IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg, IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint="GetPrinterA", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.Drv", EntryPoint="OpenPrinterA", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
[DllImport("winspool.Drv",EntryPoint="SetPrinterA", ExactSpelling=true, SetLastError=true)] private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr pPrinter, int Command);
// Wrapper for Win32 message formatter.
[StructLayout(LayoutKind.Sequential)] private struct PRINTER_DEFAULTS { public IntPtr pDatatype; public IntPtr pDevMode; public int DesiredAccess; }
[StructLayout(LayoutKind.Sequential)] private struct PRINTER_INFO_2 { [MarshalAs(UnmanagedType.LPStr)] public string pServerName; [MarshalAs(UnmanagedType.LPStr)] public string pPrinterName; [MarshalAs(UnmanagedType.LPStr)] public string pShareName; [MarshalAs(UnmanagedType.LPStr)] public string pPortName; [MarshalAs(UnmanagedType.LPStr)] public string pDriverName; [MarshalAs(UnmanagedType.LPStr)] public string pComment; [MarshalAs(UnmanagedType.LPStr)] public string pLocation; public IntPtr pDevMode; [MarshalAs(UnmanagedType.LPStr)] public string pSepFile; [MarshalAs(UnmanagedType.LPStr)] public string pPrintProcessor; [MarshalAs(UnmanagedType.LPStr)] public string pDatatype; [MarshalAs(UnmanagedType.LPStr)] public string pParameters; public IntPtr pSecurityDescriptor; public Int32 Attributes; public Int32 Priority; public Int32 DefaultPriority; public Int32 StartTime; public Int32 UntilTime; public Int32 Status; public Int32 cJobs; public Int32 AveragePPM; }
private const short CCDEVICENAME = 32; private const short CCFORMNAME = 32;
[StructLayout(LayoutKind.Sequential)] private struct DEVMODE { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)] public string dmDeviceName;
public short dmSpecVersion; public short dmDriverVersion; public short dmSize; public short dmDriverExtra; public int dmFields;
public short dmOrientation; public short dmPaperSize; public short dmPaperLength; public short dmPaperWidth; public short dmScale; public short dmCopies; public short dmDefaultSource; public short dmPrintQuality;
public short dmColor; public short dmDuplex; public short dmYResolution; public short dmTTOption; public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)] public string dmFormName;
public short dmUnusedPadding; public short dmBitsPerPel; public int dmPelsWidth; public int dmPelsHeight; public int dmDisplayFlags; public int dmDisplayFrequency; }
public const int DM_DUPLEX = 0x1000; public const int DM_IN_BUFFER = 8;
public const int DM_OUT_BUFFER = 2; public const int PRINTER_ACCESS_ADMINISTER = 0x4; public const int PRINTER_ACCESS_USE = 0x8; public const int STANDARD_RIGHTS_REQUIRED = 0xF0000; private System.Windows.Forms.Button button1; public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
public bool SetPrinterDuplex(string sPrinterName, int nDuplexSetting) { IntPtr hPrinter; PRINTER_DEFAULTS pd = new PRINTER_DEFAULTS(); PRINTER_INFO_2 pinfo = new PRINTER_INFO_2(); DEVMODE dm; IntPtr ptrDM; IntPtr ptrPrinterInfo; int sizeOfDevMode = 0; int lastError; byte[] yDevModeData; byte[] yPInfoMemory; int nBytesNeeded; int nRet; System.Int32 nJunk;
//On Error GoTo cleanup
if ((nDuplexSetting < 1) || (nDuplexSetting > 3) ) { throw new ArgumentOutOfRangeException("nDuplexSetting","nDuplexSetting is incorrect."); } else { //if no printername provided, check if there is a default printer and use it instead if (sPrinterName.Trim() == "") { PrintDocument printDocument1 = new PrintDocument(); sPrinterName = printDocument1.PrinterSettings.PrinterName;// + "\0"; }
//open the printer pd.DesiredAccess = PRINTER_ALL_ACCESS; nRet = Convert.ToInt32(OpenPrinter(sPrinterName, out hPrinter, ref pd));
if ((nRet == 0) || (hPrinter == IntPtr.Zero)) { return false; }
IntPtr para=IntPtr.Zero;
sizeOfDevMode=DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, ref para, 0); if(sizeOfDevMode<0) { MessageBox.Show("Cannot get the size of the DEVMODE structure"); }
IntPtr iparg = Marshal.AllocCoTaskMem(sizeOfDevMode+100); nRet = DocumentProperties(IntPtr.Zero , hPrinter, sPrinterName, iparg, ref para, DM_OUT_BUFFER); if(nRet<0) { MessageBox.Show("Cannot get the DEVMODE structure"); }
dm=(DEVMODE)Marshal.PtrToStructure(iparg, typeof(DEVMODE));
if (!Convert.ToBoolean(dm.dmFields & DM_DUPLEX)) { //You cannot modify the duplex flag for this printer //because it does not support duplex or the driver does not support setting //it from the Windows API. return false; }
dm.dmDuplex = (short)nDuplexSetting; Marshal.StructureToPtr(dm, iparg, true);
nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, pinfo.pDevMode , ref pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER)); if (nRet < 0) { //Unable to set duplex setting to this printer. return false; }
//get the size of the Printer Info structure nRet = Convert.ToInt32(GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out nBytesNeeded)); if (nBytesNeeded <= 0) { return false; } // Allocate enough space for PRINTER_INFO_2... ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded+100);
// The second GetPrinter fills in all the current settings, so all you // need to do is modify what you're interested in... nRet = Convert.ToInt32(GetPrinter(hPrinter, 2, ptrPrinterInfo, nBytesNeeded, out nJunk)); if (nRet == 0) { return false; } pinfo = (PRINTER_INFO_2)Marshal.PtrToStructure(ptrPrinterInfo, typeof(PRINTER_INFO_2)); pinfo.pDevMode=iparg; pinfo.pSecurityDescriptor =IntPtr.Zero; Marshal.StructureToPtr(pinfo,ptrPrinterInfo,true);
nRet = Convert.ToInt16(SetPrinter(hPrinter, 2, ptrPrinterInfo, 0)); if (nRet == 0)//Unable to set shared printer settings. { lastError = Marshal.GetLastWin32Error(); //string myErrMsg = GetErrorMessage(lastError);
return false; } } if (hPrinter != IntPtr.Zero) ClosePrinter(hPrinter); return Convert.ToBoolean(nRet);
}
private void button1_Click(object sender, System.EventArgs e) { SetPrinterDuplex("MyTestPrinter",2); } } }
Luke
|
|
| |
| |
| manofbluz |
Luke,
The C# code does the exact same thing as the VB. I can step through the code and everything seems to work. It doesn't throw the exception that my printer cannot be manipulated via the API; nevertheless it simply won't duplex the document - it spits out two pages.
Anyway, I think you've given this enough energy and I certainly appreciate it. I'm just going to have to go with a different solution, I think.
"[MSFT]" wrote:
[Original message clipped]
|
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|