Related
recently I was testing printing using winspool drv and I managed to be able to print successfully through a string (extracted from prn file). Now I want to check the status of my print job. I have read the winspool api documentation but there isn't much of C# examples, so I am kind of lost.
I chanced upon this link and I am facing issues implementing it .
This is my current code
#region Send to Printer
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean SetDefaultPrinter(String name);
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
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 = "Document";
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
if (hPrinter.ToInt32() == 0)
return false; //Printer not found!!
// 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();
}
return bSuccess;
} public static bool SendStringToPrinter(string szPrinterName, string szString)
{
bool bSuccess = false;
try
{
Byte[] bytes = new Byte[szString.Length];
//your unmanaged pointer
IntPtr pUnmanagedBytes = new IntPtr(0);
//read content to array
bytes = System.Text.Encoding.UTF8.GetBytes(szString);
bytes = System.Text.Encoding.UTF8.GetPreamble().Concat(bytes).ToArray();
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(bytes.Length);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, bytes.Length);
//send the unmanage bytes to the printer
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, bytes.Length);
//Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
}
catch (Exception ex)
{ string s = ex.Message.ToString(); }
return bSuccess;
}
to call the method
SendStringToPrinter(printername, prnstring);
Appreciate if anyone could help thx!
In the code you already have, StartDocPrinter returns a job ID you can query using GetJob.
See here and here for possibly useful info.
I'm trying to convert Vietnamese to Latin. It is a requirement to send the byte to ESC/P printer (see C# ESC/POS Print Vietnamese for reason why).
But my question is very simple, look at this code:
Encoding enc = Encoding.GetEncoding(1258); //vietnamese code page
string content = "Cơm chiên với các loại gia vị truyền";
string newStr = Encoding.GetEncoding("Latin1").GetString(enc.GetBytes(content));
string origStr = enc.GetString(Encoding.GetEncoding("Latin1").GetBytes(newStr)); //origStr is becomes "Cơm chiên v?i các lo?i gia v? truy?n"
Why is the origStr becomes Cơm chiên v?i các lo?i gia v? truy?n instead of contain the same content with content? But, it works fine in Chinese or Thai. You can test the code below...
For Chinese Simplified
Encoding enc = Encoding.GetEncoding(936); //chinese simplified code page
string content = "印尼炒饭";
string newStr = Encoding.GetEncoding("Latin1").GetString(enc.GetBytes(content));
string origStr = enc.GetString(Encoding.GetEncoding("Latin1").GetBytes(newStr)); //origStr is correct "印尼炒饭"
For Thai
Encoding enc = Encoding.GetEncoding(874); //Thai code page
string content = "ข้าวผัดอินโดนีเซียกับเครื่องเทศแบบดั้ง";
string newStr = Encoding.GetEncoding("Latin1").GetString(enc.GetBytes(content));
string origStr = enc.GetString(Encoding.GetEncoding("Latin1").GetBytes(newStr)); //origStr is correct "ข้าวผัดอินโดนีเซียกับเครื่องเทศแบบดั้ง"
Any idea why? Why Vietnamese won't work? How to make it work so I can send it to Printer?
Thanks for any help :)
PS.
Here is the code I used to send to printer
[DllImport("Winspool.drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("Winspool.drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("Winspool.drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("Winspool.drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("Winspool.drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("Winspool.drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("Winspool.drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
public static bool SendBytesToPrinter(string printerName, IntPtr pBytes, int dwCount, string docName = null, string dataType = "RAW")
{
DOCINFOA di = new DOCINFOA();
di.pDocName = string.IsNullOrWhiteSpace(docName) ? string.Empty : docName;
di.pDataType = string.IsNullOrWhiteSpace(dataType) ? "RAW" : dataType;
IntPtr hPrinter = new IntPtr(0); int dwError = 0, dwWritten = 0; bool bSuccess = false;
if (OpenPrinter(printerName.Normalize(), out hPrinter, IntPtr.Zero))
{
if (StartDocPrinter(hPrinter, 1, di))
{
if (StartPagePrinter(hPrinter))
{
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
if (bSuccess == false)
dwError = Marshal.GetLastWin32Error();
return bSuccess;
}
public static bool SendBytesToPrinter(string printerName, byte[] bytes, string docName)
{
int dwCount = bytes.Length;
IntPtr ptrBytes = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(byte)) * bytes.Length);
try
{
Marshal.Copy(bytes, 0, ptrBytes, bytes.Length);
SendBytesToPrinter(printerName, ptrBytes, dwCount, docName);
}
finally { Marshal.FreeCoTaskMem(ptrBytes); }
return true;
}
public static bool SendStringToPrinter(string printerName, string str, string docName)
{
int dwCount = str.Length;
IntPtr ptrBytes = Marshal.StringToCoTaskMemAnsi(str);
try { SendBytesToPrinter(printerName, ptrBytes, dwCount, docName); }
finally { Marshal.FreeCoTaskMem(ptrBytes); }
return true;
}
Usually this happens when you provide the encoder with data not present in the codepage.
So if you would e.g. try to convert a character with a byte value > 255 (which is not present in codepage 1258) you would get the fallback which is the ? character in this case. My guess is, that you have invalid data in the input string in the first case (maybe characters that look the same but are not the correct ones).
My next step would be to inspect the characters and their corresponding byte values.
I am trying to automate one of our daily print jobs.
On the old VBA program...
We are creating the crystal report, grabbing an 8 1/2 x 11 pdf, then grabbing an 11 x 17 pdf
The program then prints these in consecutive order. They are all sent to the same printer, but the 11 x 17 pdf uses another driver specifically for the paper size. Both pdfs are shelled in adobe and printed.
We are now trying to do the same thing in C#, except without shelling. There are still two drivers set up for the printer, and I have been trying to send the raw data directly to them, but I still have one issue...
The 11 x 17 pdfs are not "true" 11 x 17's (sometimes 12.8 x 18.4, etc.). This causes the printer to stop printing (even appear offline) until you select a tray from the physical printer and click start.
I have played with the driver enough to believe that the driver is not the issue, but the program is to blame. I am trying to use winspool to complete this process, but don't know if this is the right approach.`
namespace WorkOrderMass.Helper
{
public class RawPrinterHelper
{[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
PrinterSettings ps = new PrinterSettings();
bool bSuccess = false; // Assume failure unless you specifically succeed.
di.pDocName = "PDF Document";
di.pDataType = "RAW";
PrintDocument pd = new PrintDocument();
pd.DefaultPageSettings.PaperSize = new PaperSize("PaperA3", 840, 1180);
pd.Print();
// 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);
System.Threading.Thread.Sleep(5000);
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();
}
return bSuccess;
}
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
bool bSuccess = true;
using (FileStream fs = new FileStream(szFileName, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
Byte[] bytes = new Byte[fs.Length];
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
}
}
return bSuccess;
}
}
}`
Answer: Program is now using SumantraPDF to silently print the PDF's.
I have a zebra zt410 printer.
I've found a class to print a barcode with it.
RawPrinterHelper.cs
public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
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();
}
return bSuccess;
}
/// <summary>
///
/// </summary>
/// <param name="szPrinterName"></param>
/// <param name="szFileName"></param>
/// <returns></returns>
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
}
/// <summary>
///
/// </summary>
/// <param name="szPrinterName"></param>
/// <param name="szString"></param>
/// <returns></returns>
public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
dwCount = szString.Length;
// Assume that the printer is expecting ANSI text, and then convert
// the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
// Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount);
Marshal.FreeCoTaskMem(pBytes);
return true;
}
I'm sending data to printer like below:
StringBuilder strBldr = new StringBuilder();
strBldr.AppendLine("^XA");
strBldr.AppendLine("^FO40,100");
strBldr.AppendLine("^AQ,50,30");
strBldr.AppendLine(string.Format(CultureInfo.InvariantCulture, "^FO220,50^A0,30,30^FD{0}^FS", m.No));
strBldr.AppendLine(string.Format(CultureInfo.GetCultureInfoByIetfLanguageTag("en-EN"), "^FO220,90^A0,30,30^FD{0}^FS", m.DescriptionENG));
strBldr.AppendLine(string.Format(CultureInfo.GetCultureInfoByIetfLanguageTag("ru-RU"), "^FO220,130^A0,30,30^FD{0}^FS", m.DescriptionRUS));
strBldr.AppendLine("^FO100,300^BY2");
strBldr.AppendLine("^BCN,60,Y,N,Y,N");
strBldr.AppendLine(string.Format(CultureInfo.InvariantCulture, "^FD{0}^FS", m.No));
strBldr.AppendLine("^XZ");
RawPrinterHelper.SendStringToPrinter("ZDesigner ZT410-203dpi ZPL", strBldr.ToString());
English characters print normally, but Russian characters don't.
I've changed this line in RawPrinterHelper.cs
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
to
pBytes = Marshal.StringToCoTaskMemUni(szString);
but no effect.
Any help?
Regards.
this link has given me an idea: Unicode characters on ZPL printer
I haven't done it with sending string, but I'm creating a uft-8 file before every printing job and sending this file to printer.
It's solved my problem.
If someone needs:
StreamWriter sw11 = new StreamWriter(fileName, false, Encoding.UTF8);
sw11.WriteLine("^XA");
sw11.WriteLine("^FO40,100");
sw11.WriteLine("^AQ,50,30");
sw11.WriteLine(string.Format(CultureInfo.InvariantCulture, "^FO200,50^A0,40,40^FD{0}^FS", m.No));
sw11.WriteLine(string.Format(CultureInfo.GetCultureInfo("tr-TR"), "^FO200,100^A0,30,25^FD{0}^FS", m.DescriptionTR));
sw11.WriteLine(string.Format(CultureInfo.GetCultureInfo("en-US"), "^FO200,135^A0,30,25^FD{0}^FS", m.DescriptionENG));
sw11.WriteLine(string.Format(CultureInfo.GetCultureInfo("ru-RU"), "^FO200,170^A0,30,25^FD{0}^FS", m.DescriptionRUS));
sw11.WriteLine(string.Format(CultureInfo.GetCultureInfo("en-US"), "^FO200,205^A0,30,25^FD{0}^FS", m.Model));
sw11.WriteLine("^FO100,300^BY2");
sw11.WriteLine("^BCN,60,Y,N,Y,N");
sw11.WriteLine(string.Format(CultureInfo.InvariantCulture, "^FD{0}^FS", m.No));
sw11.WriteLine("^XZ");
sw11.Close();
RawPrinterHelper.SendFileToPrinter(printerName, fileName);
RawPrinterHelper.cs
public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
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();
}
return bSuccess;
}
/// <summary>
///
/// </summary>
/// <param name="szPrinterName"></param>
/// <param name="szFileName"></param>
/// <returns></returns>
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
}
/// <summary>
///
/// </summary>
/// <param name="szPrinterName"></param>
/// <param name="szString"></param>
/// <returns></returns>
public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
dwCount = szString.Length;
// Assume that the printer is expecting ANSI text, and then convert
// the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
// Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount);
Marshal.FreeCoTaskMem(pBytes);
return true;
}
Regards.
I can render the text, but cannot render the svg element. When I save the html I am trying to render as a svg file, Internet Explorer will render the complete image the way it should, so I fairly confident my input data is ok.
here is where I launch the thread that starts the webbrowser
Browserinfo bi = new Browserinfo(height, width, rsltPath, stype);
bi.Temphtml = temphtml.Replace("\\", "/");
Thread webBrowseThread = new Thread(new ParameterizedThreadStart(PerformWebBrowseOp));
webBrowseThread.SetApartmentState(ApartmentState.STA);
webBrowseThread.Start(bi);
bi.Temphtml is the file that I save the input data to. This is the way the file looks (with the guts removed)
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><svg xmlns="http://www.w3.org/2000/svg"
..svg data...
</svg></body></html>
here is the actual code:
private void PerformWebBrowseOp(object obj)
{
Browserinfo bi = (Browserinfo)obj;
using (Bitmap bitmap = new Bitmap(bi.Width, bi.Height))
{
using (WebBrowser webBrowser = new WebBrowser())
{
webBrowser.Navigate("file:///"+bi.Temphtml);
while (webBrowser.Document.Body == null)
{
Application.DoEvents();
}
IHTMLDocument2 rawDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
//rawDoc.write(sbody);
IHTMLElement rawBody = rawDoc.body;
IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;
Rectangle bitmapRect = new Rectangle(0, 0, bi.Width, bi.Height);
webBrowser.DrawToBitmap(bitmap, bitmapRect);
System.Drawing.Imaging.Encoder qualityEncoder = System.Drawing.Imaging.Encoder.Quality;
var quality = (long)100;
using (EncoderParameter ratio = new EncoderParameter(qualityEncoder, quality))
{
using (EncoderParameters codecParams = new EncoderParameters(1))
{
codecParams.Param[0] = ratio;
ImageCodecInfo ici = null;
if (bi.ImgType == "jpg")
{
ici = GetImageEncoder(ImageFormat.Jpeg);
}
else
{
ici = GetImageEncoder(ImageFormat.Png);
}
bitmap.Save(bi.SavePath, ici, codecParams);
}
}
}
}
((AutoResetEvent)waithandle[0]).Set();
}
In the interest of keeping the discussion focused the following notes might be helpful:
I initially used Batik and had it working, but Java is not installed on our webserver and the boss refuses to install it. Back to the drawing board!
I downloaded svg.dll, and got it partially working. It will render part of the svg element, but doesn't render the text.
I think I'm missing an interface or should be calling a com object, but haven't any idea how or what to do.
Simple answer, you cant do it that way. However you can do it with librsvg. I've copied my code below which works on the png but does not for jpeg. If anyone can see whats wrong with the jpeg part, please let me know.
The files you will need are:
freetype6.dll
intl.dll
libcairo-2.dll
libcroco-0.6-3.dll
libexpat-1.dll
libfontconfig-1.dll
libgdk-win32-2.0-0.dll
libgdk_pixbuf-2.0-0.dll
libgio-2.0-0.dll
libglib-2.0-0.dll
libgmodule-2.0-0.dll
libgobject-2.0-0.dll
libgthread-2.0-0.dll
libgtk-win32-2.0-0.dll
libpango-1.0-0.dll
libpangocairo-1.0-0.dll
libpangoft2-1.0-0.dll
libpangowin32-1.0-0.dll
libpixbufloader-svg.dll
libpng14-14.dll
librsvg-2-2.dll
libxml2-2.dll
zlib1.dll
The extract of the svg code from your html page should look like this.
<svg xmlns="http://www.w3.org/2000/svg" width="945" height="325"....</svg>
In other words, get rid of all the html except what is in the svg tags
here is the C# routine
private void RasterizeSvg(string tempsvg, string rsltPath, int _width, int _height, string formattype)
{
string slib = ConfigurationManager.AppSettings["LibrSvgPath"];
if (slib == null)
{
slib = #"C:\Librsvg";
}
bool callSuccessful = SetDllDirectory(slib);
if (!callSuccessful)
{
throw new Exception("Could not set DLL directory");
}
// g_type_init is critical for the png to save correctly
g_type_init();
rsvg_init();
IntPtr error = IntPtr.Zero;
IntPtr rsvghandle = rsvg_handle_new_from_file(tempsvg, out error);
if (error != IntPtr.Zero)
{
throw new Exception(Marshal.ReadInt32(error).ToString());
}
rsvg_handle_close(rsvghandle, out error);
if (error != IntPtr.Zero)
{
throw new Exception(Marshal.ReadInt32(error).ToString());
}
IntPtr cairosurface = cairo_image_surface_create(cairo_format_t.CAIRO_FORMAT_RGB24, _width, _height);
IntPtr cairocontext = cairo_create(cairosurface);
bool brslt = rsvg_handle_render_cairo(rsvghandle, cairocontext);
cairo_destroy(cairocontext);
if (formattype == "png")
{
cairo_surface_write_to_png(cairosurface, rsltPath);
cairo_surface_destroy(cairosurface);
}
else
{
//jpeg not working. the problem is how to convert from a cairo surface to a pixbuf
// once we figure that out, we can implement the jpeg conversion
/*option 1*/
//IntPtr pixbuf = cairo_create(cairosurface);
//cairo_set_source_surface(pixbuf, cairosurface, 0, 0);
//cairo_rectangle(pixbuf, 0, 0, _width, _height);
//cairo_fill(pixbuf);
//error = IntPtr.Zero;
/*option 2*/
IntPtr pixbuf = rsvg_handle_get_pixbuf(rsvghandle);
rsvg_handle_close(rsvghandle, out error);
cairo_surface_destroy(cairosurface);
gdk_init(0, "");
callSuccessful = gdk_pixbuf_save(pixbuf, rsltPath, formattype, out error);
gdk_exit(out error);
if (!callSuccessful)
{
throw new Exception(error.ToInt32().ToString());
}
/* need to release pixbuf memory*/
}
g_object_unref(rsvghandle);
}
As I said at the top, the jpeg doesnt work yet. But it will render out to png.
Finally here are some declarations you will need
enum cairo_format_t
{
CAIRO_FORMAT_INVALID = -1,
CAIRO_FORMAT_ARGB32 = 0,
CAIRO_FORMAT_RGB24 = 1,
CAIRO_FORMAT_A8 = 2,
CAIRO_FORMAT_A1 = 3,
CAIRO_FORMAT_RGB16_565 = 4,
CAIRO_FORMAT_RGB30 = 5
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern bool SetDllDirectory(string pathname);
[DllImport("libgobject-2.0-0.dll", SetLastError = true)]
static extern void g_type_init();
[DllImport("libgobject-2.0-0.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void g_object_unref(IntPtr obj);
[DllImport("librsvg-2-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool rsvg_handle_render_cairo(IntPtr handle, IntPtr cairorenderer);
[DllImport("librsvg-2-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr rsvg_handle_get_pixbuf(IntPtr _rsvghandle);
[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr rsvg_handle_new_from_file(string file_name, out IntPtr error);
[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool rsvg_handle_close(IntPtr _rsvghandle, out IntPtr error);
[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void rsvg_init();
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr cairo_create(IntPtr cairo_surface_t);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr cairo_image_surface_create(cairo_format_t _pixformat, int width, int height);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_surface_write_to_png(IntPtr cairo_surface_t, string filename);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_set_source_surface(IntPtr destbuf, IntPtr srcsuface, double x, double y);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_rectangle(IntPtr buf, double x, double y, double width, double height);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_fill(IntPtr destbuf);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_destroy(IntPtr buf);
[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_surface_destroy(IntPtr buf);
[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error);
[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr gdk_pixbuf_get_from_drawable(IntPtr dest, IntPtr src, IntPtr cmap, int srcx, int srcy, int destx, int desty, int width, int height);
[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void gdk_init(int argcnt, string args);
[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void gdk_exit(out IntPtr error);