在没有 prnadmin.dll 的情况下使用 powershell 安装 'printer forms'?

Installing 'printer forms' using powershell without prnadmin.dll?

由于来自 Microsoft 的最新安全更新已使 Jet OLEDB Provider 无法使用,我不得不重写几个较旧的 VBScript。

有没有更好的方法在 Windows Server 2008 R2 和 2012 R2 上安装打印机表单,然后通过 regsvr32/COM/VBscript 调用过时的 prnadmin.dll

prnadmin.dll 最初是在 Windows Server 2000 资源工具包中引入的,我想将整个脚本迁移到 PowerShell。

不幸的是,我在模块 PrintManagement 中找不到任何有用的 PowerShell cmdlet。那么如何使用 PSH 将自定义表单添加到打印机服务器?

添加系统表单定义的编程方式是调用AddForm. There is not a good wrapper for this call that I am aware of, but P/Invoking to AddForm works. I wrote a quick wrapper and posted it on GitHub

使用包装器的示例:

Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS C:\Drop> Import-Module .\PowershellPrinterFormsModule.dll
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 1' -Units Inches -Size '4,5'
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 2' -Units Inches -Size '4,5' -Margin '0.25,0.5'
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 3' -Units Millimeters -Size '80,50' -Margin '10,10,0,0'

AddForm 的实际 P/Invoke 调用:

SafePrinterHandle hServer;
if (!OpenPrinter(null, out hServer, IntPtr.Zero))
{
    throw new Win32Exception();
}
using (hServer)
{
    var form = new FORM_INFO_1()
    {
        Flags = 0,
        Name = this.Name,
        Size = (SIZEL)pageSize,
        ImageableArea = (RECTL)imageableArea
    };

    if (!AddForm(hServer, 1, ref form))
    {
        throw new Win32Exception();
    }
}

internal static class NativeMethods
{
    #region Constants

    internal const int ERROR_INSUFFICIENT_BUFFER = 0x7A;

    #endregion

    #region winspool.drv

    private const string Winspool = "winspool.drv";

    [DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool OpenPrinter(string szPrinter, out SafePrinterHandle hPrinter, IntPtr pd);

    public static SafePrinterHandle OpenPrinter(string szPrinter)
    {
        SafePrinterHandle hServer;
        if (!OpenPrinter(null, out hServer, IntPtr.Zero))
        {
            throw new Win32Exception();
        }
        return hServer;
    }

    [DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool ClosePrinter(IntPtr hPrinter);

    [DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool EnumForms(SafePrinterHandle hPrinter, int level, IntPtr pBuf, int cbBuf, out int pcbNeeded, out int pcReturned);

    [DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool AddForm(SafePrinterHandle hPrinter, int level, [In] ref FORM_INFO_1 form);

    [DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern bool DeleteForm(SafePrinterHandle hPrinter, string formName);

    #endregion

    #region Structs

    [StructLayout(LayoutKind.Sequential)]
    internal struct FORM_INFO_1
    {
        public int Flags;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string Name;
        public SIZEL Size;
        public RECTL ImageableArea;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SIZEL
    {
        public int cx;
        public int cy;

        public static explicit operator SIZEL(Size r)
            => new SIZEL { cx = (int)r.Width, cy = (int)r.Height };
        public static explicit operator Size(SIZEL r)
            => new Size(r.cx, r.cy);
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RECTL
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public static explicit operator RECTL(Rect r)
            => new RECTL { left = (int)r.Left, top = (int)r.Top, right = (int)r.Right, bottom = (int)r.Bottom };
        public static explicit operator Rect(RECTL r)
            => new Rect(new Point(r.left, r.top), new Point(r.right, r.bottom));
    }

    #endregion
}

internal sealed class SafePrinterHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    public SafePrinterHandle()
        : base(true)
    {
    }

    protected override bool ReleaseHandle()
    {
        return NativeMethods.ClosePrinter(handle);
    }
}