6 Replies Latest reply on Jun 21, 2011 1:08 PM by ctaffe

    Steps Toward Print Dialog Bypass?

    ctaffe Level 1

      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 (http://forums.adobe.com/thread/866380?tstart=0), 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 http://stackoverflow.com/questions/2044676/net-code-to-talk-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.

       

      Adding this in here to see if I'm on to something or if I'm on something (from some of the more veteran Flex-ites).

        • 1. Re: Steps Toward Print Dialog Bypass?
          Flex harUI Adobe Employee

          What error are you getting?

           

          I think byteArray.length is a property not a function

          • 2. Re: Steps Toward Print Dialog Bypass?
            EvyatarBH Level 3

            From what I remember from about 7 years ago, ZPL got a unique language that it should get as input (something really creepy with exact positions etc.)

             

            If that is what we are talking about, maybe you should write it as a String, text file or something...

            (Again I'm practically guessing and not sure this haven't changed)

             

            It's amazing that these printers still work!

            • 3. Re: Steps Toward Print Dialog Bypass?
              ctaffe Level 1

              "I think byteArray.length is a property not a function"

               

              You are correct (I had it correct in my code, just wrote it down wrong in the post here ).

               

              "What error are you getting?"

               

              A few things....

               

              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()

               

              Unfortunately I can't see what is taking place in the close or the write to see if it is actually doing anything.  The print job never progresses past spooling (and falls out of the queue once the app is closed after the crash).

               

              "From what I remember from about 7 years ago, ZPL got a unique language that it should get as input (something really creepy with exact positions etc.)"

               

              Yea, you have to send a string directly to the printer....something akin to:

              <<<AAA^XA^LH0,0^FO40,100^FH\^A0N,50,40^FDCookbook II^FS^FO40,150^CI7^FH\^A0N,30,30^FDFrom Alice Cooker^FS^FO40,180^BY3,2^BCN,150,N,N^FD1234567890ABC^FS^PQ1^XZAAA

               

              Hence I'm unable to use the standard FlexPrintJob/PrintJob methods of printing.  I need to be able to write that directly to the Zebra printer.

               

              "It's amazing that these printers still work!"

               

              Yea, unfortunately they are tied heavy into UPS/FedEx and their shipping services.  Without those goliaths holding it up it probably would go by the wayside...

              • 4. Re: Steps Toward Print Dialog Bypass?
                ctaffe Level 1

                I've got this part of the way solved.....

                 

                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.

                • 5. Re: Steps Toward Print Dialog Bypass?
                  Flex harUI Adobe Employee

                  Is this going to run on Windows only?  You might want to use NativeProcess

                  to actually feed the string to the printer.  Save it to a regular file from

                  AIR and then call some custom app to actually do the printing.

                  • 6. Re: Steps Toward Print Dialog Bypass?
                    ctaffe Level 1

                    Quite frankly that might be the final solution to all of this.  If my ZPL printers were just network capable instead of connected via USB and shared I could probably use sockets and have my solution.  Unfortunately this solution only seems to work for my networked laser printers.  Using c# or something similar (with a NativeProcess call) will more than likely work as I believe I can hit any printer via printer name.