I am working on a simple application that will be reading a text file that will overwritten every 5 minutes with some telemetry data.
I was trying to use microsoft PrintDocument but it wont work for this case because i need to have control of the printer spooler to print a new line every five but in the same page than the previous (continously). This is not possible with PrintDocument class at least for my understanding, because you cannot have control of the spooler with this class and each print command its a job and when it finishes the job then the printer scrolls the page to taken by the user. If someone knows if there is a way to continue printing in the same page every 5 minutes please share the information or example.
I am using an Okidata Microline 186 USB dot matrix printer and after a few tries with other third parties libraries with out any luck i found RawPrintHelper.cs class and i am trying it and i were able to send RAW data to the printer with this class but i have some issues. The class is here:
This is the original class code:
public class RawPrinterHelper
{
// Struct
ure 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;
}
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;
}
public static bool SendStringToPrinter( string szPrinterName, string szString )
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
// Fix from Nicholas Piasecki:
// dwCount = szString.Length;
dwCount = (szString.Length + 1) * Marshal.SystemMaxDBCSCharSize;
// 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;
}
}
public partial class USB : Form
{
public USB()
{
InitializeComponent();
}
// 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;
}
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;
}
public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
// Fix from Nicholas Piasecki:
// dwCount = szString.Length;
dwCount = (szString.Length + 1) * Marshal.SystemMaxDBCSCharSize;
// 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;
}
private void buttonSEND_Click(object sender, EventArgs e)
{
System.Windows.Forms.OpenFileDialog open = new System.Windows.Forms.OpenFileDialog();
string dados = "";
if (open.ShowDialog().Equals(DialogResult.OK))
{
StreamReader sr = new StreamReader(open.FileName);
dados = sr.ReadToEnd();
sr.Close();
}
string printer = "PRINTER NAME";
for (int i = 0; i < 30; i++)
{
SendStringToPrinter(printer, dados);
}
}
}
Issues:
First problem was that it prints only using a file with this method "SendFileToPrinter":
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;
}
However it dont work perfectly, the printer head stay to the right side of the page and when it try to print again then it writes the beginning of the text at the right of the page and then continue with the rest of the text. The second option that is using this method which receives an string to print:
public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
// Fix from Nicholas Piasecki:
// dwCount = szString.Length;
dwCount = (szString.Length + 1) * Marshal.SystemMaxDBCSCharSize;
// 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;
}
But this method is no sending anything to the printer, The printer dont begin print. I made a hybrid from both functions by taking a look at both methods and i finally able to print with this code but with same alignment issues as with the SendFileToPrinter, no mater if i send the text always in the same format delimited by tabs each line that i send to the printer is not well aligned.
This is my piece of code:
public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
bool bSuccess = false;
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength = Encoding.ASCII.GetBytes(szString).Length;
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[nLength];
bytes = Encoding.ASCII.GetBytes(szString);
// 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;
}
This is an example of what i need to print:
Expected Format
The first tree lines are for the header of the table. and the next lines will be printed one of them each 5 minutes with readings of values.
How ever its not consistent even after formatted the string and delimited by tabs.
This is what i am getting when print with my Frankenstein method.
PAGE TITLE ........ LINE 1
VAL3 VAL4 VAL1 VAL2
Time / Date DESC DESC DESC DESC ........ LINE 3
3/4/2019 11:30 AM 100 300 500 434 ........ LINE 4
3/4/2019 11:35 AM 99 290 340 452 ........ LINE 5
3/4/2019 11:40 AM 120 310 100 532 ........ LINE 6
Its not consistent and only the first line prints ok and aligned. I am newbie in this of sending raw data to the printer and i dont whats going on that is causing this when i call the method SendStringToPrinter(myString) every five minutes. I dont know if i need to specify the coordinates or where to start printing neither how to do it.
I will appreciate any help in order to fix this problem.
For the first part of the question, yes WritePrinter is the way to go because that allows you to send raw bytes. I'm not reading into the details of all your code because that is way too much code for this question.
For the layout part of this question, that printer looks like it is expecting ESC/POS. Here is the command sheet. Update your text file to conform to those commands, namely the page format section. e.g.
ESC HT 12 Hello 08 World
would align "World" to the 8th character position. You'll need to experiment with the commands to find what works. If you're new to ESC/POS I would recommend using notepad++ to create your test files. If you enable the character panel (Edit->Character Panel) you can inject arbitrary ASCII codes into the file. An ESC/POS string of the above would be:
1b090cHello09World
Related
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.
My client has bought a new Cash Drawer for his POS system.
Features fo the cash drawer as follows:
Model: D41SRB
SKU: D41SRB
Electronic Cash Drawer Black 16",
Roller, 24V Epson STD RJ11, Stainless front
5 Bill/5 Coin
1mm steel case
Two extra brackets inside top of case for added durability`
Its connected to the reciept printer EPSON TM-T88V Receipt.
I need to open this drawer from a click of button in my C# application, however when I set the drawer to open after print from Printer Preference it works. So , I am sure its connected fine. I need something similar to this ARTICLE but in C#.
So please help
To open the drawer on the TM-T88 series, you have to have it connected via a serial or network port.
The following command sequence is what I used. This is really old code, but it should do the job. You have to open the port and initialize the printer before doing anything else, so that's in there too.
private SerialPort serialPort1 = new SerialPort();
public void OpenPort()
{
serialPort1.PortName = "COM1";
serialPort1.Encoding = Encoding.ASCII;
serialPort1.BaudRate = 38400;
serialPort1.Parity = System.IO.Ports.Parity.None;
serialPort1.DataBits = 8;
serialPort1.StopBits = System.IO.Ports.StopBits.One;
serialPort1.DtrEnable = true;
serialPort1.Open();
}
public void InitializePrinter()
{
serialPort1.Write(Char.ConvertFromUtf32(27) + char.ConvertFromUtf32(64));
}
public void OpenDrawer()
{
serialPort1.Write(char.ConvertFromUtf32(27) +
char.ConvertFromUtf32(112) +
char.ConvertFromUtf32(0) +
char.ConvertFromUtf32(5) +
char.ConvertFromUtf32(5));
}
I am able to solve my issue I used
RawPrinterHelper.SendStringToPrinter("EPSON TM-T88V Receipt", System.Text.ASCIIEncoding.ASCII.GetString(new byte[] { 27, 112, 48, 55, 121 }));
got this drawer code from http://keyhut.com/popopen.htm
Heres My whole code:
public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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.Unicode, 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.Unicode, 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 = "RAW Document";
// Win7
di.pDataType = "RAW";
// Win8+
// di.pDataType = "XPS_PASS";
// 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;
}
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);
fs.Close();
fs.Dispose();
fs = null;
return bSuccess;
}
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;
}
}
private void button1_Click(object sender, EventArgs e)
{
RawPrinterHelper.SendStringToPrinter("EPSON TM-T88V Receipt", System.Text.ASCIIEncoding.ASCII.GetString(new byte[] { 27, 112, 48, 55, 121 }));
}
After this by clicking on button1 it kicks the drawer.
assume your serial port is called "port".
Just use: port.writeLine("\x10\x14\x01\x00\x08"); // For Cash Drawer 0
Just use: port.writeLine("\x10\x14\x01\x01\x08"); // For Cash Drawer 1
as the printer can talk to 2 cash drawers.
Commands:
ASCII DCE DC4 n m t
Hex 10 14 n m t
Decimal 16 20 n m t
Where n = 1, m = 0 or 1 (cash drawer #), t <= 1, t <=8
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 try to create a program that will programatically set Windows Color Management to archive an effect like f.lux as a hobby project.
**The definition of WINAPI WcsGetDefaultColorProfileSize. **
BOOL WINAPI WcsGetDefaultColorProfileSize(
_In_ WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
_In_opt_ PCWSTR pDeviceName,
_In_ COLORPROFILETYPE cptColorProfileType,
_In_ COLORPROFILESUBTYPE cpstColorProfileSubType,
_In_ DWORD dwProfileID,
_Out_ PDWORD pcbProfileName
);
**This is the signature of managed WcsGetDefaultColorProfileSize. **
[DllImport("Mscms.dll", EntryPoint = "WcsGetDefaultColorProfileSize", CharSet = CharSet.Unicode)]
private static extern bool GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
[MarshalAs(UnmanagedType.LPWStr), In] string pDeviceName,
COLORPROFILETYPE cptColorProfileType,
COLORPROFILESUBTYPE cpstColorProfileSubType,
Int32 dwProfileID,
out IntPtr pcbProfileSize
);
The problem is when I try to get the string which is return as a pointer from WINAPI using Marshal class. Like this
// Need to get the size of ICC profile file first
GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER,
monitor_name.DeviceKey,
COLORPROFILETYPE.CPT_ICC,
COLORPROFILESUBTYPE.CPST_RGB_WORKING_SPACE,
1,
out SizePointer);
System.Diagnostics.Debug.WriteLine("Size is " + Marshal.ReadInt32(SizePointer));
the GetDefaultColorProfileSize return TRUE but when I try to access the address it return (It return this address 0x0000003e) using Marshal.ReadInt32
It throw this error
System.AccessViolationException Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
How can I able to read the memory at that pointer?
I try to allocate the memory first as suggesting by nvoigt
Changing from IntPtr SizePointer to IntPtr SizePointer = Marshal.AllocHGlobal(4);
But it still throw the same exception
The full code is below here.
Enumnerate Display Devices
[DllImport("User32.dll")]
private static extern bool EnumDisplayDevices(
string lpDevice, int iDevNum,
ref DISPLAY_DEVICE lpDisplayDevice, int dwFlags);
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAY_DEVICE
{
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
public int StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
public DISPLAY_DEVICE(int flags) {
cb = 0;
StateFlags = flags;
DeviceName = new string((char)32, 32);
DeviceString = new string((char)32, 128);
DeviceID = new string((char)32, 128);
DeviceKey = new string((char)32, 128);
cb = Marshal.SizeOf(this);
}
}
Window Color System
enum WCS_PROFILE_MANAGEMENT_SCOPE
{
WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE = 0,
WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER
}
enum COLORPROFILETYPE
{
CPT_ICC = 0x0001,
CPT_DMP,
CPT_CAMP,
CPT_GMMP
}
enum COLORPROFILESUBTYPE
{
CPST_NONE = 0x0000,
CPST_RGB_WORKING_SPACE = 0x0001,
CPST_PERCEPTUAL = 0x0002,
CPST_ABSOLUTE_COLORIMETRIC = 0x0004,
CPST_RELATIVE_COLORIMETRIC = 0x0008,
CPST_SATURATION = 0x0010,
CPST_CUSTOM_WORKING_SPACE = 0x0020
}
[DllImport("Mscms.dll", EntryPoint = "WcsGetDefaultColorProfileSize", CharSet = CharSet.Unicode)]
private static extern bool GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
[MarshalAs(UnmanagedType.LPWStr), In] string pDeviceName,
COLORPROFILETYPE cptColorProfileType,
COLORPROFILESUBTYPE cpstColorProfileSubType,
Int32 dwProfileID,
out IntPtr pcbProfileSize
);
[DllImport("Mscms.dll", EntryPoint = "WcsGetDefaultColorProfile" , CharSet =CharSet.Unicode, SetLastError =true)]
private unsafe static extern bool GetDefaultColorProfile(WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
[MarshalAs(UnmanagedType.LPWStr), In] string pDeviceName,
COLORPROFILETYPE cptColorProfileType,
COLORPROFILESUBTYPE cpstColorProfileSubType,
Int32 dwProfileID,
Int32 cbProfileName,
out IntPtr pProfileName);
[DllImport("Mscms.dll", EntryPoint = "WcsSetUsePerUserProfiles", CharSet = CharSet.Unicode)]
private static extern bool SetUsePerUserProfiles([MarshalAs(UnmanagedType.LPWStr), In]string pDeviceName, Int32 dwDeviceClass, bool usePerUserProfiles);
[DllImport("Mscms.dll", EntryPoint = "WcsGetUsePerUserProfiles", CharSet = CharSet.Unicode)]
private static extern bool GetUsePerUserProfiles([MarshalAs(UnmanagedType.LPWStr), In]string pDeviceName, Int32 dwDeviceClass, out bool pUsePerUserProfiles);
The Actual Code
public unsafe static void GetProfile() {
DISPLAY_DEVICE lpDisplayDevice = new DISPLAY_DEVICE(0); // OUT
DISPLAY_DEVICE monitor_name = new DISPLAY_DEVICE(0); // OUT
int devNum = 0;
while (EnumDisplayDevices(null, devNum, ref lpDisplayDevice, 0)) {
int devNum2 = 0;
while (EnumDisplayDevices(lpDisplayDevice.DeviceName, devNum2, ref monitor_name, 0)) {
IntPtr SizePointer;
// Need to get the size of ICC profile file first
GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER,
monitor_name.DeviceKey,
COLORPROFILETYPE.CPT_ICC,
COLORPROFILESUBTYPE.CPST_RGB_WORKING_SPACE,
1,
out SizePointer);
System.Diagnostics.Debug.WriteLine("Size is " + Marshal.ReadInt32(SizePointer));
// Try to get a location of ICC profile file.
// Not Implement Yet
break;
}
break;
}
}
Your SizePointer is a local variable that you never used. I don't know what you expect to happen, but this is not going to work. You probably meant to use profileSize.
In the future, you should fix your warnings first. They are important.
Okay, now you are at least passing the correct variable. You still have not initialized it to anything. You are passing a NULL pointer to a method that is supposed to write there. It won't be able to. I cannot imagine you actually got a TRUE back from that method. And reading from a NULL pointer will obviously fail. You need to make sure that pointer actually points to a part in memory that can be written to.
You need a DWORD. As you are using ReadInt32, I'll assume you are on 32bit.
You need to allocate memory first:
int size = 4; // 4 byte = 32 bit
IntPtr p = Marshal.AllocHGlobal(size);
Don't forget to free it later, this is not garbage collected:
Marshal.FreeHGlobal(p);