Solved

Referencing the VB Printer object in ASP

Posted on 2001-08-08
27
766 Views
Last Modified: 2013-11-25
I have some VB code that prints output using the VB Printer object.  When I compile this code into a VB project and run it on my local machine, it works fine.  Now, I'd like to convert that code so that it runs as VBScript in an ASP page.

I have two choices.  Convert my VB code to VBScript - in which case I get errors when I reference Printer.Print (do I need to do some CreateObject statement to create a  printer object?)

Or, I can encapsulate my Printer.Print statements in a method inside of a COM object that I'm calling from the ASP page.  I'm fine with this second option, as I have a COM object I'm working with already.  However, I get some unhandled Printer Error kicking back to the ASP page.

I'm a little confused about what physical printer the com object would be referencing.  Is it the printer connected to the Web Server and defined under the context of the System User?  That wont do me much good.

Basically, I want my Printer.Print statements to be sent to the browser's default printer on the client's machine.

Any ideas on how to approach this?

Mike
0
Comment
Question by:mdougan
  • 7
  • 7
  • 7
  • +3
27 Comments
 
LVL 15

Expert Comment

by:ameba
ID: 6365889
Hi,
IMHO, you should delete this question or ask moderators to reduce the points, I expect you'll get "You cannot do that" answer.  I am not ASP expert, but I would be very surprised (and angry) if this would be possible.
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 6365901
>>Is it the printer connected to the Web Server and defined under the context of the System User?

It is the printer connected to the Web Server I would imagine.  ASP code, along with any code run by your instantiated COM object, will run at the server.  It processes the code and then generates the html to send to the client.  All the client gets is the html, so all of your Printer.Print statements are long gone.

With webpages, you must resort to the simple window.print functions via Javascript or VBScript...the key being, that it is client-side script.  If you are trying to print specific data using multiple Printer.Print statements, you will probably need to resort to an ActiveX solution that is downloaded and run on the client machine.
0
 
LVL 10

Expert Comment

by:arana
ID: 6366003
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6367027
ameba IMHO "absolutely nothing is impossible, is just a question of time" and that challenge is what makes this place interesting.
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6367047
The way to solve this problem is to Create a VB ActiveX DLL.

Your class object should have a simple Public property  which you set up as the printer. Give your class a name like "PRASP".
Save the project with a name like "MySubs" & compile the project.  

The Class initialise will setup up a link to the printer object.

Then in your asp you can say :

Dim Printer
Dim MySubs

Set MySubs=Server.CreateObject("MySubs.PRASP")
Set Printer=MySubs.MyPrinter

' You Now have a printer you can use.

Printer.Print "Try Me"
Printer.EndDoc

Set Printer=Nothing
Set MySubs=Nothing

I will post the code for the class module next.
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6367058
Code for the module PRASP.

Option Explicit

Public MyPrinter

Private Sub Class_Initialize()
Set MyPrinter = Printer
End Sub

Private Sub Class_Terminate()
Set MyPrinter = Nothing
End Sub
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6367059
By the way - it works! I tested it.
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6367115
To make the example print to any printer on your network you need to add a printer in the server printers panel for each printer to be utilised. Then change the initialise event to select relevant printer.

0
 
LVL 17

Expert Comment

by:inthedark
ID: 6367166
Option Explicit


Public MyPrinter

Private Sub Class_Initialize()
Dim pr
For Each pr In Printers
    If pr.DeviceName = "HP LaserJet 4L" Then
        Set Printer = pr
        Set MyPrinter = Printer
    End If
Next
End Sub

Private Sub Class_Terminate()
Set MyPrinter = Nothing
End Sub

You could pass the name of the printer as a parameter.

But warning this code only works as a DLL as it exploits a loophole in VB.

The printer object is not meant to be a Public variable.
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 6367678
>>To make the example print to any printer on your network

Does not take into account the question of:

>>Basically, I want my Printer.Print statements to be sent to the browser's default printer on the client's machine.


The problem is that you cannot control printing of a client machine from a server via simple HTTP protocol
0
 
LVL 18

Author Comment

by:mdougan
ID: 6368496
Printing on the client machine is a requirement.

I wouldn't mind using Client Side ASP script, if I could control the printing on the client's machine from there.

Any thoughts on client side script that can do something similar as print statements to the printer object? In VBScript with the FileStream object?  Or JScript or javascript?
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 6368640
you will need a component, that runs client-side.  i dont think you will find any alternative.  one sample i found on the web if you are interested:

http://home.att.net/~wshvbs/wshPrinterObjectPage.htm
0
 
LVL 18

Author Comment

