从 Windows XP 32 位开始,在 Windows 7 64 位中使用 Winspool.drv 进行的更改

发布于 2024-10-15 03:23:34 字数 3422 浏览 6 评论 0原文

我有一些 C# 代码 (VS2010;fx2),用于执行打印机功能。这段代码在Windows XP环境下运行良好。更改为 Windows 7,它不再正常工作。

第一个不同的行为是 GetPrinterNames() 方法现在仅返回本地打印机。正如您所看到的,这些标志也设置为包括网络打印机。我尝试过不同的标志,但没有成功。

我应该在 Windows 7 / 64 位版本中引用不同的库吗?

打印机助手类的代码如下所示:

internal class Printers
{

    ...

    [DllImport("winspool.drv", SetLastError = true)]
    static extern bool EnumPrintersW(Int32 flags, [MarshalAs(UnmanagedType.LPTStr)] string printerName,
         Int32 level, IntPtr buffer, Int32 bufferSize, out Int32 requiredBufferSize,
         out Int32 numPrintersReturned);

    [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned);

    ...

    ...

    public static string[] GetPrinterNames()
    {
        List<string> returnVal = new List<string>();
        foreach(PRINTER_INFO_2 info in enumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_NETWORK))
        {
            returnVal.Add(info.pPrinterName);
        }
        return returnVal.ToArray();
    }

...

    private static PRINTER_INFO_2[] enumPrinters(PrinterEnumFlags Flags)
    {
        uint cbNeeded = 0;
        uint cReturned = 0;
        if (EnumPrinters(Flags, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned))
        {
            return null;
        }
        int lastWin32Error = Marshal.GetLastWin32Error();
        if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)
        {
            IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
            if (EnumPrinters(Flags, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned))
            {
                PRINTER_INFO_2[] printerInfo2 = new PRINTER_INFO_2[cReturned];
                int offset = pAddr.ToInt32();
                Type type = typeof(PRINTER_INFO_2);
                int increment = Marshal.SizeOf(type);
                for (int i = 0; i < cReturned; i++)
                {
                    printerInfo2[i] = (PRINTER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type);
                    offset += increment;
                }
                Marshal.FreeHGlobal(pAddr);
                return printerInfo2;
            }
            lastWin32Error = Marshal.GetLastWin32Error();
        }
        throw new System.ComponentModel.Win32Exception(lastWin32Error);
    }

    ...

    [FlagsAttribute]
    enum PrinterEnumFlags
    {
        PRINTER_ENUM_DEFAULT = 0x00000001,
        PRINTER_ENUM_LOCAL = 0x00000002,
        PRINTER_ENUM_CONNECTIONS = 0x00000004,
        PRINTER_ENUM_FAVORITE = 0x00000004,
        PRINTER_ENUM_NAME = 0x00000008,
        PRINTER_ENUM_REMOTE = 0x00000010,
        PRINTER_ENUM_SHARED = 0x00000020,
        PRINTER_ENUM_NETWORK = 0x00000040,
        PRINTER_ENUM_EXPAND = 0x00004000,
        PRINTER_ENUM_CONTAINER = 0x00008000,
        PRINTER_ENUM_ICONMASK = 0x00ff0000,
        PRINTER_ENUM_ICON1 = 0x00010000,
        PRINTER_ENUM_ICON2 = 0x00020000,
        PRINTER_ENUM_ICON3 = 0x00040000,
        PRINTER_ENUM_ICON4 = 0x00080000,
        PRINTER_ENUM_ICON5 = 0x00100000,
        PRINTER_ENUM_ICON6 = 0x00200000,
        PRINTER_ENUM_ICON7 = 0x00400000,
        PRINTER_ENUM_ICON8 = 0x00800000,
        PRINTER_ENUM_HIDE = 0x01000000
    }

编辑:编辑代码以减小大小(删除不太感兴趣的区域)。

I have some C# code (VS2010;fx2) which is used to carry out printer functions. This code works fine in Windows XP environment. Changing to Windows 7, it no longer works correctly.

The first different behaviour is that the GetPrinterNames() method now only returns local printers. As you can see, the flags are set to include NETWORK printers also. I've tried different flags, but with no success.

Is there a different library I should be referencing in Windows 7 / 64 bit version?

Printer helper class with code shown below:

internal class Printers
{

    ...

    [DllImport("winspool.drv", SetLastError = true)]
    static extern bool EnumPrintersW(Int32 flags, [MarshalAs(UnmanagedType.LPTStr)] string printerName,
         Int32 level, IntPtr buffer, Int32 bufferSize, out Int32 requiredBufferSize,
         out Int32 numPrintersReturned);

    [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned);

    ...

    ...

    public static string[] GetPrinterNames()
    {
        List<string> returnVal = new List<string>();
        foreach(PRINTER_INFO_2 info in enumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_NETWORK))
        {
            returnVal.Add(info.pPrinterName);
        }
        return returnVal.ToArray();
    }

