HOWTO: How to Connect Local Printers to Network Print Shares (152551)
The information in this article applies to:
- Microsoft Win32 Application Programming Interface (API), when used with:
- Microsoft Windows NT Server 3.51
- Microsoft Windows NT Workstation 3.51
This article was previously published under Q152551 SUMMARY
Prior to Windows 95 and Windows NT, network print shares were used in
Windows by connecting MS-DOS devices to network resources. Often, this was
accomplished by the WNetAddConnection function that was implemented by the
underlying network software. This architecture limited the number of
connections to the number of MS-DOS devices that could be redirected.
Further, it suffered from an inherent inflexibility of print job and
printer management.
The current Win32 Application Programming Interface (API) defines a collection of functions known as the Print Spooler API. The Print Spooler API manipulates the Spooler, a component of the operating system that is always running, and manages printers and print jobs both local and remote. The Spooler and its printers are no longer tied to MS-DOS devices for access to network print shares. Any printer in Windows can now be connected (redirected) directly to network print shares by their UNC names.
MORE INFORMATION
Configuring a printer to be redirected to a network print share is a three-
step process: The application first obtains a current PRINTER_INFO_2
structure via the GetPrinter function; the new configuration is then
defined by altering the members of the PRINTER_INFO_2 structure; once modified, the structure is passed to the SetPrinter function that resets the configuration.
To configure a printer to print to a network print share, set the pPortName member of the PRINTER_INFO_2 structure to point to a valid port name string. Windows NT requires the name of the port to be in the list of ports that are returned from the EnumPorts function. On Windows 95, this string may contain the UNC path to a remote network print share or can be from this list of installed ports. Additional ports are defined by calling the AddPort function and specifying the appropriate Port Monitor.
When AddPort is used to set up a new port, a dialog box provided by the Port Monitor appears. There is no way to prevent this dialog box from being
displayed. The Port Monitor uses this dialog box to configure the new port with information specific to that type of port.
Although Windows NT supports the redirection of local printers to network
print shares, the recommended method for printing to a network print share
on Windows NT is a Printer Connection. A Printer Connection is a direct
representation of the network printer resource on the local workstation.
Printing to a Connection involves Remote Procedure Calls (RPC) that offer
many advantages, such as spooling on the Server and Server-supplied printer
drivers. However, Printer Connections currently work only when the client
and server are both Windows NT or if the network specifically supports it.
Microsoft recommends that applications running on Windows NT attempt to
call AddPrinterConnection to define Network Printers to which applications
would print. If AddPrinterConnection fails, applications should then
attempt to use a local printer redirected to the network print share as
this article describes. Use and diagnosis of AddPrinterConnection failures
is beyond the scope of this article.
For more information on the use of AddPrinterConnection and how to install
local printers, please see the following article in the Microsoft Knowledge
Base:
147202
How to Add a Network Printer Connection
Use the following steps to configure a printer with the Print Spooler
functions:
- Use OpenPrinter to obtain a handle to a printer object whose configuration can be modified by the SetPrinter function. For SetPrinter to succeed, the calling process must have administrative privileges and the printer must be opened with PRINTER_ALL_ACCESS.
- Call GetPrinter once to determine the size of a PRINTER_INFO_2 structure for the current configuration by passing zero for the size of the buffer in the cbBuffer parameter, two in the Level parameter, NULL for pPrinter parameter, the handle to the opened printer in the hPrinter parameter and the address of a DWORD in the pcbNeeded parameter. GetPrinter fails and GetLastError returns ERROR_INSUFFICIENT_BUFFER. This is an indication of success, because GetPrinter was asked to return the required buffer size by forcing a failure with too small a buffer. Under these conditions, GetPrinter returns the required buffer size in the pcbNeeded parameter. If GetLastError returns anything other than this return value, it is an indication of an actual error.
- Allocate a buffer of size pcbNeeded and call GetPrinter to retrieve the PRINTER_INFO_2 structure for the current configuration. For this second call, the address of the allocated buffer is passed in the pPrinter
parameter and the size of this buffer is passed in the cbBuffer parameter.
- Update the members of the PRINTER_INFO_2 structure to change the printer's configuration. Generally, the pSecurityDescriptor member of the structure should be set to NULL to avoid changing the security information for the printer. String pointers such as pPortName should simply be assigned the address of the string containing the new value. SetPrinter copies the data from this structure and any strings pointed to by members of this structure.
- Finally, call SetPrinter, passing the handle to the open printer, two for the dwLevel parameter, the address of the buffer containing the modified PRINTER_INFO_2 structure, and zero in the dwCommand parameter. If SetPrinter succeeds, the contents of the PRINTER_INFO_2 structure will have been used to reconfigure the printer. If SetPrinter fails, call GetLastError to determine the cause. A typical reason for the failure of a SetPrinter call is insufficient privileges for the user to change some part of the printer's configuration.
Sample Code
The following code sample demonstrates the calls to GetPrinter and
SetPrinter:
BOOL ConnectToRemotePrinter(char *pszRemotePath, HANDLE hPrinter)
{
PRINTER_INFO_2 *ppi = NULL;
DWORD dwNeeded, dwReturned;
if (!pszRemotePath && lstrlen(pszRemotePath) == 0)
goto Fail;
/*
* Manage Printer's port connections
*/
/* Get the size required for the buffer */
SetLastError(0);
if (!GetPrinter(hPrinter, 2, NULL, 0, &dwNeeded))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Fail;
}
ppi = (PRINTER_INFO_2 *)malloc(dwNeeded);
if (!ppi)
goto Fail;
/* Get a copy of the printer's configuration */
if (!GetPrinter(hPrinter, 2, (LPBYTE)ppi, dwNeeded, &dwReturned))
goto Fail;
/* change the connection */
ppi->pPortName = pszRemotePath;
/* don't set the security information */
ppi->pSecurityDescriptor = NULL;
/* Make it so */
if (!SetPrinter(hPrinter, 2, (LPBYTE)ppi, 0))
goto Fail;
/* cleanup */
free(ppi);
return TRUE;
Fail:
if (ppi)
free(ppi);
return FALSE;
} /* end of function ConnectToRemotePrinter */
Modification Type: | Minor | Last Reviewed: | 3/21/2005 |
---|
Keywords: | kbhowto KB152551 |
---|
|