2013-02-14 187 views
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); 

最有趣的事情,這段代碼的工作只是一次(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解決方案也會很好。

+0

錯誤代碼6是'無效句柄值'。不過,您不會顯示收到錯誤代碼6的位置。你永遠不會檢查'XcvData()'的返回值,它是一個'BOOL',以查明它是否失敗;你只是在調用'XcvData()'後調用'GetLastError()'來查看它是否失敗。 – 2013-02-14 23:17:48

+0

這是一個測試代碼。 XcvData是錯誤的。 GetLastError返回6. – 2013-02-14 23:21:12

+0

沒有任何謎題。 XcvData在我用過的任何代碼示例中都不起作用。不,它可以工作,但只是第一次在我使用的任何代碼示例中。謝謝。 – 2013-02-14 23:28:03

回答

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; 
    } 
} 

Resource is from CodeProject

在OpenPrinter的第一個參數()必須是 - XcvMonitor本地端口。 比我們可以使用.NET管理對象選擇端口是默認的。