title: Print labels via a redirected printer
body: <p>My task is to print labels via a thermal printer. To this purpose a string of tspl(programming language that the printer understands) commands is generated and sent to the printer. The latter is done in C# with the following method taken from  the microsoft example <a href="http://support.microsoft.com/en-us/kb/322091" rel="nofollow">"How to send raw data to a printer by using Visual C# .NET"</a></p>
  
  <pre><code>        public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
      {
          Int32 dwError = 0, dwWritten = 0;
          IntPtr hPrinter = new IntPtr(0);
          DOCINFOA di = new DOCINFOA();
          bool bSuccess = false; // Assume failure unless you specifically succeed.
  
          di.pDocName = "My C#.NET RAW Document";
          di.pDataType = "RAW";
  
          // Open the printer.
          if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
          {
              // Start a document.
              if (StartDocPrinter(hPrinter, 1, di))
              {
                  // Start a page.
                  if (StartPagePrinter(hPrinter))
                  {
                      // Write your bytes.
                      bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                      EndPagePrinter(hPrinter);
                  }
                  EndDocPrinter(hPrinter);
              }
              ClosePrinter(hPrinter);
          }
          // If you did not succeed, GetLastError may give more information
          // about why not.
          if (bSuccess == false)
          {
              dwError = Marshal.GetLastWin32Error();
              MessageBox.Show("Error " + dwError);
          }
          return bSuccess;
      }
  </code></pre>
  
  <p>The actual printer is selected in a PrintDialog</p>
  
  <pre><code>        private void button2_Click(object sender, EventArgs e)
      {
          string s = "CLS\nPRINT 1\n"; // device-dependent string, need a FormFeed?
          // Allow the user to select a printer.
          PrintDialog pd = new PrintDialog();
          pd.PrinterSettings = new PrinterSettings();
          if (DialogResult.OK == pd.ShowDialog(this))
          {
              // Send a printer-specific to the printer.
              RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s);
          }
      }
  </code></pre>
  
  <p>In my working environment everything works fine. The environment is a LAN consisting of 3 computers and 1 shared thermal printer:</p>
  
  <ol>
  <li><strong><em>PC_with_printer</em></strong> - it runs on Windows 7 and has the printer connected to it via USB</li>
  <li><strong><em>PC_aware</em></strong> - it runs on Win 8 and knows about the shared printer</li>
  <li><strong><em>PC_unaware</em></strong> - it runs on WinXP and doens't have the shared printer installed</li>
  </ol>
  
  <p>From PC_aware I connect to PC_unaware via rdp and the printer appears in the list of printers as redirected. Then I run my application , choose the redirected printer and get my empty label printed. So far so good.<br>
  Problems begin when I replace PC_unaware with another computer. It runs on Windows Server 2008 R2 and is not in our LAN. Let's call it SERVER. So I carry out the same experiment:</p>
  
  <ol>
  <li>From PC_aware I connect to SERVER via rdp using its public ip address</li>
  <li>My thermal printer appears in "Printers and Devices" as "TSC_TDP-244 (redirected 20)"</li>
  <li>I go to the printer's properties and click Print Test Page, and it gets printed</li>
  <li>I run my app and the printer doesn't print anything.</li>
  </ol>
  
  <p>I have checked return values of all winapi functions that are used in SendBytesToPrinter method (OpenPrinter,StartDocPrinter, StartPagePrinter, WritePrinter,EndPagePrinter,EndDocPrinter, ClosePrinter), and none of them indicates an error. Any idea why it happens and how it may be fixed?</p>