...

    private static PRINTER_INFO_2[] enumPrinters(PrinterEnumFlags Flags)
    {
        uint cbNeeded = 0;
        uint cReturned = 0;
        if (EnumPrinters(Flags, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned))
        {
            return null;
        }
        int lastWin32Error = Marshal.GetLastWin32Error();
        if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)
        {
            IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
            if (EnumPrinters(Flags, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned))
            {
                PRINTER_INFO_2[] printerInfo2 = new PRINTER_INFO_2[cReturned];
                int offset = pAddr.ToInt32();
                Type type = typeof(PRINTER_INFO_2);
                int increment = Marshal.SizeOf(type);
                for (int i = 0; i < cReturned; i++)
                {
                    printerInfo2[i] = (PRINTER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type);
                    offset += increment;
                }
                Marshal.FreeHGlobal(pAddr);
                return printerInfo2;
            }
            lastWin32Error = Marshal.GetLastWin32Error();
        }
        throw new System.ComponentModel.Win32Exception(lastWin32Error);
    }

    ...

    [FlagsAttribute]
    enum PrinterEnumFlags
    {
        PRINTER_ENUM_DEFAULT = 0x00000001,
        PRINTER_ENUM_LOCAL = 0x00000002,
        PRINTER_ENUM_CONNECTIONS = 0x00000004,
        PRINTER_ENUM_FAVORITE = 0x00000004,
        PRINTER_ENUM_NAME = 0x00000008,
        PRINTER_ENUM_REMOTE = 0x00000010,
        PRINTER_ENUM_SHARED = 0x00000020,
        PRINTER_ENUM_NETWORK = 0x00000040,
        PRINTER_ENUM_EXPAND = 0x00004000,
        PRINTER_ENUM_CONTAINER = 0x00008000,
        PRINTER_ENUM_ICONMASK = 0x00ff0000,
        PRINTER_ENUM_ICON1 = 0x00010000,
        PRINTER_ENUM_ICON2 = 0x00020000,
        PRINTER_ENUM_ICON3 = 0x00040000,
        PRINTER_ENUM_ICON4 = 0x00080000,
        PRINTER_ENUM_ICON5 = 0x00100000,
        PRINTER_ENUM_ICON6 = 0x00200000,
        PRINTER_ENUM_ICON7 = 0x00400000,
        PRINTER_ENUM_ICON8 = 0x00800000,
        PRINTER_ENUM_HIDE = 0x01000000
    }

EDIT: Code edited to reduce size (areas of less interest removed).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

诺曦 2024-10-22 03:23:34

在 64 位 Windows 机器上,异常是 OverflowException (算术运算导致溢出。)由于将指针转换为 32 位整数而不是 64 位整数而引起。

int offset = pAddr.ToInt32();

修复它,在 Windows 10 x64 上检查

long offset = pAddr.ToInt64();

使用完整的工作代码

public static string[] GetPrinterNames()
{
    var results = new List<string>();
    foreach (PRINTER_INFO_2 info in enumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_NETWORK))
        results.Add(info.pPrinterName);
    return results.ToArray();
}

private static PRINTER_INFO_2[] enumPrinters(PrinterEnumFlags Flags)
{
    uint cbNeeded = 0;
    uint cReturned = 0;
    if (EnumPrinters(Flags, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned))
    {
        return null;
    }
    int lastWin32Error = Marshal.GetLastWin32Error();
    if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)
    {
        IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
        if (EnumPrinters(Flags, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned))
        {
            PRINTER_INFO_2[] printerInfo2 = new PRINTER_INFO_2[cReturned];
            long offset = pAddr.ToInt64();
            Type type = typeof(PRINTER_INFO_2);
            int increment = Marshal.SizeOf(type);
            for (int i = 0; i < cReturned; i++)
            {
                printerInfo2[i] = (PRINTER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type);
                offset += increment;
            }
            Marshal.FreeHGlobal(pAddr);
            return printerInfo2;
        }
        lastWin32Error = Marshal.GetLastWin32Error();
    }
    throw new System.ComponentModel.Win32Exception(lastWin32Error);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal 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;
}

const int ERROR_INSUFFICIENT_BUFFER = 122;

[FlagsAttribute]
enum PrinterEnumFlags
{
    PRINTER_ENUM_DEFAULT = 0x00000001,
    PRINTER_ENUM_LOCAL = 0x00000002,
    PRINTER_ENUM_CONNECTIONS = 0x00000004,
    PRINTER_ENUM_FAVORITE = 0x00000004,
    PRINTER_ENUM_NAME = 0x00000008,
    PRINTER_ENUM_REMOTE = 0x00000010,
    PRINTER_ENUM_SHARED = 0x00000020,
    PRINTER_ENUM_NETWORK = 0x00000040,
    PRINTER_ENUM_EXPAND = 0x00004000,
    PRINTER_ENUM_CONTAINER = 0x00008000,
    PRINTER_ENUM_ICONMASK = 0x00ff0000,
    PRINTER_ENUM_ICON1 = 0x00010000,
    PRINTER_ENUM_ICON2 = 0x00020000,
    PRINTER_ENUM_ICON3 = 0x00040000,
    PRINTER_ENUM_ICON4 = 0x00080000,
    PRINTER_ENUM_ICON5 = 0x00100000,
    PRINTER_ENUM_ICON6 = 0x00200000,
    PRINTER_ENUM_ICON7 = 0x00400000,
    PRINTER_ENUM_ICON8 = 0x00800000,
    PRINTER_ENUM_HIDE = 0x01000000
}

