Changing Printers
4:25 PM 
26 May 1993 

Access folks:

This database contains code and an example form to display how to change
printers at run time.  This was moderately simple, until I was reminded
that it's possible for a single Device line to have multiple printer
ports attached.  That complicated matters a lot.

In any case, this whole thing is based on the following structure:

Type tagDeviceRec
    szDeviceName As String
    szDriverName As String
    szPort As String
End Type

In this structure, I store away the device name, the driver name, and 
the port for every device found in the [Devices] section in Win.INI.
That's where all the possible output options are to be found.  If you
look there, you'll find things like:

HP LaserJet III=HPPCL5MS,LPT1:,LPT2:
WINFAX=WINFAX,COM2:

The code here pulls those out, and puts them into an array of 
tagDeviceRecs as

szDeviceName:		szDriverName:	szPort:
-----------------------------------------------
HP LaserJet III		HPPPCL5MS	LPT1:
HP LaserJet III		HPPPCL5MS	LPT2:
WINFAX			WINFAX		COM2:

To find the current default printer, the code looks in the [Windows] 
section of Win.INI for the line that says something like:

device=xxx,yyy,zzz

xxx == szDeviceName
yyy == szDriverName
zzz == szPort

If you look in the routine sp_PrintNewDevice(), you'll find that the 
code gets the current device (sp_GetCurrentDevice()), stores it away,
sets a new current device (sp_SetCurrentDevice()), does a print job, and
then sets it back.

There are several ways to use the code provided here.  For examples, 
refer to the code in the modSetPrinter module.

sp_PrintNewDevice():
If you know the full information about an output device, you can call
sp_PrintNewDevice() to preserve the old printer, change to the new one,
print, and change back.

sp_FillDeviceList():
If you just want to provide a list of all the current output devices, 
put a list or combo box on the form and use the sp_FillDeviceList()
function as its RowSourceType.

sp_GetDevices():
If you want to fill in the array of tagDeviceRec structures, 
use sp_GetDevices(), passing in an empty array of structures to be filled
in.  The function sp_GetDevices() calls both sp_GetRawDevices() and
sp_FillDeviceArray() for you (see the next two items).

sp_GetRawDevices():
If you want to get the raw list of devices as they appear in Win.INI,
call sp_GetRawDevices() with an empty array of strings to fill in.

sp_FillDeviceArray():
Once you have the array of raw device names, if you want to create 
the array of tagDeviceRecs, then call sp_FillDeviceArray().

sp_GetDeviceInfo():
Given a specific item in the array of raw device names, call 
sp_GetDeviceInfo() to look that name up in the [Devices] section of
Win.INI and return the original name, plus all the text to the right of
the equal sign.  The function sp_FillDeviceArray() calls this function
once for each element in the array of raw device names.

sp_RetrieveDeviceInfo():
Once you've built up the array of tagDeviceRecs for use in your program, 
you can call this function to retrieve output information by index
number.  

sp_GetCurrentDevice():
sp_SetCurrentDevice():
These functions get and set the device= value in the [Windows] 
section of Win.INI.

sp_ExtractString():
sp_TrimNull():
Essential utility functions.


' ================================================================
'      sp_ExtractString()
' ================================================================
' Pull a chunk of a device name out of a line read from WIN.INI.
'
' Actually, this could be done really easily with StrToken()
' that's in STRINGS.DLL, but I didn't want folks to have to
' use a DLL just for this.  If you have it, you might think of
' rewriting this function to use it.  It'd be faster.
'
' Pull tokens out of a comma-delimited list.  szDevice is the
' list, and wPiece tells us which chunk to pull out.
'
' sp_ExtractString("This,is,a,test", 1, ",") == "This"
' sp_ExtractString("This,is,a,test", 2, ",") == "is"
' sp_ExtractString("This,is,a,test", 4, ",") == "test"
' sp_ExtractString("This,is,a,test", 5, ",") == #NULL#
' sp_ExtractString("This is a test", 2, " ") == "is"
'

' ================================================================
'      sp_FillDeviceArray()
' ================================================================
' This function receives an array of strings (aszAllDevices()) in
' a format like:
'
' HP LaserJet III
'
' Its job is to create an array of structures, with entries like:
'
' szDeviceName:     szDriverName:   szPort:
' ===========================================
' HP LaserJet III   HPPCL5MS        LPT1:
' HP LaserJet III   HPPCL5MS        LPT2:
'
' This way, other functions can use this array to figure out
' what to do.

' ================================================================
'      sp_FillDeviceList()
' ================================================================
' Use Access Basic to fill the list of available devices.  This
' function calls sp_GetRawDevices(), which returns the number of
' devices it found.  If it finds none, then the list box will
' just display #Error.

' ================================================================
'      sp_GetCurrentDevice()
' ================================================================
' Get the current device name from WIN.INI.  If you get back the
' default string, then you have an error condition and the function
' returns Null.

' ================================================================
'      sp_GetDeviceInfo()
' ================================================================
' Given a device name (WINFAX, HP LaserJet III, etc.) look
' through the [Devices] section in Win.INI for a match.  If
' one is found, return the matching portion (after the "="
' in Win.INI).  If a match is found, the return value from
' this function might be used in a call to sp_SetDefaultDevice().
' Otherwise, the return value is Null.
'
' If the user has a device installed on multiple ports, then
' this function will return a string like:
'
' HP LaserJet III,HPPCL5MS,LPT1:,LPT2:
'
' so you're really not safe using the output from this function
' in its raw state.  You'll need to use a function like
' sp_FillDeviceArray(), which walks through the list of all the
' devices in Win.INI and builds an array of device/port
' combinations.

' ================================================================
'      sp_GetDevices()
' ================================================================
' This function does the grunt work of getting all the devices
' listed in the [Devices] section in Win.INI and filling an
' array of tagDeviceRecs (which was passed in as a parameter
' to this function) with all the device information.  You might
' call this function from your own app to fill an array with
' device information, whether or not you were going to display
' that list for the user.

' ================================================================
'      sp_GetRawDevices()
' ================================================================
' Fill the global array aszAllDevices() with all the devices found
' in the [devices] section in WIN.INI.

' ================================================================
'      sp_PrintNewDevice()
' ================================================================
' Print the currently selected item to the printer device that
' is supplied as the parameter szDeviceName.  Stores away the
' current default printer, switches to szDeviceName, attempts
' to print, and then switches back to the original device.
'
' Example:
'
'   sp_PrintNewDevice("WINFAX,WINFAX,COM2:")
'
' will print the current document to WinFax Pro and then will
' switch back to the current, default printer.

' ================================================================
'      sp_RetrieveDeviceInfo
' ================================================================
' Given an array index, build up a string in the format
'
' HP LaserJet III,HPPCL5MS,LPT1:
'
' for use elsewhere.

' ================================================================
'      sp_SetCurrentDevice
' ================================================================
' Set the current default printer by changing the value in Win.INI
' in the [Windows] section.  This changes the item found in the
' "device=" line.  The function returns True if it successfully
' changed the value, and False otherwise.

' ================================================================
'      sp_TrimNull()
' ================================================================
' Remove any Nulls that strings returned from the Windows API
' might happen to have embedded.  Don't send this function a
' Null string.  It won't like it.
