TechSpoken

"Any ideas?" is the most frequently-asked question in technical forums. My answer is: yes.

How to ruin a weekend (or: Endless Vistas)

Adrian Paterson-Roos wrote plaintively (and you'd 'plaint too):

I am trying to create PDF's on an "In house System" using MS Fox Pro, we originally used your suggestion of the Apple Color printer, which worked fine in XP, but since testing in VISTA, it's all gone wrong. I have looked at your posting (http://www.spacefold.com/articles/PDFPower.aspx), which gave some clues, but even trying to use alternative Printer drivers listed in http://www.spacefold.com/articles/PDFPower.aspx, all I get are blank PDFs.

Have you done any work with VISTA and if so, can you put me out of my misery?

Dear god, yes I have done work in Vista. In fact, I bruised my fingers writing two white papers for MS during the Vista beta.  I breathed, dreamt, and ate Vista for a period of months, to do it. 

I'm not sure what happened to the white papers, or where they might be published, so I can't reference them for you here. They were not entirely complimentary, and I presented them before this was a fashionable attitude. Maybe the attitude had nothing to do with it, and just the VFP-slant on integration and interop got them buried. 

Or maybe the papers were just cr*p. I don't think so, though, since a very similar approach to the one I took in the XAML-oriented paper turned up in recommendations for VB6 and the Interop toolkit, including remarkably similar terminology, later.  I'm not saying at all that they got the idea from me, just that I can't have been too far off the mark.

In any case, GhostScript is really environment-independent and therefore works as well under Vista as under XP, so as far as I knew PdfListener and PdfClass did too.  I suspected that Adrian's blank PDFs were the product of a permission problem, that some errors were being swallowed, and GS, when invoked, didn't have PS source files to work on.

I easily verified this as a potential problem by spelunking around in google for a few minutes (I think I searched for "postscript Vista" or something like that.)

Some posts were yet more plaintive cries, just confirming there was a general issue. Others really made me want to throw up my hands in disgust and forget the whole thing (not because the posts were horrible but because the problem is so endemic and so deep).  But a few gave me pointers on how to fix the thing, and I returned to these later on.

I started a from-scratch "transparent" install to see what could be wrong and immediately ran into what you see below.  This activity ordinarily happens during the  .VerifyPrinterSetup method in both PdfListener and PdfClass, but in this screenshot I've extracted it to the command line so you can see clearly that we're not in GhostScript territory when the error occurs:

Vista not liking it

To give MS credit, they're really telling you exactly what's wrong here.  The ntprint.inf that I'm invoking, and that comes with Vista, doesn't have the information it needs to do what you're asking it to do.

My Vista computer originally had XP on it.  It has a C:\I386 folder with a different ntprint.inf file in it, with all the instructions you need to install the Postscript base files and their association with the PS printer name I happen to have specified (in this case, Apple Color LaserWriter 12/600).  So all I really had to do to fix this was to make a small change in PdfListener... from:

#DEFINE DRIVER_TO_USE "Apple Color LaserWriter 12/600"

lcCmd = [%windir%\\system32\\rundll32.exe ] + ;
   [printui.dll,PrintUIEntry /if /b ] + ;
   ["] + THIS.PSDriverSetupName + ["] + ;
   [ /f %windir%\\inf\\ntprint.inf /r "lpt1:" /m "] + ;
   DRIVER_TO_USE + [" /Z]

 

... to

#DEFINE DRIVER_TO_USE "Apple Color LaserWriter 12/600"
#DEFINE NTPRINT_INF_LOC "C:\\I386\\"

lcCmd = [%windir%\\system32\\rundll32.exe ] + ;
   [printui.dll,PrintUIEntry /if /b ] + ;
   ["] +
THIS.PSDriverSetupName + ["] + ;
   [ /f ] + NTPRINT_INF_LOC + [ntprint.inf /r "lpt1:" /m "] + ;
   DRIVER_TO_USE + [" /Z]

 

... and if the old files could be assumed to be available, that would do it.

Of course, in PdfListener, we don't assume the files are available.  You already know what we do to install the GS files: we stick them all in an INSTALL.DBF and pop them out at runtime.  There's no reason in the world why you can't do the same thing for the old ntprint.inf file and the relevant postscript driver files from some XP install, if you want. 

The relevant code might now look something like this:

#DEFINE DRIVER_TO_USE "Apple Color LaserWriter 12/600" 

lcCmd = [%windir%\\system32\\rundll32.exe ] + ;
   [printui.dll,PrintUIEntry /if /b ] + ;
   ["] +
THIS.PSDriverSetupName + ["] + ;
   [ /f ] + THIS.GSLocation + [ntprint.inf /r "lpt1:" /m "] + ;
   DRIVER_TO_USE + [" /Z]


... and of course if life were simple in Vista-land, that would do it.

The reason it's not simple, as you can probably guess, is that these old drivers are not signed.  Once you take them out of an "expected" location such as C:\I386, you're likely to see something like the following -- which is hardly a "transparent" installation of your branded PDF driver:

Uh-oh. User's not going to have a clue when they see this dialog confirming installation of Apple Color LaserWriter, a printer they don't have.

So, what to do? 

First, get yourself a signed PostScript driver.  (Don't forget to use one that supports at least one color printer model, if you want color PDFs.)  I got mine here.

Change your DRIVER_TO_USE value to something that matches the materials you downloaded (for the one I used, an appropriate value was Xerox 700 Integrated Color Server PS) .  You will usually have to change the name of the .inf file to match whatever file goes with this set of installation files, too.

Your resulting code, which will allow you to do the install from the location of your choice without that dialog, will look something like this, assuming you dump the driver install files in the same place as the GS files:

lcCmd = [%windir%\\system32\\rundll32.exe ] + ;
   [printui.dll,PrintUIEntry /if /b ] + ;
      ["] + THIS.PSDriverSetupName + ["] + ;
   [ /f ] +
THIS.GSLocation + OTHER_INF_FILENAME + ;
   [ /r "lpt1:" /m "] + ;
   DRIVER_TO_USE + [" /Z]

 

... and this will work.

Of course I'm assuming you clear the usual UAC hassles and standard user permission issues in our Brave New OS World. "Work" is a relative term.

It is semi-okay for users to understand that creating a PDF is "printing".

But, hey, this dialog doesn't clue them in about what driver is being installed, it's okay for your branded "PDF driver" to show it. 

I've already mentioned this type of problem in the original PdfListener article and if you're doing VFP in Vista you doubtless have come up with your own approach to the general UAC and permissions hurdles.  In this case, my personal recommendation is to run the setup program for your app under admin settings to make sure everything you need goes as planned, because the potential disasters are hardly limited to PdfListener's requirements. You can include the .VerifyPrinterSetup code as part of your app setup, whether by instantiating one of my classes -- the method code is designed to run outside of a report context, during setup, as well as "verifying" at report-time -- or by lifting the code.

I'll put a link from the original article to this post.  I won't bother to change the PRGs in the code downloads for the article, because who knows what else someone will discover before the dust settles.

Happy Vistas! Now I'll SET SARCASM OFF and take a nap.