by:mdougan
ID: 6369144
I looked at aranas link, and it pointed to an article about the wsh which didn't work for me, as I don't seem to have wsh installed (I've got NT 4.0, but maybe not the right service pack).

The link AzraSound provided was closest yet to what I need, but I think I'd run into problems with it.  I'm really using Printer.Line (10,10) - (20,10) type of statements for drawing lines to the printer object, not writing text, and it doesn't look like they implemented the Line method.

I'm starting to think that my best bet might be to output my lines in HTML (if I can get it exact enough), and then print the window or frame through the normal browser File|Print menu.

I'll leave this open for a few more days, but if I don't get any other suggestions, I'll give Azra credit.
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 15

Expert Comment

by:ameba
ID: 6369233
Maybe you can use Word Automation and create .doc file...
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 6369273
>>I'm starting to think that my best bet might be to output my lines in HTML

And that is really the only solution on a server-to-client relationship over the Internet.  Sometimes, on an Intranet, you can get away with certain things, but otherwise, when all you are really serving to the client is text, that text better be formatted how you want it before it gets there.  Even then, people gripe about how html is printed out, and they want to control headers/footers/etc.  Truth be told, once the page is on the client machine, youre pretty much outta the picture.  What settings the user chooses when printing is entirely up to them.

One thing before you go and try to reproduce html code that creates the effect you are after.  Since you are using the Print statement, consider using it on a picturebox control within a COM object.  Once the image is "painted", you can serve up that picture by saving it to a temp file or streaming it to the client, e.g.,


<%
Dim objDraw
Set objDraw = Server.CreateObject("MyComponent.Draw")
Call objDraw.DrawPic
Call objDraw.SavePic(strFile)
%>

<img src="<%= strFile %>">


You would have to perform some cleanup routine to delete these temporary images, but you cant do it within the context if this instance of your component, otherwise, the temporary picture file will be deleted before the client receives the html, at which time it will see the <img> tag, and request the picture from the server, only to find it has already been deleted.

Another option, I had mentioned, is to stream the image to the client.  Ifthe image is the only thing that needs to be sent to the client, you can set an appropriate content-type, and use a Response.BinaryWrite command to stream the byte information for your created image.  This sends the actual contents and avoids the problem of saving to a temporary file.
0
 
LVL 18

Author Comment

by:mdougan
ID: 6369662
AzraSound,

Your last option might get me where I want to go in the shortest amount of time.

I'm doing my Line statements to a Printer object, but I'm sure I could do the same to a picture box.  One problem is that my com object doesn't have any graphical elements, forms or controls, it's just code.  I wonder if I can do the Line drawing to a DIB or stdPicture?  Or, I can add a form and picturebox.  Either way.

Can you give me an example of the VBScript necessary to do the Response.BinaryWrite using the streaming technique?  Assume that I'm drawing into a picture box, and I guess I'd be streaming the contents of the Picture property?  But I'm a little confused how this would work.

0
 
LVL 28

Accepted Solution

by:
AzraSound earned 300 total points
ID: 6369838
>>Or, I can add a form and picturebox.

This would probably be your best bet.  Once you have instantiated your COM object, and done the Line statements to the picturebox, you need to get that binary data out to stream to the client.  There is probably a way to grab the contents and turn it into a binary stream, or byte array, but the easiest method would probably be to save the picture to a temp file.  Then, you can use the ADO stream object to read that file and stream it to the client, e.g.,


<%
Dim objDraw, objStream

Set objDraw = Server.CreateObject("MyComponent.Draw")
Call objDraw.DrawImage
Call objDraw.SaveImage(strFile)

'create ADO Stream object
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1     'adTypeBinary
objStream.Open
objStream.LoadFromFile strFile

'stream contents to the client
Response.ContentType = "image/bmp"
Response.BinaryWrite objStream.Read

objStream.Close
Set objStream = Nothing
Set objDraw = Nothing
%>



This is untested but it should work, so long as the image is all that you need to send to the client.  I believe it gets a bit trickier if you wish to stream the image along with additional content.
0
 
LVL 10

Expert Comment

by:arana
ID: 6372901
*watching very interested in the results*


looks very very good AZRA! :)
0
 
LVL 18

Author Comment

by:mdougan
ID: 6374316
Great, I'll try it over the weekend and let you know!
0
 
LVL 17

Expert Comment

by:inthedark
ID: 6378713
I new there would be an answer somewhere.  But BMP's could be converted to JPG to gain a performance advantage.

Another route in a different direction, which may have some advantages and like the bmp./jpg route would also work with non-windows clients.  If you purchased a PDF kit, you could generate the documents for download, which could also be printed. Some of the kits work a bit like the printer object and don't cost too much. You could also consider generating RTF or DOC files but formatting images is harder.
0
 
LVL 18

Author Comment

by:mdougan
ID: 6380936
OK, some interesting developments.  I added a method to my OCX that would print to a picturebox instead of the printer and then save the results as a bmp file.  This worked fine with no modifications to the Line drawing code except to point to the picture box instead of the printer.

The Stream code gave me some trouble, because I was starting to format a regular HTML document, and then was trying to do the BinaryWrite in the middle of the Body section.  It didn't want to change the content type after I'd already written out the HTML and BODY tags, so, I had to strip out all HTML and only have the script doing the BinaryWrite.  When I tried it on a test JPG file, it would keep throwing me into Visual Interdev, showing me the source of the document as a bunch of binary characters, but it would never show the jpg inside the browser window.

