none
Printing unicode directly to a printer

    Question

  • Im using a tweaked version of the RawPrinterHelper.cs class to print directly to a zebra printer. All is fine until I try and print something containing unicode text, the print still happens but the unicode characters are displayed as question marks. The font Im using on the printer is a unicode code one and I can print unicode on the printer via one of the Zebra utility programs. I thought the problem may have been in the SendStringToPrinter method with the call to Marshal.StringToCoTaskMemAnsi(szString), so I changed it to Marshal.StringToCoTaskMemUni(szString) but doing that caused the printer to fail to print, but with its data light on.

     

    My version of RawPrinterHelper.cs is below:

     

    Code Snippet

    using System;

    using System.IO;

    using System.Drawing.Printing;

    using System.Runtime.InteropServices;

    namespace Printing2

     

    {

    class RawPrinterHelper2

    {

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

    public struct DOCINFOW

    {

    [MarshalAs(UnmanagedType.LPWStr)]

    public string pDocName;

    [MarshalAs(UnmanagedType.LPWStr)]

    public string pOutputFile;

    [MarshalAs(UnmanagedType.LPWStr)]

    public string pDataType;

    }

    [DllImport("winspool.Drv", EntryPoint = "OpenPrinterW", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]

    public static extern bool OpenPrinter(string src, ref IntPtr hPrinter, long pd);

    [DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]

    public static extern bool ClosePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterW", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]

    public static extern bool StartDocPrinter(IntPtr hPrinter, int level, ref RawPrinterHelper2.DOCINFOW pDI);

    [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

    public static extern bool EndDocPrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

    public static extern bool StartPagePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

    public static extern bool EndPagePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]

    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, int dwCount, ref int dwWritten);

     

    public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)

    {

    IntPtr hPrinter = System.IntPtr.Zero;

    Int32 dwError;

    DOCINFOW di = new DOCINFOW();

    Int32 dwWritten = 0;

    bool bSuccess;

    di.pDocName = "My Document";

    di.pDataType = "RAW";

    bSuccess = false;

    if (OpenPrinter(szPrinterName, ref hPrinter, 0))

    {

    if (StartDocPrinter(hPrinter, 1, ref di))

    {

    if (StartPagePrinter(hPrinter))

    {

    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, ref dwWritten);

    EndPagePrinter(hPrinter);

    }

    EndDocPrinter(hPrinter);

    }

    ClosePrinter(hPrinter);

    }

    if (bSuccess == false)

    {

    dwError = Marshal.GetLastWin32Error();

    }

    return bSuccess;

    }

     

    public static bool SendFileToPrinter(string szPrinterName, string szFileName)

    {

    FileStream stream1 = new FileStream(szFileName, FileMode.Open);

    BinaryReader reader1 = new BinaryReader(stream1);

    byte[] buffer1 = new byte[((int)stream1.Length) + 1];

    buffer1 = reader1.ReadBytes((int)stream1.Length);

    IntPtr ptr1 = Marshal.AllocCoTaskMem((int)stream1.Length);

    Marshal.Copy(buffer1, 0, ptr1, (int)stream1.Length);

    bool flag1 = RawPrinterHelper2.SendBytesToPrinter(szPrinterName, ptr1, (int)stream1.Length);

    Marshal.FreeCoTaskMem(ptr1);

    return flag1;

    }

     

    public static void SendStringToPrinter(string szPrinterName, string szString)

    {

    IntPtr pBytes;

    Int32 dwCount;

    dwCount = szString.Length;

    pBytes = Marshal.StringToCoTaskMemAnsi(szString);

    SendBytesToPrinter(szPrinterName, pBytes, dwCount);

    Marshal.FreeCoTaskMem(pBytes);

    }

    }

    }

     

     

    Wednesday, January 23, 2008 3:24 PM

Answers

  • Well I seem to have come up with a fix so here it is:

     

    Change the SendStringToPrinter method to:

     

    Code Snippet

    public static void SendStringToPrinter(string szPrinterName, string szString)

    {

      IntPtr pBytes;

     

      // create a temp byte buffer

      byte[] encodedBytes = Encoding.Unicode.GetBytes(szString);

     

      // allocate some memory for the copy

      pBytes = Marshal.AllocCoTaskMem(encodedBytes.Length + 1);

     

      // copy the byte arry to the allocated memory

      Marshal.Copy(encodedBytes, 0, pBytes, encodedBytes.Length);

     

      // send to the printer method

      SendBytesToPrinter(szPrinterName, pBytes, encodedBytes.Length);

     

      // free the allocated memory

      Marshal.FreeCoTaskMem(pBytes);

    }

     

     

    Seems to work.

    Friday, January 25, 2008 12:09 PM

All replies

  • Ok, I can move this on a bit.

     

    The problem with unicode characters being printed as question marks was down to the SendStringToPrinter method and the call to Marshal.StringToCoTaskMemAnsi(szString); Turning the pBytes back into a string showed that the unicode chars had been turned in question marks.

     

    So, I've change the SendStringToPrinter to the following, using Marshal.StringToCoTaskMemUni instead:

     

    Code Snippet

    public static void SendStringToPrinter(string szPrinterName, string szString)

    {

      IntPtr pBytes;

      Int32 dwCount;

     

      dwCount = szString.Length;

     

      pBytes = Marshal.StringToCoTaskMemUni(szString);

     

      SendBytesToPrinter(szPrinterName, pBytes, dwCount);

      Marshal.FreeCoTaskMem(pBytes);

    }

     

     

    But the problem now appears to be that the call to

     

    Code Snippet
    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, ref dwWritten);

     

    In the method SendBytesToPrinter does not work correctly with a IntPtr which points at unicode data, it does not seem to read to the end of the data. I've tried to test this by doubling the dwCount size and had some success printing correctly but this is obviously not a viable solution.

     

    Have I got the definition for the WritePrinter call correct, its currently:

     

    Code Snippet

    [DllImport("winspool.Drv", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]

    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, int dwCount, ref int dwWritten);

     

     

     

    Thursday, January 24, 2008 12:25 PM
  • Well I seem to have come up with a fix so here it is:

     

    Change the SendStringToPrinter method to:

     

    Code Snippet

    public static void SendStringToPrinter(string szPrinterName, string szString)

    {

      IntPtr pBytes;

     

      // create a temp byte buffer

      byte[] encodedBytes = Encoding.Unicode.GetBytes(szString);

     

      // allocate some memory for the copy

      pBytes = Marshal.AllocCoTaskMem(encodedBytes.Length + 1);

     

      // copy the byte arry to the allocated memory

      Marshal.Copy(encodedBytes, 0, pBytes, encodedBytes.Length);

     

      // send to the printer method

      SendBytesToPrinter(szPrinterName, pBytes, encodedBytes.Length);

     

      // free the allocated memory

      Marshal.FreeCoTaskMem(pBytes);

    }

     

     

    Seems to work.

    Friday, January 25, 2008 12:09 PM
  • I have got the same as this problem

    have you solved it?

    please inform me about it

    thank you

    Friday, July 15, 2011 11:31 AM