2013-02-14 144 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管理对象选择端口是默认的。