0
votes

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 "How to send raw data to a printer by using Visual C# .NET"

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

The actual printer is selected in a PrintDialog

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

In my working environment everything works fine. The environment is a LAN consisting of 3 computers and 1 shared thermal printer:

  1. PC_with_printer - it runs on Windows 7 and has the printer connected to it via USB
  2. PC_aware - it runs on Win 8 and knows about the shared printer
  3. PC_unaware - it runs on WinXP and doens't have the shared printer installed

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.
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:

  1. From PC_aware I connect to SERVER via rdp using its public ip address
  2. My thermal printer appears in "Printers and Devices" as "TSC_TDP-244 (redirected 20)"
  3. I go to the printer's properties and click Print Test Page, and it gets printed
  4. I run my app and the printer doesn't print anything.

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?

1
This is really more of a Remote Desktop issue. Since PC_unaware has no LAN connection and the shared printer hasn't been installed on it, it's relying on RD's printer cloning feature, which I've always found to be problematic. Is RD really essential to the problem you're trying to solve? If not, I would get it out of the picture.Carey Gregory
This printing functionality should be available on the server and users connect to it via rdp, so I am afraid RD is an essential part.zurab
I don't know how RD implements printer cloning, but I strongly suspect it depends on the spooler being involved, which means that writing directly to cloned printers won't work. A lot of complex code would be required in RD to support direct printing and it's rare enough that my guess would be they did not implement it.Carey Gregory

1 Answers

0
votes
PRINTER_DEFAULTS pd;

    pd.DesiredAccess = PRINTER_ACCESS_USE;
    pd.pDatatype = NULL;
    pd.pDevMode = NULL;

    if (!OpenPrinter(szPrinterName, &hPrinter, &pd))
        return false;