0

XPS プリンターのポートを設定する必要があります。Stackoverflow でいくつかの例を見つけましたが、うまくいきません。ここにコードがあります(たくさんのゴミ):

    LPTSTR pDeviceName = _T("Microsoft XPS Document Writer");
    HANDLE phPrinter(nullptr);
    PRINTER_DEFAULTS defaults;
    defaults.DesiredAccess = PRINTER_ACCESS_USE;
    defaults.pDatatype = 0;

    PORT_INFO_3 pInfo3;;

    DWORD needed;
    DWORD XcvResult;

    DWORD err = OpenPrinter(pDeviceName,&phPrinter,NULL);
    //const BYTE* portValue = reinterpret_cast<const BYTE*>("TestPort");
    PBYTE port = (PBYTE)_T("Test1");

    if(err) {
        int res =    XcvData(phPrinter,_T("AddPort"),port,sizeof(port),NULL,0,&needed,&XcvResult);
                }
    else {
        AfxMessageBox(_T("ERROR."),MB_OK);
    }
    ClosePrinter(phPrinter);

このコードが 1 回だけ (XcvData func の最初の開始) しか機能しなかったのが最も面白いことです!

同じ動作の別の例:

 BOOL AddPortX(void)
    {
        DWORD cbneed,cbstate;
        PBYTE pOutputData;
        HANDLE hXcv = INVALID_HANDLE_VALUE;
        PRINTER_DEFAULTS Defaults = { NULL,NULL,SERVER_ACCESS_ADMINISTER };     

        WCHAR pszPortName[]=L"UTReportPDFPort:"; 
        pOutputData=(PBYTE)malloc(MAX_PATH);

        if(!OpenPrinter(_T("Microsoft XPS Document Writer"),&hXcv,NULL ))
        {
            LPVOID lpMsgBuf; 
            GetLastError();
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
            ::MessageBox(NULL,(LPCTSTR)lpMsgBuf,_T("ERROR"),MB_OK|MB_ICONINFORMATION);
            free(pOutputData);
            LocalFree( lpMsgBuf );
            return FALSE;

        }
// False
        if(!XcvData(hXcv,L"AddPort",(PBYTE)pszPortName,sizeof(pszPortName),(PBYTE)pOutputData,MAX_PATH,&cbneed,&cbstate))
        {
            LPVOID lpMsgBuf; 
            SetLastError(cbstate);
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL ); 
            ::MessageBox(NULL,(LPCTSTR)lpMsgBuf,_T("ERROR"),MB_OK|MB_ICONINFORMATION);       
            LocalFree( lpMsgBuf ); 
            free(pOutputData);
        }

        free(pOutputData);
        ClosePrinter(hXcv);

        return TRUE;

    }

では、どのように追加プリンターポートを設定し、追加後に自動的に選択するのでしょうか? たぶん、誰かが一度だけ機能する理由を知っていますか? つまり、XcvData 関数です。次回はすべてエラー コード 6 が返されます。.NET ソリューションも適切です。

4

1 に答える 1

1
  public static class Winspool
{
    [StructLayout(LayoutKind.Sequential)]
    private class PRINTER_DEFAULTS
    {
        public string pDatatype;
        public IntPtr pDevMode;
        public int DesiredAccess;
    }

    [DllImport("winspool.drv", EntryPoint = "XcvDataW", SetLastError = true)]
    private static extern bool XcvData(
        IntPtr hXcv,
        [MarshalAs(UnmanagedType.LPWStr)] string pszDataName,
        IntPtr pInputData,
        uint cbInputData,
        IntPtr pOutputData,
        uint cbOutputData,
        out uint pcbOutputNeeded,
        out uint pwdStatus);

    [DllImport("winspool.drv", EntryPoint = "OpenPrinterA", SetLastError = true)]
    private static extern int OpenPrinter(
        string pPrinterName,
        ref IntPtr phPrinter,
        PRINTER_DEFAULTS pDefault);

    [DllImport("winspool.drv", EntryPoint = "ClosePrinter")]
    private static extern int ClosePrinter(IntPtr hPrinter);

    public static int AddLocalPort(string portName)
    {
        PRINTER_DEFAULTS def = new PRINTER_DEFAULTS();

        def.pDatatype = null;
        def.pDevMode = IntPtr.Zero;
        def.DesiredAccess = 1; //Server Access Administer

        IntPtr hPrinter = IntPtr.Zero;

        int n = OpenPrinter(",XcvMonitor Local Port", ref hPrinter, def);
        if (n == 0)
            return Marshal.GetLastWin32Error();

        if (!portName.EndsWith("\0"))
            portName += "\0"; // Must be a null terminated string

        // Must get the size in bytes. Rememeber .NET strings are formed by 2-byte characters
        uint size = (uint)(portName.Length * 2);

        // Alloc memory in HGlobal to set the portName
        IntPtr portPtr = Marshal.AllocHGlobal((int)size);
        Marshal.Copy(portName.ToCharArray(), 0, portPtr, portName.Length);

        uint needed; // Not that needed in fact...
        uint xcvResult; // Will receive de result here

        XcvData(hPrinter, "AddPort", portPtr, size, IntPtr.Zero, 0, out needed, out xcvResult);

        ClosePrinter(hPrinter);
        Marshal.FreeHGlobal(portPtr);

        return (int)xcvResult;
    }
}

リソースは CodeProject からのものです

OpenPrinter() の最初のパラメーターは、XcvMonitor Local Port である必要があります。.NET 管理オブジェクトを使用してポートを選択できるのはデフォルトです。

于 2013-02-19T17:05:43.993 に答える