[DllImport("winspool.drv", SetLastError = true)]
static extern bool EnumPrintersW(Int32 flags, [MarshalAs(UnmanagedType.LPTStr)] string printerName,
                 Int32 level, IntPtr buffer, Int32 bufferSize, out Int32 requiredBufferSize,
                 out Int32 numPrintersReturned);

[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned);

On 64 bit windows machine is the exception an OverflowException (Arithmetic operation resulted in an overflow.) Caused by converting a pointer in a 32 bits integer instead of a 64 bits integer.

int offset = pAddr.ToInt32();

Fix it with

long offset = pAddr.ToInt64();

The complete working code, checked on Windows 10 x64

public static string[] GetPrinterNames()
{
    var results = new List<string>();
    foreach (PRINTER_INFO_2 info in enumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL | PrinterEnumFlags.PRINTER_ENUM_NETWORK))
        results.Add(info.pPrinterName);
    return results.ToArray();
}

private static PRINTER_INFO_2[] enumPrinters(PrinterEnumFlags Flags)
{
    uint cbNeeded = 0;
    uint cReturned = 0;
    if (EnumPrinters(Flags, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned))
    {
        return null;
    }
    int lastWin32Error = Marshal.GetLastWin32Error();
    if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)
    {
        IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
        if (EnumPrinters(Flags, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned))
        {
            PRINTER_INFO_2[] printerInfo2 = new PRINTER_INFO_2[cReturned];
            long offset = pAddr.ToInt64();
            Type type = typeof(PRINTER_INFO_2);
            int increment = Marshal.SizeOf(type);
            for (int i = 0; i < cReturned; i++)
            {
                printerInfo2[i] = (PRINTER_INFO_2)Marshal.PtrToStructure(new IntPtr(offset), type);
                offset += increment;
            }
            Marshal.FreeHGlobal(pAddr);
            return printerInfo2;
        }
        lastWin32Error = Marshal.GetLastWin32Error();
    }
    throw new System.ComponentModel.Win32Exception(lastWin32Error);
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal 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;
}

const int ERROR_INSUFFICIENT_BUFFER = 122;

[FlagsAttribute]
enum PrinterEnumFlags
{
    PRINTER_ENUM_DEFAULT = 0x00000001,
    PRINTER_ENUM_LOCAL = 0x00000002,
    PRINTER_ENUM_CONNECTIONS = 0x00000004,
    PRINTER_ENUM_FAVORITE = 0x00000004,
    PRINTER_ENUM_NAME = 0x00000008,
    PRINTER_ENUM_REMOTE = 0x00000010,
    PRINTER_ENUM_SHARED = 0x00000020,
    PRINTER_ENUM_NETWORK = 0x00000040,
    PRINTER_ENUM_EXPAND = 0x00004000,
    PRINTER_ENUM_CONTAINER = 0x00008000,
    PRINTER_ENUM_ICONMASK = 0x00ff0000,
    PRINTER_ENUM_ICON1 = 0x00010000,
    PRINTER_ENUM_ICON2 = 0x00020000,
    PRINTER_ENUM_ICON3 = 0x00040000,
    PRINTER_ENUM_ICON4 = 0x00080000,
    PRINTER_ENUM_ICON5 = 0x00100000,
    PRINTER_ENUM_ICON6 = 0x00200000,
    PRINTER_ENUM_ICON7 = 0x00400000,
    PRINTER_ENUM_ICON8 = 0x00800000,
    PRINTER_ENUM_HIDE = 0x01000000
}

[DllImport("winspool.drv", SetLastError = true)]
static extern bool EnumPrintersW(Int32 flags, [MarshalAs(UnmanagedType.LPTStr)] string printerName,
                 Int32 level, IntPtr buffer, Int32 bufferSize, out Int32 requiredBufferSize,
                 out Int32 numPrintersReturned);

[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level, IntPtr pPrinterEnum, uint cbBuf, ref uint pcbNeeded, ref uint pcReturned);
初懵 2024-10-22 03:23:34

根据 EnumPrinters 的 msdn 注释,只有当

EnumPrinters 中的第三个参数为 1 时,您的代码才有效。...

PRINTER_ENUM_NETWORK
该函数枚举计算机域中的网络打印机。仅当 Level 为 1 时该值才有效。

According to msdn notes for EnumPrinters, your code only works if the 3rd paramater is 1

from EnumPrinters....

PRINTER_ENUM_NETWORK
The function enumerates network printers in the computer's domain. This value is valid only if Level is 1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文