我在Windows 7上访问和更改打印机设置时遇到了严重问题。
Option Strict On
Imports System.Runtime.InteropServices
Imports System.ComponentModel
<StructLayout(LayoutKind.Sequential)> _
Structure PRINTER_DEFAULTS
Public pDatatype As IntPtr
Public pDevMode As IntPtr
Public DesiredAccess As Integer
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Structure PRINTER_INFO_2
<MarshalAs(UnmanagedType.LPTStr)> _
Public pServerName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pPrinterName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pShareName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pPortName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pDriverName As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pComment As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pLocation As String
Public pDevMode As IntPtr
<MarshalAs(UnmanagedType.LPTStr)> _
Public pSepFile As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pPrintProcessor As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pDatatype As String
<MarshalAs(UnmanagedType.LPTStr)> _
Public pParameters As String
Public pSecurityDescriptor As IntPtr
Public Attributes As UInteger
Public Priority As UInteger
Public DefaultPriority As UInteger
Public StartTime As UInteger
Public UntilTime As UInteger
Public Status As UInteger
Public cJobs As UInteger
Public AveragePPM As UInteger
End Structure
Structure POINTL
Public x As Int32
Public y As Int32
End Structure
<Flags()> _
Enum DM As Integer
Orientation = &H1
PaperSize = &H2
PaperLength = &H4
PaperWidth = &H8
Scale = &H10
Position = &H20
NUP = &H40
DisplayOrientation = &H80
Copies = &H100
DefaultSource = &H200
PrintQuality = &H400
Color = &H800
Duplex = &H1000
YResolution = &H2000
TTOption = &H4000
Collate = &H8000
FormName = &H10000
LogPixels = &H20000
BitsPerPixel = &H40000
PelsWidth = &H80000
PelsHeight = &H100000
DisplayFlags = &H200000
DisplayFrequency = &H400000
ICMMethod = &H800000
ICMIntent = &H1000000
MediaType = &H2000000
DitherType = &H4000000
PanningWidth = &H8000000
PanningHeight = &H10000000
DisplayFixedOutput = &H20000000
End Enum
<StructLayout(LayoutKind.Explicit, CharSet:=CharSet.Ansi)> _
Structure DEVMODE
Public Const CCHDEVICENAME As Integer = 32
Public Const CCHFORMNAME As Integer = 32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHDEVICENAME)> _
<System.Runtime.InteropServices.FieldOffset(0)> _
Public dmDeviceName As String
<System.Runtime.InteropServices.FieldOffset(32)> _
Public dmSpecVersion As Int16
<System.Runtime.InteropServices.FieldOffset(34)> _
Public dmDriverVersion As Int16
<System.Runtime.InteropServices.FieldOffset(36)> _
Public dmSize As Int16
<System.Runtime.InteropServices.FieldOffset(38)> _
Public dmDriverExtra As Int16
<System.Runtime.InteropServices.FieldOffset(40)> _
Public dmFields As DM
<System.Runtime.InteropServices.FieldOffset(44)> _
Private dmOrientation As Int16
<System.Runtime.InteropServices.FieldOffset(46)> _
Private dmPaperSize As Int16
<System.Runtime.InteropServices.FieldOffset(48)> _
Private dmPaperLength As Int16
<System.Runtime.InteropServices.FieldOffset(50)> _
Private dmPaperWidth As Int16
<System.Runtime.InteropServices.FieldOffset(52)> _
Public dmScale As Int16
<System.Runtime.InteropServices.FieldOffset(54)> _
Public dmCopies As Int16
<System.Runtime.InteropServices.FieldOffset(56)> _
Private dmDefaultSource As Int16
<System.Runtime.InteropServices.FieldOffset(58)> _
Private dmPrintQuality As Int16
<System.Runtime.InteropServices.FieldOffset(44)> _
Public dmPosition As POINTL
<System.Runtime.InteropServices.FieldOffset(52)> _
Public dmDisplayOrientation As Int32
<System.Runtime.InteropServices.FieldOffset(56)> _
Public dmDisplayFixedOutput As Int32
<System.Runtime.InteropServices.FieldOffset(60)> _
Public dmColor As Short
<System.Runtime.InteropServices.FieldOffset(62)> _
Public dmDuplex As Short
<System.Runtime.InteropServices.FieldOffset(64)> _
Public dmYResolution As Short
<System.Runtime.InteropServices.FieldOffset(66)> _
Public dmTTOption As Short
<System.Runtime.InteropServices.FieldOffset(68)> _
Public dmCollate As Short
<System.Runtime.InteropServices.FieldOffset(72)> _
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCHFORMNAME)> _
Public dmFormName As String
<System.Runtime.InteropServices.FieldOffset(102)> _
Public dmLogPixels As Int16
<System.Runtime.InteropServices.FieldOffset(104)> _
Public dmBitsPerPel As Int32
<System.Runtime.InteropServices.FieldOffset(108)> _
Public dmPelsWidth As Int32
<System.Runtime.InteropServices.FieldOffset(112)> _
Public dmPelsHeight As Int32
<System.Runtime.InteropServices.FieldOffset(116)> _
Public dmDisplayFlags As Int32
<System.Runtime.InteropServices.FieldOffset(116)> _
Public dmNup As Int32
<System.Runtime.InteropServices.FieldOffset(120)> _
Public dmDisplayFrequency As Int32
End Structure
Class PrinterSettings
Private gPrinter As IntPtr = New System.IntPtr()
Private gPrinterValues As New PRINTER_DEFAULTS()
Private gPInfo As New PRINTER_INFO_2()
Private gDevMode As DEVMODE
Private gPtrDevMode As IntPtr
Private gPtrPrinterInfo As IntPtr
Private gSizeOfDevMode As Integer = 0
Private gLastError As Integer
Private gNBytesNeeded As Integer
Private gNRet As Long
Private gIntError As Integer
Private gNTemporary As Integer
Private gDevModeData As IntPtr
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="DocumentPropertiesA", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function DocumentProperties(ByVal hwnd As IntPtr, ByVal hPrinter As IntPtr, <MarshalAs(UnmanagedType.LPStr)> ByVal pDeviceName As String, ByVal pDevModeOutput As IntPtr, ByVal pDevModeInput As IntPtr, ByVal fMode As Integer) As Integer
End Function
<DllImport("winspool.drv", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared 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
<DllImport("winspool.Drv", EntryPoint:="OpenPrinterA", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function OpenPrinter(<MarshalAs(UnmanagedType.LPStr)> ByVal szPrinter As String, ByRef hPrinter As IntPtr, ByRef pd As PRINTER_DEFAULTS) As Boolean
End Function
<DllImport("winspool.drv", CharSet:=CharSet.Ansi, SetLastError:=True)> _
Private Shared Function SetPrinter(ByVal hPrinter As IntPtr, ByVal Level As Integer, ByVal pPrinter As IntPtr, ByVal Command As Integer) As Boolean
End Function
Private Const DM_DUPLEX As Integer = 4096
''0x1000
Private Const DM_IN_BUFFER As Integer = 8
Private Const DM_OUT_BUFFER As Integer = 2
Private Const PRINTER_ACCESS_ADMINISTER As Integer = 4
''0x4
Private Const STANDARD_RIGHTS_REQUIRED As Integer = 983040
''0xF0000
Private Const PRINTER_ALL_ACCESS As Integer = STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE
Private Const PRINTER_ACCESS_USE As Integer = 8
''0x8
Public Function SetPrinterSettings(ByVal iPrinterName As String, ByVal dm As DEVMODE, Optional ByVal ShowPreferences As Integer = 0) As Integer
gDevMode = dm
Marshal.StructureToPtr(gDevMode, gDevModeData, True)
gPInfo.pDevMode = gDevModeData
gPInfo.pSecurityDescriptor = IntPtr.Zero
''optionally brings up the printer preferences dialog
If ShowPreferences = 1 Then
Dim retval As Integer
retval = DocumentProperties(IntPtr.Zero, gPrinter, iPrinterName, gDevModeData, gPInfo.pDevMode, DM_IN_BUFFER Or DM_OUT_BUFFER Or PRINTER_ACCESS_ADMINISTER)
If retval = DialogResult.Cancel Then Return -1
End If
''update driver dependent part of the DEVMODE
''HERE CRASHES ******************************
Marshal.StructureToPtr(gPInfo, gPtrPrinterInfo, True)
''
gLastError = Marshal.GetLastWin32Error()
gNRet = Convert.ToInt16(SetPrinter(gPrinter, 2, gPtrPrinterInfo, 0))
If gNRet = 0 Then
''Unable to set extern printer settings.
gLastError = Marshal.GetLastWin32Error()
Throw New Win32Exception(gLastError)
End If
If gPrinter <> IntPtr.Zero Then
ClosePrinter(gPrinter)
End If
Return CInt(gNRet)
End Function
Public Function GetPrinterSettings(ByVal PrinterName As String) As DEVMODE
Dim lDevMode As DEVMODE
gPrinterValues.pDatatype = IntPtr.Zero
gPrinterValues.pDevMode = IntPtr.Zero
gPrinterValues.DesiredAccess = PRINTER_ALL_ACCESS
gNRet = Convert.ToInt32(OpenPrinter(PrinterName, gPrinter, gPrinterValues))
If gNRet = 0 Then
gLastError = Marshal.GetLastWin32Error()
Throw New Win32Exception(gLastError)
End If
GetPrinter(gPrinter, 2, IntPtr.Zero, 0, gNBytesNeeded)
If gNBytesNeeded <= 0 Then
Throw New System.Exception("Unable to allocate memory")
Else
'' Allocate enough space for PRINTER_INFO_2...
gPtrPrinterInfo = Marshal.AllocCoTaskMem(gNBytesNeeded)
gPtrPrinterInfo = Marshal.AllocHGlobal(gNBytesNeeded)
''The second GetPrinter fills in all the current settings, so all you
''need to do is modify what youre interested in...
gNRet = Convert.ToInt32(GetPrinter(gPrinter, 2, gPtrPrinterInfo, gNBytesNeeded, gNTemporary))
If gNRet = 0 Then
gLastError = Marshal.GetLastWin32Error()
Throw New Win32Exception(gLastError)
End If
gPInfo = CType(Marshal.PtrToStructure(gPtrPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
Dim lTempBuffer As New IntPtr()
If gPInfo.pDevMode = IntPtr.Zero Then
''if GetPrinter didnt fill in the DEVMODE, try to get it by calling
''DocumentProperties...
Dim ptrZero As IntPtr = IntPtr.Zero
''get the size of the devmode struct
gSizeOfDevMode = DocumentProperties(IntPtr.Zero, gPrinter, PrinterName, ptrZero, ptrZero, 0)
gPtrDevMode = Marshal.AllocCoTaskMem(gSizeOfDevMode)
Dim i As Integer = DocumentProperties(IntPtr.Zero, gPrinter, PrinterName, gPtrDevMode, ptrZero, DM_OUT_BUFFER)
If i < 0 OrElse gPtrDevMode <> IntPtr.Zero Then
''Cannot get the DEVMODE struct.
Throw New System.Exception("Cannot get DEVMODE data")
End If
gPInfo.pDevMode = gPtrDevMode
End If
gIntError = DocumentProperties(IntPtr.Zero, gPrinter, PrinterName, IntPtr.Zero, lTempBuffer, 0)
gDevModeData = Marshal.AllocHGlobal(gIntError)
gIntError = DocumentProperties(IntPtr.Zero, gPrinter, PrinterName, gDevModeData, lTempBuffer, 2)
lDevMode = CType(Marshal.PtrToStructure(gDevModeData, GetType(DEVMODE)), DEVMODE)
If gNRet = 0 OrElse gPrinter = IntPtr.Zero Then
gLastError = Marshal.GetLastWin32Error()
Throw New Win32Exception(gLastError)
End If
Return lDevMode
End If
End Function
End Class
用法:
Dim defaultPrinterName As String = getDefaultPrinter()
Dim dm As DEVMODE
Dim lPrinterpreferences As PrinterSettings = New PrinterSettings()
dm = lPrinterpreferences.GetPrinterSettings(defaultPrinterName)
dm.dmCopies = 4
lPrinterpreferences.SetPrinterSettings(defaultPrinterName, dm, 1)
编辑: 并且可能在调用SetPrinter API时仍然存在最后一个错误。
gNRet = Convert.ToInt16(SetPrinter(gPrinter, 2, gPtrPrinterInfo, 0))
抛出错误:“打印机驱动程序未知”, 但
gNRet = Convert.ToInt16(SetPrinter(gPrinter, 0, gPtrPrinterInfo, 3))
工作没有错误但不可靠。
如何摆脱这最后一个错误?
答案 0 :(得分:2)
以下是一些提示:
仅供参考我在Win7 x64上使用C#工作的GetPrinterSettings函数没有对代码进行任何逻辑更改。 OpenPrinter没有崩溃,但在更改其函数签名之前返回错误nr 87:gPrinter必须成为out参数。我认为你应该能够做相同的检查,并使其在VB中工作。
这是类,虽然我相信你最好使用pinvoke.net的结构和函数签名,而不是试图将它转换回VB。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace PrintersettingsTest
{
[StructLayout(LayoutKind.Sequential)]
struct PRINTER_DEFAULTS
{
public IntPtr pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPTStr)]
public string pServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pPrinterName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pShareName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pPortName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pDriverName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pComment;
[MarshalAs(UnmanagedType.LPTStr)]
public string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPTStr)]
public string pSepFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string pPrintProcessor;
[MarshalAs(UnmanagedType.LPTStr)]
public string pDatatype;
[MarshalAs(UnmanagedType.LPTStr)]
public string pParameters;
public IntPtr pSecurityDescriptor;
public uint Attributes;
public uint Priority;
public uint DefaultPriority;
public uint StartTime;
public uint UntilTime;
public uint Status;
public uint cJobs;
public uint AveragePPM;
}
struct POINTL
{
public Int32 x;
public Int32 y;
}
[Flags()]
enum DM : int
{
Orientation = 0x1,
PaperSize = 0x2,
PaperLength = 0x4,
PaperWidth = 0x8,
Scale = 0x10,
Position = 0x20,
NUP = 0x40,
DisplayOrientation = 0x80,
Copies = 0x100,
DefaultSource = 0x200,
PrintQuality = 0x400,
Color = 0x800,
Duplex = 0x1000,
YResolution = 0x2000,
TTOption = 0x4000,
Collate = 0x8000,
FormName = 0x10000,
LogPixels = 0x20000,
BitsPerPixel = 0x40000,
PelsWidth = 0x80000,
PelsHeight = 0x100000,
DisplayFlags = 0x200000,
DisplayFrequency = 0x400000,
ICMMethod = 0x800000,
ICMIntent = 0x1000000,
MediaType = 0x2000000,
DitherType = 0x4000000,
PanningWidth = 0x8000000,
PanningHeight = 0x10000000,
DisplayFixedOutput = 0x20000000
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
struct DEVMODE
{
public const int CCHDEVICENAME = 32;
public const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
[System.Runtime.InteropServices.FieldOffset(0)]
public string dmDeviceName;
[System.Runtime.InteropServices.FieldOffset(32)]
public Int16 dmSpecVersion;
[System.Runtime.InteropServices.FieldOffset(34)]
public Int16 dmDriverVersion;
[System.Runtime.InteropServices.FieldOffset(36)]
public Int16 dmSize;
[System.Runtime.InteropServices.FieldOffset(38)]
public Int16 dmDriverExtra;
[System.Runtime.InteropServices.FieldOffset(40)]
public DM dmFields;
[System.Runtime.InteropServices.FieldOffset(44)]
Int16 dmOrientation;
[System.Runtime.InteropServices.FieldOffset(46)]
Int16 dmPaperSize;
[System.Runtime.InteropServices.FieldOffset(48)]
Int16 dmPaperLength;
[System.Runtime.InteropServices.FieldOffset(50)]
Int16 dmPaperWidth;
[System.Runtime.InteropServices.FieldOffset(52)]
Int16 dmScale;
[System.Runtime.InteropServices.FieldOffset(54)]
Int16 dmCopies;
[System.Runtime.InteropServices.FieldOffset(56)]
Int16 dmDefaultSource;
[System.Runtime.InteropServices.FieldOffset(58)]
Int16 dmPrintQuality;
[System.Runtime.InteropServices.FieldOffset(44)]
public POINTL dmPosition;
[System.Runtime.InteropServices.FieldOffset(52)]
public Int32 dmDisplayOrientation;
[System.Runtime.InteropServices.FieldOffset(56)]
public Int32 dmDisplayFixedOutput;
[System.Runtime.InteropServices.FieldOffset(60)]
public short dmColor;
[System.Runtime.InteropServices.FieldOffset(62)]
public short dmDuplex;
[System.Runtime.InteropServices.FieldOffset(64)]
public short dmYResolution;
[System.Runtime.InteropServices.FieldOffset(66)]
public short dmTTOption;
[System.Runtime.InteropServices.FieldOffset(68)]
public short dmCollate;
[System.Runtime.InteropServices.FieldOffset(72)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
[System.Runtime.InteropServices.FieldOffset(102)]
public Int16 dmLogPixels;
[System.Runtime.InteropServices.FieldOffset(104)]
public Int32 dmBitsPerPel;
[System.Runtime.InteropServices.FieldOffset(108)]
public Int32 dmPelsWidth;
[System.Runtime.InteropServices.FieldOffset(112)]
public Int32 dmPelsHeight;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmDisplayFlags;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmNup;
[System.Runtime.InteropServices.FieldOffset(120)]
public Int32 dmDisplayFrequency;
}
class PrinterSettings
{
private IntPtr gPrinter = new System.IntPtr();
private PRINTER_DEFAULTS gPrinterValues = new PRINTER_DEFAULTS();
private PRINTER_INFO_2 gPInfo = new PRINTER_INFO_2();
private DEVMODE gDevMode;
private IntPtr gPtrDevMode;
private IntPtr gPtrPrinterInfo;
private int gSizeOfDevMode = 0;
private int gLastError;
private int gNBytesNeeded;
private long gNRet;
private int gIntError;
private int gNTemporary;
private IntPtr gDevModeData;
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private 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 pDeviceName,
IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA",
SetLastError = true, CharSet = CharSet.Ansi,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level,
IntPtr pPrinter, int Command);
private const int DM_DUPLEX = 4096; //0x1000
private const int DM_IN_BUFFER = 8;
private const int DM_OUT_BUFFER = 2;
private const int PRINTER_ACCESS_ADMINISTER = 4; //0x4
private const int STANDARD_RIGHTS_REQUIRED = 983040; //0xF0000
private const int PRINTER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
private const int PRINTER_ACCESS_USE = 8; //0x8
public bool ChangePrinterSetting(string iPrinterName)
{
gDevMode = this.GetPrinterSettings(iPrinterName);
Marshal.StructureToPtr(gDevMode, gDevModeData, true);
gPInfo.pDevMode = gDevModeData;
gPInfo.pSecurityDescriptor = IntPtr.Zero;
//bring up the printer preferences dialog
DocumentProperties(IntPtr.Zero, gPrinter, iPrinterName, gDevModeData
, gPInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | PRINTER_ACCESS_ADMINISTER);
//update driver dependent part of the DEVMODE
Marshal.StructureToPtr(gPInfo, gPtrPrinterInfo, true);
gLastError = Marshal.GetLastWin32Error();
gNRet = Convert.ToInt16(SetPrinter(gPrinter, 2, gPtrPrinterInfo, 0));
if (gNRet == 0)
{
//Unable to set extern printer settings.
gLastError = Marshal.GetLastWin32Error();
throw new Win32Exception(gLastError);
}
if (gPrinter != IntPtr.Zero)
{
ClosePrinter(gPrinter);
}
return Convert.ToBoolean(gNRet);
}
public DEVMODE GetPrinterSettings(string PrinterName)
{
DEVMODE lDevMode;
gPrinterValues.pDatatype = IntPtr.Zero;
gPrinterValues.pDevMode = IntPtr.Zero;
gPrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
// HERE CRASHES
gNRet = Convert.ToInt32(OpenPrinter(PrinterName, out gPrinter, ref gPrinterValues));
if (gNRet == 0)
{
gLastError = Marshal.GetLastWin32Error();
throw new Win32Exception(gLastError);
}
GetPrinter(gPrinter, 2, IntPtr.Zero, 0, out gNBytesNeeded);
if (gNBytesNeeded <= 0)
throw new System.Exception("Unable to allocate memory");
else
{
// Allocate enough space for PRINTER_INFO_2...
gPtrPrinterInfo = Marshal.AllocCoTaskMem(gNBytesNeeded);
gPtrPrinterInfo = Marshal.AllocHGlobal(gNBytesNeeded);
//The second GetPrinter fills in all the current settings, so all you
//need to do is modify what youre interested in...
gNRet = Convert.ToInt32(GetPrinter(gPrinter, 2,
gPtrPrinterInfo, gNBytesNeeded, out gNTemporary));
if (gNRet == 0)
{
gLastError = Marshal.GetLastWin32Error();
throw new Win32Exception(gLastError);
}
gPInfo = (PRINTER_INFO_2)Marshal.PtrToStructure(gPtrPrinterInfo, typeof(PRINTER_INFO_2));
IntPtr lTempBuffer = new IntPtr();
if (gPInfo.pDevMode == IntPtr.Zero)
{
//if GetPrinter didnt fill in the DEVMODE, try to get it by calling
//DocumentProperties...
IntPtr ptrZero = IntPtr.Zero;
//get the size of the devmode struct
gSizeOfDevMode = DocumentProperties(IntPtr.Zero, gPrinter,
PrinterName, ptrZero, ptrZero, 0);
gPtrDevMode = Marshal.AllocCoTaskMem(gSizeOfDevMode);
int i = DocumentProperties(IntPtr.Zero, gPrinter, PrinterName, gPtrDevMode,
ptrZero, DM_OUT_BUFFER);
if (i < 0 || gPtrDevMode != IntPtr.Zero)
{
//Cannot get the DEVMODE struct.
throw new System.Exception("Cannot get DEVMODE data");
}
gPInfo.pDevMode = gPtrDevMode;
}
gIntError = DocumentProperties(IntPtr.Zero, gPrinter,
PrinterName, IntPtr.Zero, lTempBuffer, 0);
gDevModeData = Marshal.AllocHGlobal(gIntError);
gIntError = DocumentProperties(IntPtr.Zero, gPrinter,
PrinterName, gDevModeData, lTempBuffer, 2);
lDevMode = (DEVMODE)Marshal.PtrToStructure(gDevModeData, typeof(DEVMODE));
if (gNRet == 0 || gPrinter == IntPtr.Zero)
{
gLastError = Marshal.GetLastWin32Error();
throw new Win32Exception(gLastError);
}
return lDevMode;
}
}
}
}
答案 1 :(得分:2)
Marshal.StructureToPtr(gPInfo, gPtrPrinterInfo, True)
这将终止程序,异常代码为0xc0000374,您可以在“输出”窗口中看到它。这是STATUS_HEAP_CORRUPTION,“堆已损坏”。
这是因为最后一个参数,你错误地传递了True。这指示该方法释放旧结构数据的内存。这不正确,GetPrinter()winapi函数不希望你释放字符串指针。你可以在旧版本的Windows上使用它,比如XP。但是从Vista开始,包括Windows 7,堆管理器不再忽略错误的指针值。
将第3个参数更改为False以解决您的问题。