So, I tried it using a test bmp file, and instead of showing it inside the browser window, it would pop-up Paintbrush, with my test bmp file opened.  This was an interesting option, so, I tried printing, but the output is offset by the margins which are set in the Paintbrush File|Print Setup (which I can never set lower than .25").

So, going back to the thought of getting the bmp to display in the browser window, I realized that I don't really need to do a binarywrite if I've already saved the file as a temporary bmp.  Instead, I just have simple HTML to load and <IMG src='temp.bmp'> and it loads it fine.  Still, when I print, the margins throw off the output.

Before I go through the print code and adjust for the standard margin size, any idea of how I might be able to adjust the printer margins from HTML?  And/or to maybe output my bmp to a popup window and print it automatically, so that the user doesn't have to click on the File|Print in the browser?

Say that I have some html that just loads the image, in my script after generating the bmp can I do something like

window.open("printimage.html")
window.print
window.close

0
 
LVL 18

Author Comment

by:mdougan
ID: 6380949
The answer got me further along than I expected I'd be able to get to.  The binarywrite is an interesting option to know about.  Still working to get the exact output, but at least it's possible!  Thanks!

Mike
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 6381016
>>Instead, I just have simple HTML to load and <IMG src='temp.bmp'> and it loads it fine.

The thing to watch for here is concurrent users.  If this image is dynamic (which it must be to be going through this trouble) then consider the scenario when two people request this image near simultaneously...


Client1 requests the image
Client2 requests the image
Server Side component generates image for Client1
Server side component generates image for Client2
Client1 receives image generated for Client2
Client2 receives image generated for Client2

This may be a rare case, but something to consider.



As for the automatic printing...
1) You cant control how HTML prints.  Its really up to the end user, how they have things configured, etc.  The only way to even attempt to control printing on the client's computer is via an activex control embedded in the webpage which alters the user's browser's print settings via the registry right before a print operation, and then resets them afterwards.  Of course, if you go through all of that trouble, you might as well stick your original component into an ocx and embed it in the webpage and call your original Printer.Print statements.

2) For "auto-printing", youre on the right track.  It would be something like:

window.open("imageGenerator.asp")

and from within imageGenerator.asp you would have:

<html>
<body onload="javascript:window.print();">
<%
    'all code to generate the image here
%>
</body>
</html>
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6381269
Good job, Azra!
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 6381302
Thanks Dennis...

This is an area of development that I thoroughly enjoy, so I look forward to giving as much input as possible to these types of queries...and I have taken the "DennisBorg-approach" to answering in this thread with those long, clean, and concise comments.  ;-)
0
 
LVL 8

Expert Comment

by:DennisBorg
ID: 6381350
I'll hafta keep you in mind should I ever need to develop expertise in that area.


>I have taken the "DennisBorg-approach" to answering

Thank you for the kind compliment. :-)


-Dennis Borg
0
 
LVL 18

Author Comment

by:mdougan
ID: 6381355
To complicate matters further, I tried the javascript print code listed above, and found that you can run into browser specific problems with the java script.  I found some sample code that checks to see if you have IE4 (NS4 or IE5 will use the print code as written).  If you IE4, then I found some script that you can write to use the ExecWB method of the web browser object in IE.  You can tell it to Print and not prompt the user (note, the body onload didn't seem to work with IE4 so, I also included an href to the print function):

<SCRIPT LANGUAGE="JavaScript">
<!--
var da = (document.all) ? 1 : 0;
var pr = (window.print) ? 1 : 0;
var mac = (navigator.userAgent.indexOf("Mac") != -1);

function printPage() {
     alert("In Print Page");
     if (pr) // NS4, IE5    
         window.print()  
     else if (da && !mac) // IE4 (Windows)
          vbPrintPage()  
     else // other browsers
          alert("Sorry, your browser doesn't support this feature.");  
}

if (da && !pr && !mac) with (document) {
     // Shell.Explorer
     writeln('<OBJECT ID="WB" WIDTH="0" HEIGHT="0" CLASSID="clsid:8856F961-340A-11D0-A96B-00C04FD705A2"></OBJECT>');
     writeln('<' + 'SCRIPT LANGUAGE="VBScript">');  
     writeln('Sub window_onunload');
     writeln('  On Error Resume Next');  
     writeln('  Set WB = nothing');
     writeln('End Sub');  
     writeln('Sub vbPrintPage');

     writeln('  OLECMDID_PRINT = 6');
     writeln('  OLECMDEXECOPT_DONTPROMPTUSER = 2');
     writeln('  OLECMDEXECOPT_PROMPTUSER = 1');  
     writeln('  On Error Resume Next');
     writeln('  WB.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER');
     writeln('End Sub');
     writeln('<' + '/SCRIPT>');
}

//-->
</SCRIPT>
<html>
<body onload="javascript:printPage();">
<A HREF="javascript:printPage();"><IMG SRC='temp.bmp'></a>
</body>
</html>
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Introduction I needed to skip over some file processing within a For...Next loop in some old production code and wished that VB (classic) had a statement that would drop down to the end of the current iteration, bypassing the statements that were c…
The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now