2016-09-26 73 views
-1

我會問和回答我自己的問題。我本來以爲需要創建一個空打印機並不是一件難得的事情,但是我花了太多時間在搜索工作的解決方案之前使用google搜索和拼湊一些小部分。我發現很多關於通過Windows GUI創建一個空打印機的答案,但是關於以編程方式執行它的信息相對稀缺且分散。希望我的回答或更好的建議可以爲其他一些可憐的shmo節省一些時間。如何以編程方式爲Windows創建空打印機?

+4

雖然這是完全可以接受的要求,在這裏回答你自己的問題,這個問題你*問*必須滿足與其他問題相同的質量標準。這不是。請[編輯]清楚解釋您嘗試解決的問題,並提出明確提出的問題,然後您發佈的答案即可解決。 –

+1

我的歉意。我認爲標題本身清楚地表明瞭這個問題。也許我太接近它看不到它了?給我一些具體的批評,我會盡我所能來改進它。 – mickeyf

+1

刪除問題的所有內容並添加爲什麼需要創建「空白打印機」的原因。目前帖子只包含「搜索很多」和「我很棒」的文字,沒有明確的理由爲什麼會這樣做。 (你的問題很可能是在形式上的話題)。 –

回答

1

這個「爲我工作」。我想有一個更優雅的方法來實現這一點,我希望有任何改進/糾正代碼的建議,但是我無法找到一個簡潔完整的答案來解釋我認爲相對普遍的需求。我有一個相當具體的要求,很顯然這個代碼可以概括,也可加入適當的錯誤處理等

//pd is a PrintDocument. used like: 

PrintController printController = new StandardPrintController(); 
pd.PrintController = printController; 

NullPrinter np = new NullPrinter();     
if (!np.NullPortExists()) 
{ 
    np.CreateNullPort(); 
} 

if (!np.NullPrinterExists()) 
{ 
    np.CreateNullPrinter(); 
} 

pd.PrinterSettings.PrinterName = "NUL_PRINTER"; 


/*********************************************/ 
using System; 
using System.Management; // This must also be added as a reference 
using System.Drawing.Printing; 
using System.Runtime.InteropServices; 

namespace YourFavoriteNamespace 
{ 
    // 
    // This helper class has methods to determine whether a 'Nul Printer' exists, 
    // and to create a null port and null printer if it does not. 
    // 
    public class NullPrinter 
    { 
    // Printer port management via Windows GUI (Windows 7, probably same in other versions): 
    // 
    //  Go to printers & devices 
    //  Select any printer 
    //  Click on Print server properties 
    //  Select Ports tab 
    //  Add or remove (local) port 
    //  To remove a local port, if "in use", stop and restart the print spooler service. 
    //  It seems that the most recently used port will be "in use" until the system restarts, 
    //  or until another port is used. 
    //  A port may also be added when adding a printer. 
    //  Valid names for a Null port appear to be NUL, NULL, NUL: - all case insensitive. 

    public bool NullPortExists() 
    { 
     for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++) 
     { 
      string printerName = PrinterSettings.InstalledPrinters[i]; 
      string query = string.Format("SELECT * from Win32_Printer WHERE Name LIKE '%{0}'", printerName); 
      ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); 
      ManagementObjectCollection coll = searcher.Get(); 
      foreach (ManagementObject printer in coll) 
      { 
       string pName = printer["PortName"].ToString(); 
       if (pName.Equals("NULL", StringComparison.InvariantCultureIgnoreCase) || 
       pName.Equals("NUL", StringComparison.InvariantCultureIgnoreCase) || 
       pName.Equals("NUL:", StringComparison.InvariantCultureIgnoreCase)) 
       { 
       return true; 
       } 
      } 
     } 
     return false; 
    } 

    // The application that uses this requires a printer specifically named "NUL_PRINTER" 
    public bool NullPrinterExists() 
    { 
     for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++) 
     { 
      if (PrinterSettings.InstalledPrinters[i] == "NUL_PRINTER") 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

    public bool CreateNullPort() 
    { 
     return Winspool.AddLocalPort("NUL") == 0 ? true : false; 
    } 

    public void CreateNullPrinter() 
    { 
     Winspool.AddPrinter("NUL_PRINTER"); 
    } 

} 
/*********************************************************/ 
    // 
    // This Winspool class was mostly borrowed and adapted 
    // from several different people's blog posts, 
    // the links to which I have lost. 
    // Thank you, whoever you are. 
    // 
    public static class Winspool 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     private class PRINTER_DEFAULTS 
     { 
      public string pDatatype; 
      public IntPtr pDevMode; 
      public int DesiredAccess; 
     } 

     [DllImport("winspool.drv", CharSet = CharSet.Auto)] 
     static extern IntPtr AddPrinter(string pName, uint Level, [In] ref PRINTER_INFO_2 pPrinter); 

     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
     struct PRINTER_INFO_2 
     { 
      public string pServerName, 
       pPrinterName, 
        pShareName, 
        pPortName, 
        pDriverName, 
        pComment, 
        pLocation; 
      public IntPtr pDevMode; 
      public string pSepFile, 
        pPrintProcessor, 
        pDatatype, 
        pParameters; 
      public IntPtr pSecurityDescriptor; 
      public uint Attributes, 
        Priority, 
        DefaultPriority, 
        StartTime, 
        UntilTime, 
        Status, 
        cJobs, 
        AveragePPM; 
     } 

     [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. .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 NotUsedByUs; 
      uint xcvResult; 

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

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

      return (int)xcvResult; 
     } 

     public static void AddPrinter(string PrinterName) 
     { 
      IntPtr mystrptr = new IntPtr(0);  
      IntPtr mysend2; 
      PRINTER_INFO_2 pi = new PRINTER_INFO_2(); 

      pi.pServerName = ""; 
      pi.pPrinterName = PrinterName; 
      pi.pShareName = "NUL"; 
      pi.pPortName = "NUL"; 
      pi.pDriverName = "Generic/Text Only"; 
      pi.pComment = "No Comment"; 
      pi.pLocation = "Local"; 
      pi.pDevMode = mystrptr; 
      pi.pSepFile = ""; 
      pi.pPrintProcessor = "WinPrint"; 
      pi.pDatatype = "RAW"; 
      pi.pParameters = ""; 
      pi.pSecurityDescriptor = mystrptr; 
      mysend2 = AddPrinter(null,2, ref pi);      
     } 
    } 

} 
+0

嘿@mickeyf,你有沒有想通過其他方式來做到這一點或改進你的代碼? – jNewbie

+1

@jnewbie我可能會在盤子上有很多東西,事實證明這種情況「足夠好」,所以我沒有花更多時間在它上面。我希望這對你有一些幫助。我不會質疑你的動機。 – mickeyf

+0

哈哈哈,謝謝! 您是否有將代碼發送到創建的打印機的代碼? – jNewbie