0

我在 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)) 

工作没有错误但不可靠。

如何摆脱最后一个错误?

4

2 回答 2

2

这里有一些提示:

  • 检查并查看您的结构和 dllimport 函数是否定义正确。在 pinvoke.net 上,您可以找到经过测试的签名(例如 DocumentProperties 函数)http://www.pinvoke.net/default.aspx/winspool/DocumentProperties.html
  • 如果您运行的是 x64 系统,请注意 pinvoke.net 上的评论。在 x64 系统上需要更改某些函数/结构。
  • 您是以管理员还是普通用户的身份运行您的程序/视觉工作室?它可能会有所作为。

仅供参考,我在 Win7 x64 上的 C# 中获得了 GetPrinterSettings 函数,无需对代码进行任何逻辑更改。OpenPrinter 没有崩溃,但在我更改其函数签名之前返回了错误 nr 87:gPrinter 必须成为一个输出参数。我认为您应该能够进行相同的检查并使其在 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;
            }
        }
    }

}
于 2013-08-28T23:54:55.037 回答
2
  Marshal.StructureToPtr(gPInfo, gPtrPrinterInfo, True)

这将以异常代码 0xc0000374 终止程序,您可以在“输出”窗口中看到它。那是 STATUS_HEAP_CORRUPTION,“堆已损坏”。

发生这种情况是因为最后一个参数,您错误地传递了 True。这指示方法释放旧结构数据的内存。这是不正确的,GetPrinter() winapi 函数不希望您释放字符串指针。您在旧版本的 Windows(如 XP)上摆脱了这种情况。但是从 Vista 开始,包括 Windows 7,堆管理器不再忽略错误的指针值。

将第三个参数更改为 False 以解决您的问题。

于 2013-08-30T00:41:27.567 回答