0

I know this is a pretty heavy topic and see requests for it all the time (I believe the stance for blocking it is security related).

While messing around trying to get ZPL printing working in AIR, I ran into something interesting.

Looking at other programming languages and their attempts to print to ZPL, most of them handle it through a File Stream and treat the printer as a file (see here for a .NET example .NET code to send ZPL to Zebra printers).

I took this approach with Flex and got some interesting results.

I tested this talking directly to a network shared printer on my own PC. It's a simple piece of code:

var file:File = new File('\\\\PC-Name\\Printer-Name');
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);

Obviously you will need to fill in your own info for PC-Name (network name) and Printer-Name (printer's shared name).

If you watch your printer, you'll notice that it does initiate spooling with this request.

Unfortunately, this is about as far as I'm able to get with it. Initiating any sort of actually writing over that stream doesn't seem to work (although I'm far from an expert on the matter, I could be missing something).

Stepping through something like:

var file:File = new File('\\\\PC-Name\\Printer-Name');
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.close();

You can watch it hit the spooler with the open and then successfully close without any ill effects.

Once you add an actual write though such as:

var byteArray:ByteArray = new ByteArray();
byteArray.writeUTFBytes("Hello World");
byteArray.position = 0;

var file:File = new File('\\\\PC-Name\\Printer-Name');
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeBytes(byteArray, 0, byteArray.length);
stream.close();

It all goes to hell unfortunately.

Some things to note about the variables and what happens:

After declaring your file (var file:File = new File('\\PC-Name\Printer-Name');), when you inspect the file variable you'll notice a few issues. creationDate, modificationDate, and size all have "exception thrown by getter" errors. More specifically "Error: Error #3003: File or directory does not exist.". I'm not overly concerned with these as it isn't a file, it's a printer.

After opening the stream (stream.open(file, FileMode.WRITE);) and inspecting the stream variable the "bytesAvailable" has an "exception thrown by getter" (Error: Error #2029: This URLStream object does not have a stream opened). Once again, it isn't a file so the bytesAvailable like this might be okay (or it may be the reason everything after this seems to fail). At this point, you will also have a print document with a status of "Spooling" in your print queue.

Calling stream.writeBytes(byteArray, 0, byteArray.length); causes the stream variable position to move from 0 to 167 (the length of my byteArray). So it seems to think it attempts to write. Nothing "bad" seems to happen here.....

Calling stream.close(); however, brings the whole thing crashing down with a "Error #2038: File I/O Error. at flash.filesystem::FileStream/close()

Posting this here to see if anyone has any ideas (am I missing something? Is it completely not possible? Close but no cigar?)

******** UPDATE *********

I did find a way to accomplish this with a network printer (unfortunately not with a windows shared printer). It is using sockets instead of filestreams. I can almost guarantee you this will throw some sandbox violations upon an actual release so that will need to be handled (socket policy files I would assume).

public var socket:Socket = new Socket();
socket.addEventListener( Event.CONNECT, onConnect);
socket.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData);
socket.connect(ip_address, 9100);

private function onConnect(event : Event) : void {
  var byteArray:ByteArray = new ByteArray();
  byteArray.writeUTFBytes("Hello World");
  byteArray.position = 0;

  socket.writeBytes(byteArray, 0, byteArray.length);
  socket.removeEventListener(Event.CONNECT, onConnect);
  socket.removeEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
  socket.flush();
  socket.close();
}

public function onSocketData(event:Event):void {
  trace("onSocketData Fired");
}

Not sure if one can even connect over a socket to a windows shared printer (ie a printer connected to someone's PC and shared). So far I haven't had any luck. But, if you are strictly dealing with networked printers this might work for you to skip/bypass the flex print dialogue.

Community
  • 1
  • 1
fr0x
  • 1
  • 1
  • Update added above with successfull socket connection to networked printer (still unable to handle windows shared printers) – fr0x Jun 21 '11 at 17:12

1 Answers1

0

I'm making a few assumptions: If you're using AIR and you have a working .Net solution and you are targeting Windows only... why not just use the .Net solution and call it using NativeProcess class?

Basically you compile the ZPL .NET printer as an EXE and call it using NativeProcess, passing in the printer string.

That way you can still have a nice Flexy interface but get native printing controls.

Jonathan Rowny
  • 7,588
  • 1
  • 18
  • 26
  • That might be the eventual answer to all of this. It definitely would be preferred if we could keep this all bundled within a single app and a single code base. I know quite a few people are also looking for methods to avoid the printer dialogue within Flex/Air. If it does turn out that this is a failed exercise we will move to the NativeProcess calling the .net piece of code. It just seems so promising since it seems one can initiate spooling to the printer this way ;) – fr0x Jun 21 '11 at 14:20
  • You can keep it all bundled, just drop the EXE in your "assets" folder and use it that way. It will be packaged with your app when you deploy it. This is exactly how Rosetta Stone works (Rosetta Stone is a Flex/AIR app). The only additional dependency will be .Net but most windows machines have that anyway. I don't know enough about Flex's file stream or printing to help you sorry :( – Jonathan Rowny Jun 21 '11 at 14:27
  • "I don't know enough about Flex's file stream or printing to help you sorry :(" Not a problem, I definitely thank you for your help in the solution you provided. It will probably be the route I end up taking because while I have been successfull now in using sockets to talk to network printers, I need this to be able to handle shared printers as well which doesn't seem possible this way. – fr0x Jun 23 '11 at 15:03