I am using the code on http://support.microsoft.com/kb/322091 to send raw data to a USB printer.
This doc only explains how to send data, but some printers do also report data back.
I am wondering if it would be possible to extend that code, so it would also raise an event on received data from the printer. I don't know though if that's possible at all based on extension of that code.
//something like
[DllImport("winspool.Drv", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ReadPrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwRead);
Related
I have the following function:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetLongPathName(
[MarshalAs(UnmanagedType.LPTStr)]
string path,
[MarshalAs(UnmanagedType.LPTStr)]
StringBuilder longPath,
int longPathLength
);
This works with files and folder paths that are available on the device. But if I have a DELETED item then I get an empty string. The path of the deleted item which comes from the FilesystemWatcher looks something like this 'C:\abc\FIRSTF~1\SECOND~1\THIRDF~1\FOURTH~1\FIFTHF~1....\AVIA~1.jpg'.
Is there a way to get the long path of a deleted item?
I am trying to programmatically open a file in notepad++ using SendMessage but I'am having no luck.
I figured that because I can drag and drop a file onto Notepad++ and it will open it, that a SendMessage would work.
Declarations:
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
Method:
I launch Notepad++ using Process.Start:
IntPtr cHwnd = FindWindowEx(pDocked.MainWindowHandle, IntPtr.Zero, "Scintilla", null);
SendMessage(cHwnd, WM_SETTEXT, 0, "C:\Users\nelsonj\Desktop\lic.txt");
When SendMessage executes it will send my text into the 'edit' section of Notepad++ instead of opening the file.
Any help would be great.
If you simply want to open a file in Notepad++, you can just start a new Process:
set the path of the file you want to open to the Arguments property of the ProcessStartInfo class.
the FileName property is set to the path of the program you want to open.
UseShellExecute and CreateNoWindow are irrelevant here, leave the default.
using System.Diagnostics;
Process process = new Process();
ProcessStartInfo procInfo = new ProcessStartInfo()
{
FileName = #"C:\Program Files\Notepad++\notepad++.exe",
Arguments = Path.Combine(Application.StartupPath, "[Some File].txt"),
};
process.StartInfo = procInfo;
process.Start();
if (process != null) process.Dispose();
I want to send raw data to print, avoiding printer selection (fast print).
I am trying to use this helper provided by Microsoft: https://support.microsoft.com/en-us/kb/322091#top
However, when I call to the method:
RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s);
My printer starts to works (makes some noise) but It never takes the white paper and starts to print.
I have tried it with my two printers and the behavior is the same in both printers. Also I discard the possibility that the printers are broken because I can print other documents.
What can be wrong?
Try this:
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
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;
}
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;
}
}
Fran_gg7, I had the same issue recently. Firstly, turn on the persistence of documents on the printer. This will allow you to see if the printer successfully received the print request.
You will see items in the printer queue and they will remain there.
In my scenario the print request was correctly being sent to the printer, however I was testing it on a laser printer that ultimately was unable to interpret the raw string data I was passing to it.
I tested the same output on a label printer that could understand the ZPL (zebra programming language) I was passing it and boom it worked fine.
Have a look at this for a detailed explanation
Hope this helps.
In cases where you are using the MSDN example from here https://support.microsoft.com/en-us/kb/322091#top but are trying to use an array of bytes instead of a string or file... This may help
public static void SendBytesToLocalPrinter(byte[] data, string printerName)
{
var size = Marshal.SizeOf(data[0]) * data.Length;
var pBytes = Marshal.AllocHGlobal(size);
try
{
SendBytesToPrinter(printerName, pBytes, size);
}
finally
{
Marshal.FreeCoTaskMem(pBytes);
}
}
This does not change with the byte array encoding. This is useful if you are trying to send some utf8 encoded byte sequences with some binary (ie. image) data mixed in as was the case for our team.
If printing plain text to Dot Matrix using "RawPrinterHelper" Method, it would only work properly for me when I manually added a printer, selected Generic / Text Only, and selected the USB001 port that was assigned to my USB connected printer (okidata in my test). Then RawPrinterHelper.SendStringToPrinter would behave very much like an 'lpd to lpt1:'
Had exactly the same issue with my ZEBRA ZD420 printer.
Sending ZPL string to printer only the data light flashing shortly without printing.
I changed only
Marshal.StringToCoTaskMemAnsi(szString);
to
Marshal.StringToCoTaskMemUTF8(szString);
and it works !
Before you go on and flag my question as a duplicate, believe me, its
not. I have gone through virtually every solution provided here and I
still can't get to get my app to work, so please will you just be nice
and take some time to help me.
Scenario: I have a Zebra RW 420 thermal printer which I would like to use for printing vouchers with a QR Code on them. I am using C# and have followed all the help as given by Scott Chamberlain here and the code here for sending the commands to the printer. I have the EPL2 manual as well as the CPCL, and ZPL reference manuals with a whole lot of stuff on how to format my commands.
Problem:
All the commands I am sending are either printing as plain text replicas of the commands or the printer just hangs with the small message icon showing on its display. I have tried sending the same commands using the Zebra Utilitis and still getting the same result as with my sample app.
Below is the code snippets I have, please do advise me if there are any reference libraries I may require to get this to work.
private void btnPrint_Click(object sender, RoutedEventArgs e)
{
string s = "! 0 200 200 500 1\nB QR 10 100 M 2 U 10\nMA,QR code ABC123\nENDQR\nFORM\nPRINT";
// Have also tried \r\n for the line feeds with the same result.
// Allow the user to select a printer.
PrintDialog pd = new PrintDialog();
if ((bool)pd.ShowDialog())
{
var bytes = Encoding.ASCII.GetBytes(s);
// Send a printer-specific to the printer.
RawPrinterHelper.SendBytesToPrinter(pd.PrintQueue.FullName, bytes, bytes.Length);
}
}
PrinterHelper class as modified by Scott here
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, byte[] 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, byte[] 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 = "Zebra Label";
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();
throw new Win32Exception(dwError);
}
return bSuccess;
}
}
I did a lot of work on Zebra ZT230 and GX430t printers last year, and the thing I found out about them was using the ZPL instructions over TCP sockets via port 9100 was a LOT more reliable.
I know this is taking your conversation in a very different direction, but having tried the spool / Win32 approach I can tell you using sockets was a lot more reliable. Let me know if you need some sample code.
Wrote a kiosk application using a KR403 last year. I was able to
successfully print and poll the status of the printer to see if there
was a paper jam low paper etc via usb using the blog post below.
http://danielezanoli.blogspot.com/2010/06/usb-communications-with-zebra-printers.html
Using print spooler (Print only)
https://sharpzebra.codeplex.com/SourceControl/latest#src/Com.SharpZebra/Printing/RawPrinter.cs
I used the ZebraDesigner to do my initial layout. On the print screen
inside the zebra designer there is a print to file option that will
save your design as a txt file with ZPL in it. I then took that file
broke it up into sections and created a helper class that uses a
StringBuilder internally so I could focus on certain pieces of the zpl
since it can be overwhelming to look at more than 1-2 lines.
var kioskTicketBuilder = new KioskTicketBuilder();
kioskTicketBuilder.SetPrinterDefaults();
kioskTicketBuilder.DisplayTicketHeader();
kioskTicketBuilder.DisplayInformationHeading(data.Name, data.todaysDate, data.ClientName, data.ClientCode);
kioskTicketBuilder.DisplayMoreStuff()
kioskTicketBuilder.DisplayBarcode(data.TrackingId);
kioskTicketBuilder.EndOfJob();
return kioskTicketBuilder.GetPrintJobToArray();
Also if you go to the the printer properties > Printing Defaults > Tools
Tab There is an option to send a file of zpl to the printer or send
individual commands. This is really good for testing your zpl seperate
from your application.
I'm having some problems when sending raw command to a FGL-enabled Practical Automation ITX3002 ticket printer. I've been searching the whole day and I wasn't able to find a working example of using the ReadPrinter method from the winspool.drv Windows library.
Most code samples I've found, were related to network printers. This is a simple printer connected via usb. I need to retrieve some commands which response structure I already know (composite structure, well documented by the vendor).
I am able to send FGL commands to print normal and diagnostic ticket successfully. My problem, is reading back the data from the printer. I've read the Microsoft documentation found in http://msdn.microsoft.com/en-us/library/dd162895(v=vs.85).aspx and several other places. The doc doesn't explain how to SEND the data which this method is reading.
So, I really don't know if I have to call WritePrinter with the commands I need, close the handle, then call ReadPrinter to retrieve the data, or if I have to do everything in a single printer handle management (I mean, open, work and close a printer handle).
The vendor has been very patient with me, but the responses don't give me any help on how to get this.
This is my code:
[DllImport("winspool.Drv", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern Boolean ReadPrinter(IntPtr hPrinter, StringBuilder data, Int32 cbBuf, out Int32 pNoBytesRead);
public static Boolean ReadBytesFromPrinter(String szPrinterName, out String data)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
Boolean bSuccess = false; // Assume failure unless you specifically succeed.
data = null;
di.pDocName = "SendBytesToPrinter";
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))
{
Int32 maxRead = 256;
StringBuilder sbData = new StringBuilder(maxRead);
//Read Data
bSuccess = ReadPrinter(hPrinter, sbData, maxRead, out dwWritten);
data = sbData.ToString();
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();
data = null;
}
return bSuccess;
}
ReadPrinter always return "false", and the call to GetLastWin32Error is always zero. In other words, there is an error, no clues about what, and no data is read back.
I'm sending the commands as explained in http://support.microsoft.com/kb/322091 and it's successfully working as expected, with print commands and diagnostic ticket printing.
Does anyone knows the right handshaking between the code and the printer? How it's supposed to write the commands, and how to read response back? For me, it's no sense having to create a print job, a print document, and a print page to retrieve the data (I've already tryed that, BTW). Am I missing something? Am I making something wrong?
Have you checked Enable bidirectional support in the ports tab of the printer properties dialog? If it's grayed out, you will need to find a driver that supports bidirectional comms.