windows-nt/Source/XPSP1/NT/ds/nw/svcdlls/nwwks/client/nwspl.c

3213 lines
70 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
nwspl.c
Abstract:
This module contains the Netware print provider.
Author:
Yi-Hsin Sung (yihsins) 15-Apr-1993
Revision History:
Yi-Hsin Sung (yihsins) 15-May-1993
Moved most of the functionality to the server side
Ram Viswanathan (ramv) 09-Aug-1995
Added functionality to Add and Delete Printer.
--*/
#include <stdio.h>
#include <nwclient.h>
#include <winspool.h>
#include <winsplp.h>
#include <ntlsa.h>
#include <nwpkstr.h>
#include <splutil.h>
#include <nwreg.h>
#include <nwspl.h>
#include <nwmisc.h>
#include <winsta.h>
//------------------------------------------------------------------
//
// Local Functions
//
//------------------------------------------------------------------
// now all SKUs have TerminalServer flag. If App Server is enabled, SingleUserTS flag is cleared
#define IsTerminalServer() (BOOLEAN)(!(USER_SHARED_DATA->SuiteMask & (1 << SingleUserTS))) //user mode
DWORD
InitializePortNames(
VOID
);
VOID
NwpGetUserInfo(
LPWSTR *ppszUser,
BOOL *pfGateway
);
DWORD
NwpGetThreadUserInfo(
LPWSTR *ppszUser,
LPWSTR *ppszUserSid
);
DWORD
NwpGetUserNameFromSid(
PSID pUserSid,
LPWSTR *ppszUserName
);
DWORD
NwpGetLogonUserInfo(
LPWSTR *ppszUserSid
);
DWORD
ThreadIsInteractive(
VOID
);
VOID
pFreeAllContexts();
//------------------------------------------------------------------
//
// Global Variables
//
//------------------------------------------------------------------
HMODULE hmodNW = NULL;
BOOL fIsWinnt = FALSE ;
WCHAR *pszRegistryPath = NULL;
WCHAR *pszRegistryPortNames=L"PortNames";
WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 3];
PNWPORT pNwFirstPort = NULL;
CRITICAL_SECTION NwSplSem;
CRITICAL_SECTION NwServiceListCriticalSection; // Used to protect linked
// list of registered services
HANDLE NwServiceListDoneEvent = NULL;// Used to stop local advertise
// threads.
STATIC HANDLE handleDummy; // This is a dummy handle used to
// return to the clients if we have previously
// opened the given printer successfully
// and the netware workstation service is not
// currently available.
STATIC
PRINTPROVIDOR PrintProvidor = { OpenPrinter,
SetJob,
GetJob,
EnumJobs,
AddPrinter, // NOT SUPPORTED
DeletePrinter, // NOT SUPPORTED
SetPrinter,
GetPrinter,
EnumPrinters,
AddPrinterDriver, // NOT SUPPORTED
EnumPrinterDrivers, // NOT SUPPORTED
GetPrinterDriverW, // NOT SUPPORTED
GetPrinterDriverDirectory, // NOT SUPPORTED
DeletePrinterDriver, // NOT SUPPORTED
AddPrintProcessor, // NOT SUPPORTED
EnumPrintProcessors, // NOT SUPPORTED
GetPrintProcessorDirectory, // NOT SUPPORTED
DeletePrintProcessor, // NOT SUPPORTED
EnumPrintProcessorDatatypes,// NOT SUPPORTED
StartDocPrinter,
StartPagePrinter, // NOT SUPPORTED
WritePrinter,
EndPagePrinter, // NOT SUPPORTED
AbortPrinter,
ReadPrinter, // NOT SUPPORTED
EndDocPrinter,
AddJob,
ScheduleJob,
GetPrinterData, // NOT SUPPORTED
SetPrinterData, // NOT SUPPORTED
WaitForPrinterChange,
ClosePrinter,
AddForm, // NOT SUPPORTED
DeleteForm, // NOT SUPPORTED
GetForm, // NOT SUPPORTED
SetForm, // NOT SUPPORTED
EnumForms, // NOT SUPPORTED
EnumMonitors, // NOT SUPPORTED
EnumPorts,
AddPort, // NOT SUPPORTED
ConfigurePort,
DeletePort,
CreatePrinterIC, // NOT SUPPORTED
PlayGdiScriptOnPrinterIC, // NOT SUPPORTED
DeletePrinterIC, // NOT SUPPORTED
AddPrinterConnection, // NOT SUPPORTED
DeletePrinterConnection, // NOT SUPPORTED
PrinterMessageBox, // NOT SUPPORTED
AddMonitor, // NOT SUPPORTED
DeleteMonitor // NOT SUPPORTED
};
//------------------------------------------------------------------
//
// Initialization Functions
//
//------------------------------------------------------------------
BOOL InitializeDll(
HINSTANCE hdll,
DWORD dwReason,
LPVOID lpReserved
)
{
NT_PRODUCT_TYPE ProductType ;
UNREFERENCED_PARAMETER( lpReserved );
if ( dwReason == DLL_PROCESS_ATTACH )
{
DisableThreadLibraryCalls( hdll );
hmodNW = hdll;
//
// are we a winnt machine?
//
fIsWinnt = RtlGetNtProductType(&ProductType) ?
(ProductType == NtProductWinNt) :
FALSE ;
//
// Initialize the critical section for maintaining the registered
// service list
//
InitializeCriticalSection( &NwServiceListCriticalSection );
NwServiceListDoneEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
}
else if ( dwReason == DLL_PROCESS_DETACH )
{
//
// Free up memories used by the port link list
//
DeleteAllPortEntries();
//
// Get rid of Service List and Shutdown SAP library
//
NwTerminateServiceProvider();
#ifndef NT1057
//
// Clean up shell extensions
//
NwCleanupShellExtensions();
#endif
pFreeAllContexts(); // clean up RNR stuff
DeleteCriticalSection( &NwServiceListCriticalSection );
if ( NwServiceListDoneEvent )
{
CloseHandle( NwServiceListDoneEvent );
NwServiceListDoneEvent = NULL;
}
}
return TRUE;
}
DWORD
InitializePortNames(
VOID
)
/*++
Routine Description:
This is called by the InitializePrintProvidor to initialize the ports
names used in this providor.
Arguments:
None.
Return Value:
Returns NO_ERROR or the error that occurred.
--*/
{
DWORD err;
HKEY hkeyPath;
HKEY hkeyPortNames;
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
pszRegistryPath,
0,
KEY_READ,
&hkeyPath );
if ( !err )
{
err = RegOpenKeyEx( hkeyPath,
pszRegistryPortNames,
0,
KEY_READ,
&hkeyPortNames );
if ( !err )
{
DWORD i = 0;
WCHAR Buffer[MAX_PATH];
DWORD BufferSize;
while ( !err )
{
BufferSize = sizeof(Buffer) / sizeof(WCHAR);
err = RegEnumValue( hkeyPortNames,
i,
Buffer,
&BufferSize,
NULL,
NULL,
NULL,
NULL );
if ( !err )
CreatePortEntry( Buffer );
i++;
}
/* We expect RegEnumKeyEx to return ERROR_NO_MORE_ITEMS
* when it gets to the end of the keys, so reset the status:
*/
if( err == ERROR_NO_MORE_ITEMS )
err = NO_ERROR;
RegCloseKey( hkeyPortNames );
}
#if DBG
else
{
IF_DEBUG(PRINT)
KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n",
pszRegistryPortNames, err ));
}
#endif
RegCloseKey( hkeyPath );
}
#if DBG
else
{
IF_DEBUG(PRINT)
KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n",
pszRegistryPath, err ));
}
#endif
return err;
}
//------------------------------------------------------------------
//
// Print Provider Functions supported by NetWare provider
//
//------------------------------------------------------------------
BOOL
InitializePrintProvidor(
LPPRINTPROVIDOR pPrintProvidor,
DWORD cbPrintProvidor,
LPWSTR pszFullRegistryPath
)
/*++
Routine Description:
This is called by the spooler subsystem to initialize the print
providor.
Arguments:
pPrintProvidor - Pointer to the print providor structure to be
filled in by this function
cbPrintProvidor - Count of bytes of the print providor structure
pszFullRegistryPath - Full path to the registry key of this print providor
Return Value:
Always TRUE.
--*/
{
//
// dfergus 20 Apr 2001 #323700
// Prevent Multiple CS Initialization
//
static int iCSInit = 0;
DWORD dwLen;
if ( !pPrintProvidor || !pszFullRegistryPath || !*pszFullRegistryPath )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
memcpy( pPrintProvidor,
&PrintProvidor,
min( sizeof(PRINTPROVIDOR), cbPrintProvidor) );
//
// Store the registry path for this print providor
//
if ( !(pszRegistryPath = AllocNwSplStr(pszFullRegistryPath)) )
return FALSE;
//
// Store the local machine name
//
szMachineName[0] = szMachineName[1] = L'\\';
dwLen = MAX_COMPUTERNAME_LENGTH;
GetComputerName( szMachineName + 2, &dwLen );
#if DBG
IF_DEBUG(PRINT)
{
KdPrint(("NWSPL [InitializePrintProvidor] "));
KdPrint(("RegistryPath = %ws, ComputerName = %ws\n",
pszRegistryPath, szMachineName ));
}
#endif
//
// dfergus 20 Apr 2001 #323700
// Prevent Multiple CS Initialization
//
if( !iCSInit )
{
InitializeCriticalSection( &NwSplSem );
iCSInit = 1;
}
//
// Ignore the error returned from InitializePortNames.
// The provider can still function if we cannot get all the port
// names.
//
InitializePortNames();
return TRUE;
}
BOOL
OpenPrinterW(
LPWSTR pszPrinterName,
LPHANDLE phPrinter,
LPPRINTER_DEFAULTS pDefault
)
/*++
Routine Description:
This routine retrieves a handle identifying the specified printer.
Arguments:
pszPrinterName - Name of the printer
phPrinter - Receives the handle that identifies the given printer
pDefault - Points to a PRINTER_DEFAULTS structure. Can be NULL.
Return Value:
TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for
extended error information.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [OpenPrinter] Name = %ws\n", pszPrinterName ));
#endif
UNREFERENCED_PARAMETER( pDefault );
if ( !pszPrinterName )
{
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
RpcTryExcept
{
err = NwrOpenPrinter( NULL,
pszPrinterName,
PortKnown( pszPrinterName ),
(LPNWWKSTA_PRINTER_CONTEXT) phPrinter );
//
// Make sure there is a port of this name so that
// EnumPorts will return it.
//
if ( !err )
{
if ( !PortExists( pszPrinterName, &err ) && !err )
{
//
// We will ignore the errors since it is
// still OK if we can't add the port.
// Cannot delete once created, don't create
// We should not create port entry and registry entry
if ( CreatePortEntry( pszPrinterName ) )
CreateRegistryEntry( pszPrinterName );
}
}
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
{
if ( PortKnown( pszPrinterName ))
{
*phPrinter = &handleDummy;
err = NO_ERROR;
}
else
{
err = ERROR_INVALID_NAME;
}
}
else
{
err = NwpMapRpcError( code );
}
}
RpcEndExcept
if ( err )
{
SetLastError( err );
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [OpenPrinter] err = %d\n", err));
#endif
}
return ( err == NO_ERROR );
}
BOOL
ClosePrinter(
HANDLE hPrinter
)
/*++
Routine Description:
This routine closes the given printer object.
Arguments:
hPrinter - Handle of the printer object
Return Value:
TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for
extended error information.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [ClosePrinter]\n"));
#endif
//
// Just return success if the handle is a dummy one
//
if ( hPrinter == &handleDummy )
return TRUE;
RpcTryExcept
{
err = NwrClosePrinter( (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
GetPrinter(
HANDLE hPrinter,
DWORD dwLevel,
LPBYTE pbPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded
)
/*++
Routine Description:
The routine retrieves information about the given printer.
Arguments:
hPrinter - Handle of the printer
dwLevel - Specifies the level of the structure to which pbPrinter points.
pbPrinter - Points to a buffer that receives the PRINTER_INFO object.
cbBuf - Size, in bytes of the array pbPrinter points to.
pcbNeeded - Points to a value which specifies the number of bytes copied
if the function succeeds or the number of bytes required if
cbBuf was too small.
Return Value:
TRUE if the function succeeds and FALSE otherwise. GetLastError() can be
used to retrieve extended error information.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [GetPrinter] Level = %d\n", dwLevel ));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && (dwLevel != 3 ))
{
SetLastError( ERROR_INVALID_LEVEL );
return FALSE;
}
RpcTryExcept
{
err = NwrGetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
dwLevel,
pbPrinter,
cbBuf,
pcbNeeded );
if ( !err )
{
if ( dwLevel == 1 )
MarshallUpStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter);
else
MarshallUpStructure( pbPrinter, PrinterInfo2Offsets, pbPrinter);
}
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
SetPrinter(
HANDLE hPrinter,
DWORD dwLevel,
LPBYTE pbPrinter,
DWORD dwCommand
)
/*++
Routine Description:
The routine sets the specified by pausing printing, resuming printing, or
clearing all print jobs.
Arguments:
hPrinter - Handle of the printer
dwLevel - Specifies the level of the structure to which pbPrinter points.
pbPrinter - Points to a buffer that supplies the PRINTER_INFO object.
dwCommand - Specifies the new printer state.
Return Value:
TRUE if the function succeeds and FALSE otherwise. GetLastError() can be
used to retrieve extended error information.
--*/
{
DWORD err = NO_ERROR;
UNREFERENCED_PARAMETER( pbPrinter );
#if DBG
IF_DEBUG(PRINT)
{
KdPrint(( "NWSPL [SetPrinter] Level = %d Command = %d\n",
dwLevel, dwCommand ));
}
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
switch ( dwLevel )
{
case 0:
case 1:
case 2:
case 3:
break;
default:
SetLastError( ERROR_INVALID_LEVEL );
return FALSE;
}
RpcTryExcept
{
err = NwrSetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
dwCommand );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
EnumPrintersW(
DWORD dwFlags,
LPWSTR pszName,
DWORD dwLevel,
LPBYTE pbPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
/*++
Routine Description:
This routine enumerates the available providers, servers, printers
depending on the given pszName.
Arguments:
dwFlags - Printer type requested
pszName - The name of the container object
dwLevel - The structure level requested
pbPrinter - Points to the array to receive the PRINTER_INFO objects
cbBuf - Size, in bytes of pbPrinter
pcbNeeded - Count of bytes needed
pcReturned - Count of PRINTER_INFO objects
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err = NO_ERROR;
#if DBG
IF_DEBUG(PRINT)
{
KdPrint(("NWSPL [EnumPrinters] Flags = %d Level = %d",dwFlags,dwLevel));
if ( pszName )
KdPrint((" PrinterName = %ws\n", pszName ));
else
KdPrint(("\n"));
}
#endif
if ( (dwLevel != 1) && (dwLevel != 2) )
{
SetLastError( ERROR_INVALID_NAME ); // should be level, but winspool
// is silly.
return FALSE;
}
else if ( !pcbNeeded || !pcReturned )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
RpcTryExcept
{
*pcReturned = 0;
*pcbNeeded = 0;
if ( ( dwFlags & PRINTER_ENUM_NAME )
&& ( dwLevel == 1 )
)
{
err = NwrEnumPrinters( NULL,
pszName,
pbPrinter,
cbBuf,
pcbNeeded,
pcReturned );
if ( !err )
{
DWORD i;
for ( i = 0; i < *pcReturned; i++ )
MarshallUpStructure( pbPrinter + i*sizeof(PRINTER_INFO_1W),
PrinterInfo1Offsets,
pbPrinter );
}
}
else
{
err = ERROR_INVALID_NAME;
}
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_NAME;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
//
// Handle structure
// This structure was copied from \nw\svcdlls\nwwks\server\spool.c
// to fix NT bug # 366632.
//
typedef struct _NWSPOOL {
DWORD nSignature; // Signature
DWORD errOpenPrinter; // OpenPrinter API will always return
// success on known printers. This will
// contain the error that we get
// if something went wrong in the API.
PVOID pPrinter; // Points to the corresponding printer
HANDLE hServer; // Opened handle to the server
struct _NWSPOOL *pNextSpool; // Points to the next handle
DWORD nStatus; // Status
DWORD nJobNumber; // StartDocPrinter/AddJob: Job Number
HANDLE hChangeEvent; // WaitForPrinterChange: event to wait on
DWORD nWaitFlags; // WaitForPrinterChange: flags to wait on
DWORD nChangeFlags; // Changes that occurred to the printer
} NWSPOOL, *PNWSPOOL;
DWORD
StartDocPrinter(
HANDLE hPrinter,
DWORD dwLevel,
LPBYTE lpbDocInfo
)
/*++
Routine Description:
This routine informs the print spooler that a document is to be spooled
for printing.
Arguments:
hPrinter - Handle of the printer
dwLevel - Level of the structure pointed to by lpbDocInfo. Must be 1.
lpbDocInfo - Points to the DOC_INFO_1 object
Return Value:
TRUE if the function succeeds, FALSE otherwise. The extended error
can be retrieved through GetLastError().
--*/
{
DWORD err;
DOC_INFO_1 *pDocInfo1 = (DOC_INFO_1 *) lpbDocInfo;
LPWSTR pszUser = NULL;
BOOL fGateway = FALSE;
DWORD PrintOption = NW_GATEWAY_PRINT_OPTION_DEFAULT;
LPWSTR pszPreferredSrv = NULL;
#if DBG
IF_DEBUG(PRINT)
{
KdPrint(( "NWSPL [StartDocPrinter] " ));
if ( pDocInfo1 )
{
if ( pDocInfo1->pDocName )
KdPrint(("Document %ws", pDocInfo1->pDocName ));
if ( pDocInfo1->pOutputFile )
KdPrint(("OutputFile %ws", pDocInfo1->pOutputFile ));
if ( pDocInfo1->pDatatype )
KdPrint(("Datatype %ws", pDocInfo1->pDatatype ));
}
KdPrint(("\n"));
}
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
else if ( dwLevel != 1 )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
// ignore the error, just use default value
NwpGetUserInfo( &pszUser, &fGateway );
if ( !fGateway ) {
NwQueryInfo( &PrintOption, &pszPreferredSrv );
if (pszPreferredSrv) {
LocalFree( pszPreferredSrv );
}
}
RpcTryExcept
{
err = NwrStartDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
pDocInfo1? pDocInfo1->pDocName : NULL,
pszUser,
PrintOption,
fGateway );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
LocalFree( pszUser );
if ( err )
SetLastError( err );
//
// Can't do this, seems to break GSWN printing on multi-homed machines
// Commenting out code change that tries to return the job id.
//
// else
// return ((PNWSPOOL) hPrinter)->nJobNumber;
return err == NO_ERROR;
}
BOOL
WritePrinter(
HANDLE hPrinter,
LPVOID pBuf,
DWORD cbBuf,
LPDWORD pcbWritten
)
/*++
Routine Description:
This routine informs the print spooler that the specified data should be
written to the given printer.
Arguments:
hPrinter - Handle of the printer object
pBuf - Address of array that contains printer data
cbBuf - Size, in bytes of pBuf
pcbWritten - Receives the number of bytes actually written to the printer
Return Value:
TRUE if it succeeds, FALSE otherwise. Use GetLastError() to get extended
error.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [WritePrinter]\n"));
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
#endif
RpcTryExcept
{
err = NwrWritePrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
pBuf,
cbBuf,
pcbWritten );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
AbortPrinter(
HANDLE hPrinter
)
/*++
Routine Description:
This routine deletes a printer's spool file if the printer is configured
for spooling.
Arguments:
hPrinter - Handle of the printer object
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [AbortPrinter]\n"));
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
#endif
RpcTryExcept
{
err = NwrAbortPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
EndDocPrinter(
HANDLE hPrinter
)
/*++
Routine Description:
This routine ends the print job for the given printer.
Arguments:
hPrinter - Handle of the printer object
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [EndDocPrinter]\n"));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
RpcTryExcept
{
err = NwrEndDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
GetJob(
HANDLE hPrinter,
DWORD dwJobId,
DWORD dwLevel,
LPBYTE pbJob,
DWORD cbBuf,
LPDWORD pcbNeeded
)
/*++
Routine Description:
This routine retrieves print-job data for the given printer.
Arguments:
hPrinter - Handle of the printer
dwJobId - Job identifition number
dwLevel - Data structure level of pbJob
pbJob - Address of data-structure array
cbBuf - Count of bytes in array
pcbNeeded - Count of bytes retrieved or required
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [GetJob] JobId = %d Level = %d\n", dwJobId, dwLevel));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
else if (( dwLevel != 1 ) && ( dwLevel != 2 ))
{
SetLastError( ERROR_INVALID_LEVEL );
return FALSE;
}
RpcTryExcept
{
err = NwrGetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
dwJobId,
dwLevel,
pbJob,
cbBuf,
pcbNeeded );
if ( !err )
{
if ( dwLevel == 1 )
MarshallUpStructure( pbJob, JobInfo1Offsets, pbJob );
else
MarshallUpStructure( pbJob, JobInfo2Offsets, pbJob );
}
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
EnumJobs(
HANDLE hPrinter,
DWORD dwFirstJob,
DWORD dwNoJobs,
DWORD dwLevel,
LPBYTE pbJob,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
/*++
Routine Description:
This routine initializes the array of JOB_INFO_1 or JOB_INFO_2 structures
with data describing the specified print jobs for the given printer.
Arguments:
hPrinter - Handle of the printer
dwFirstJob - Location of first job in the printer
dwNoJobs - Number of jobs to enumerate
dwLevel - Data structure level
pbJob - Address of structure array
cbBuf - Size of pbJob, in bytes
pcbNeeded - Receives the number of bytes copied or required
pcReturned - Receives the number of jobs copied
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumJobs] Level = %d FirstJob = %d NoJobs = %d\n",
dwLevel, dwFirstJob, dwNoJobs));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) )
{
SetLastError( ERROR_INVALID_LEVEL );
return FALSE;
}
RpcTryExcept
{
*pcReturned = 0;
*pcbNeeded = 0;
err = NwrEnumJobs( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
dwFirstJob,
dwNoJobs,
dwLevel,
pbJob,
cbBuf,
pcbNeeded,
pcReturned );
if ( !err )
{
DWORD i;
DWORD cbStruct;
DWORD_PTR *pOffsets;
if ( dwLevel == 1 )
{
cbStruct = sizeof( JOB_INFO_1W );
pOffsets = JobInfo1Offsets;
}
else // dwLevel == 2
{
cbStruct = sizeof( JOB_INFO_2W );
pOffsets = JobInfo2Offsets;
}
for ( i = 0; i < *pcReturned; i++ )
MarshallUpStructure( pbJob + i * cbStruct, pOffsets, pbJob );
}
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
SetJob(
HANDLE hPrinter,
DWORD dwJobId,
DWORD dwLevel,
LPBYTE pbJob,
DWORD dwCommand
)
/*++
Routine Description:
This routine pauses, cancels, resumes, restarts the specified print job
in the given printer. The function can also be used to set print job
parameters such as job position, and so on.
Arguments:
hPrinter - Handle of the printer
dwJobId - Job indentification number
dwLevel - Data structure level
pbJob - Address of data structure
dwCommand - Specify the operation to be performed
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
{
KdPrint(("NWSPL [SetJob] Level = %d JobId = %d Command = %d\n",
dwLevel, dwJobId, dwCommand));
}
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) )
{
SetLastError( ERROR_INVALID_LEVEL );
return FALSE;
}
else if ( ( dwLevel == 0 ) && ( pbJob != NULL ) )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
RpcTryExcept
{
NW_JOB_INFO NwJobInfo;
if ( dwLevel == 1 )
{
NwJobInfo.nPosition = ((LPJOB_INFO_1W) pbJob)->Position;
NwJobInfo.pUserName = ((LPJOB_INFO_1W) pbJob)->pUserName;
NwJobInfo.pDocument = ((LPJOB_INFO_1W) pbJob)->pDocument;
}
else if ( dwLevel == 2 )
{
NwJobInfo.nPosition = ((LPJOB_INFO_2W) pbJob)->Position;
NwJobInfo.pUserName = ((LPJOB_INFO_2W) pbJob)->pUserName;
NwJobInfo.pDocument = ((LPJOB_INFO_2W) pbJob)->pDocument;
}
err = NwrSetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
dwJobId,
dwLevel,
dwLevel == 0 ? NULL : &NwJobInfo,
dwCommand );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
AddJob(
HANDLE hPrinter,
DWORD dwLevel,
LPBYTE pbAddJob,
DWORD cbBuf,
LPDWORD pcbNeeded
)
/*++
Routine Description:
This routine returns a full path and filename of a file that can be used
to store a print job.
Arguments:
hPrinter - Handle of the printer
dwLevel - Data structure level
pbAddJob - Points to a ADD_INFO_1 structure
cbBuf - Size of pbAddJob, in bytes
pcbNeeded - Receives the bytes copied or required
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
ADDJOB_INFO_1W TempBuffer;
PADDJOB_INFO_1W OutputBuffer;
DWORD OutputBufferSize;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [AddJob]\n"));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
else if ( dwLevel != 1 )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
//
// The output buffer size must be at least the size of the fixed
// portion of the structure marshalled by RPC or RPC will not
// call the server-side to get the pcbNeeded. Use our own temporary
// buffer to force RPC to call the server-side if output buffer
// specified by the caller is too small.
//
if (cbBuf < sizeof(ADDJOB_INFO_1W)) {
OutputBuffer = &TempBuffer;
OutputBufferSize = sizeof(ADDJOB_INFO_1W);
}
else {
OutputBuffer = (LPADDJOB_INFO_1W) pbAddJob;
OutputBufferSize = cbBuf;
}
RpcTryExcept
{
err = NwrAddJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
OutputBuffer,
OutputBufferSize,
pcbNeeded );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
ScheduleJob(
HANDLE hPrinter,
DWORD dwJobId
)
/*++
Routine Description:
This routine informs the print spooler that the specified job can be
scheduled for spooling.
Arguments:
hPrinter - Handle of the printer
dwJobId - Job number that can be scheduled
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [ScheduleJob] JobId = %d\n", dwJobId ));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return FALSE;
}
RpcTryExcept
{
err = NwrScheduleJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
dwJobId );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
DWORD
WaitForPrinterChange(
HANDLE hPrinter,
DWORD dwFlags
)
/*++
Routine Description:
This function returns when one or more requested changes occur on a
print server or if the function times out.
Arguments:
hPrinter - Handle of the printer to wait on
dwFlags - A bitmask that specifies the changes that the application
wishes to be notified of.
Return Value:
Return a bitmask that indicates the changes that occurred.
--*/
{
DWORD err;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [WaitForPrinterChange] Flags = %d\n", dwFlags));
#endif
if ( hPrinter == &handleDummy )
{
SetLastError( ERROR_NO_NETWORK );
return 0;
}
RpcTryExcept
{
err = NwrWaitForPrinterChange( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
&dwFlags );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if ( err )
{
SetLastError( err );
return 0;
}
return dwFlags;
}
BOOL
EnumPortsW(
LPWSTR pszName,
DWORD dwLevel,
LPBYTE pbPort,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
/*++
Routine Description:
This function enumerates the ports available for printing on a
specified server.
Arguments:
pszName - Name of the server to enumerate on
dwLevel - Structure level
pbPort - Address of array to receive the port information
cbBuf - Size, in bytes, of pbPort
pcbNeeded - Address to store the number of bytes needed or copied
pcReturned - Address to store the number of entries copied
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err = NO_ERROR;
DWORD cb = 0;
PNWPORT pNwPort;
LPPORT_INFO_1W pPortInfo1;
LPBYTE pEnd = pbPort + cbBuf;
LPBYTE pFixedDataEnd = pbPort;
BOOL FitInBuffer;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumPorts]\n"));
#endif
if ( dwLevel != 1 )
{
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
else if ( !IsLocalMachine( pszName ) )
{
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
EnterCriticalSection( &NwSplSem );
pNwPort = pNwFirstPort;
while ( pNwPort )
{
cb += sizeof(PORT_INFO_1W) + ( wcslen( pNwPort->pName)+1)*sizeof(WCHAR);
pNwPort = pNwPort->pNext;
}
*pcbNeeded = cb;
*pcReturned = 0;
if ( cb <= cbBuf )
{
pEnd = pbPort + cbBuf;
pNwPort = pNwFirstPort;
while ( pNwPort )
{
pPortInfo1 = (LPPORT_INFO_1W) pFixedDataEnd;
pFixedDataEnd += sizeof( PORT_INFO_1W );
FitInBuffer = NwlibCopyStringToBuffer( pNwPort->pName,
wcslen( pNwPort->pName),
(LPCWSTR) pFixedDataEnd,
(LPWSTR *) &pEnd,
&pPortInfo1->pName );
ASSERT( FitInBuffer );
pNwPort = pNwPort->pNext;
(*pcReturned)++;
}
}
else
{
err = ERROR_INSUFFICIENT_BUFFER;
}
LeaveCriticalSection( &NwSplSem );
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
DeletePortW(
LPWSTR pszName,
HWND hWnd,
LPWSTR pszPortName
)
/*++
Routine Description:
This routine deletes the port given on the server. A dialog can
be displayed if needed.
Arguments:
pszName - Name of the server for which the port should be deleted
hWnd - Parent window
pszPortName - The name of the port to delete
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD err;
BOOL fPortDeleted;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePort]\n"));
#endif
if ( !IsLocalMachine( pszName ) )
{
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
fPortDeleted = DeletePortEntry( pszPortName );
if ( fPortDeleted )
{
err = DeleteRegistryEntry( pszPortName );
}
else
{
err = ERROR_UNKNOWN_PORT;
}
if ( err )
SetLastError( err );
return err == NO_ERROR;
}
BOOL
ConfigurePortW(
LPWSTR pszName,
HWND hWnd,
LPWSTR pszPortName
)
/*++
Routine Description:
This routine displays the port configuration dialog box
for the given port on the given server.
Arguments:
pszName - Name of the server on which the given port exist
hWnd - Parent window
pszPortName - The name of the port to be configured
Return Value:
TRUE if the function succeeds, FALSE otherwise.
--*/
{
DWORD nCurrentThreadId;
DWORD nWindowThreadId;
WCHAR szCaption[MAX_PATH];
WCHAR szMessage[MAX_PATH];
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [ConfigurePort] PortName = %ws\n", pszPortName));
#endif
if ( !IsLocalMachine( pszName ) )
{
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
else if ( !PortKnown( pszPortName ) )
{
SetLastError( ERROR_UNKNOWN_PORT );
return FALSE;
}
nCurrentThreadId = GetCurrentThreadId();
nWindowThreadId = GetWindowThreadProcessId( hWnd, NULL );
if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, TRUE ))
KdPrint(("[NWSPL] AttachThreadInput failed with %d.\n",GetLastError()));
if ( LoadStringW( hmodNW,
IDS_NETWARE_PRINT_CAPTION,
szCaption,
sizeof( szCaption ) / sizeof( WCHAR )))
{
if ( LoadStringW( hmodNW,
IDS_NOTHING_TO_CONFIGURE,
szMessage,
sizeof( szMessage ) / sizeof( WCHAR )))
{
MessageBox( hWnd, szMessage, szCaption,
MB_OK | MB_ICONINFORMATION );
}
else
{
KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError()));
}
}
else
{
KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError()));
}
if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, FALSE ))
KdPrint(("[NWSPL] DetachThreadInput failed with %d.\n",GetLastError()));
return TRUE;
}
//------------------------------------------------------------------
//
// Print Provider Functions not supported by NetWare provider
//
//------------------------------------------------------------------
BOOL
AddPrinterConnectionW(
LPWSTR pszPrinterName
)
{
#if DBG
IF_DEBUG(PRINT)
{
KdPrint(("NWSPL [AddPrinterConnection] PrinterName = %ws\n",
pszPrinterName));
}
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
EnumMonitorsW(
LPWSTR pszName,
DWORD dwLevel,
LPBYTE pbMonitor,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumMonitors]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
AddPortW(
LPWSTR pszName,
HWND hWnd,
LPWSTR pszMonitorName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddPort]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
HANDLE
AddPrinterW(
LPWSTR pszName,
DWORD dwLevel,
LPBYTE pbPrinter
)
// Creates a print queue on the netware server and returns a handle to it
{
#ifdef NOT_USED
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddPrinterW]\n"));
#endif
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
#else
LPTSTR pszPrinterName = NULL;
LPTSTR pszPServer = NULL;
LPTSTR pszQueue = NULL;
HANDLE hPrinter = NULL;
DWORD err;
PPRINTER_INFO_2 pPrinterInfo;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddPrinterW]\n"));
#endif
pPrinterInfo = (PPRINTER_INFO_2)pbPrinter;
if (dwLevel != 2)
{
err = ERROR_INVALID_PARAMETER;
goto ErrorExit;
}
if (!(pszPrinterName = (LPTSTR)LocalAlloc(LPTR, (wcslen(((PRINTER_INFO_2 *)pbPrinter)->pPrinterName)+1)* sizeof(WCHAR))))
{
err = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
wcscpy(pszPrinterName,pPrinterInfo->pPrinterName);
// PrinterName is the name represented as \\server\share
//The pszPServer parameter could have multiple fields separated by semicolons
if ( ( !ValidateUNCName( pszPrinterName ) )
|| ( (pszQueue = wcschr( pszPrinterName + 2, L'\\')) == NULL )
|| ( pszQueue == (pszPrinterName + 2) )
|| ( *(pszQueue + 1) == L'\0' )
)
{
err = ERROR_INVALID_NAME;
goto ErrorExit;
}
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [AddPrinter] Name = %ws\n",pszPServer));
#endif
if ( pszPrinterName == NULL )
//PrinterName is a mandatory field but not the list of PServers
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [AddPrinter] Printername not supplied\n" ));
#endif
SetLastError( ERROR_INVALID_NAME );
goto ErrorExit;
}
//Check to see if there is a port of the same name
// If so, abort the addprinter operation.
// This code was commented earlier
if (PortExists(pszPrinterName, &err ) && !err )
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [AddPrinter], = %ws; Port exists with same name\n", pszPrinterName ));
#endif
SetLastError(ERROR_ALREADY_ASSIGNED);
goto ErrorExit;
}
// Put all the relevant information into the PRINTER_INFO_2 structure
RpcTryExcept
{
err = NwrAddPrinter ( NULL,
(LPPRINTER_INFO_2W) pPrinterInfo,
(LPNWWKSTA_PRINTER_CONTEXT) &hPrinter
);
if (!err)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(( "NWSPL [AddPrinter] Name = %ws\n", pszPrinterName ));
#endif
goto ErrorExit;
}
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
err = NwpMapRpcError( code );
goto ErrorExit;
}
RpcEndExcept
if ( !pszPrinterName)
(void) LocalFree((HLOCAL)pszPrinterName);
return hPrinter;
ErrorExit:
if ( !pszPrinterName)
(void) LocalFree((HLOCAL)pszPrinterName);
SetLastError( err);
return (HANDLE)0x0;
#endif // #ifdef NOT_USED
}
BOOL
DeletePrinter(
HANDLE hPrinter
)
{
#ifdef NOT_USED
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrinter]\n"));
#endif
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
#else
LPWSTR pszPrinterName = NULL ; // Used to delete entry from registry
DWORD err = NO_ERROR;
DWORD DoesPortExist;
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrinter]\n"));
#endif
pszPrinterName = (LPWSTR)LocalAlloc(LPTR,sizeof(WCHAR)*MAX_PATH);
if(pszPrinterName == NULL)
{
err = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
//
// Just return success if the handle is a dummy one
//
if ( hPrinter == &handleDummy )
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrinter] Dummy handle \n"));
#endif
SetLastError(ERROR_NO_NETWORK);
return FALSE;
}
RpcTryExcept
{
err = NwrDeletePrinter( NULL,
// pszPrinterName,
(LPNWWKSTA_PRINTER_CONTEXT) &hPrinter );
}
RpcExcept(1)
{
DWORD code = RpcExceptionCode();
if ( code == RPC_S_SERVER_UNAVAILABLE )
err = ERROR_INVALID_HANDLE;
else
err = NwpMapRpcError( code );
}
RpcEndExcept
if (!err && PortExists(pszPrinterName, &DoesPortExist) && DoesPortExist)
{
if ( DeleteRegistryEntry (pszPrinterName))
(void) DeletePortEntry(pszPrinterName);
}
if ( err )
SetLastError( err );
return err == NO_ERROR;
#endif // #ifdef NOT_USED
}
BOOL
DeletePrinterConnectionW(
LPWSTR pszName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrinterConnection]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
AddPrinterDriverW(
LPWSTR pszName,
DWORD dwLevel,
LPBYTE pbPrinter
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddPrinterDriver]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
EnumPrinterDriversW(
LPWSTR pszName,
LPWSTR pszEnvironment,
DWORD dwLevel,
LPBYTE pbDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumPrinterDrivers]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
GetPrinterDriverW(
HANDLE hPrinter,
LPWSTR pszEnvironment,
DWORD dwLevel,
LPBYTE pbDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [GetPrinterDriver]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
GetPrinterDriverDirectoryW(
LPWSTR pszName,
LPWSTR pszEnvironment,
DWORD dwLevel,
LPBYTE pbDriverDirectory,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [GetPrinterDriverDirectory]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
DeletePrinterDriverW(
LPWSTR pszName,
LPWSTR pszEnvironment,
LPWSTR pszDriverName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrinterDriver]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
AddPrintProcessorW(
LPWSTR pszName,
LPWSTR pszEnvironment,
LPWSTR pszPathName,
LPWSTR pszPrintProcessorName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddPrintProcessor]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
EnumPrintProcessorsW(
LPWSTR pszName,
LPWSTR pszEnvironment,
DWORD dwLevel,
LPBYTE pbPrintProcessorInfo,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumPrintProcessors]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
EnumPrintProcessorDatatypesW(
LPWSTR pszName,
LPWSTR pszPrintProcessorName,
DWORD dwLevel,
LPBYTE pbDatatypes,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumPrintProcessorDatatypes]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
GetPrintProcessorDirectoryW(
LPWSTR pszName,
LPWSTR pszEnvironment,
DWORD dwLevel,
LPBYTE pbPrintProcessorDirectory,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [GetPrintProcessorDirectory]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
StartPagePrinter(
HANDLE hPrinter
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [StartPagePrinter]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
EndPagePrinter(
HANDLE hPrinter
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EndPagePrinter]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
ReadPrinter(
HANDLE hPrinter,
LPVOID pBuf,
DWORD cbBuf,
LPDWORD pcbRead
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [ReadPrinter]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
DWORD
GetPrinterDataW(
HANDLE hPrinter,
LPWSTR pszValueName,
LPDWORD pdwType,
LPBYTE pbData,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [GetPrinterData]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
DWORD
SetPrinterDataW(
HANDLE hPrinter,
LPWSTR pszValueName,
DWORD dwType,
LPBYTE pbData,
DWORD cbData
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [SetPrinterData]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
AddForm(
HANDLE hPrinter,
DWORD dwLevel,
LPBYTE pbForm
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddForm]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
DeleteFormW(
HANDLE hPrinter,
LPWSTR pszFormName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeleteForm]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
GetFormW(
HANDLE hPrinter,
LPWSTR pszFormName,
DWORD dwLevel,
LPBYTE pbForm,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [GetForm]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
SetFormW(
HANDLE hPrinter,
LPWSTR pszFormName,
DWORD dwLevel,
LPBYTE pbForm
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [SetForm]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
EnumForms(
HANDLE hPrinter,
DWORD dwLevel,
LPBYTE pbForm,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [EnumForms]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
HANDLE
CreatePrinterIC(
HANDLE hPrinter,
LPDEVMODE pDevMode
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [CreatePrinterIC]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
PlayGdiScriptOnPrinterIC(
HANDLE hPrinterIC,
LPBYTE pbIn,
DWORD cbIn,
LPBYTE pbOut,
DWORD cbOut,
DWORD ul
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [PlayGdiScriptOnPrinterIC]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
DeletePrinterIC(
HANDLE hPrinterIC
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrinterIC]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
DWORD
PrinterMessageBoxW(
HANDLE hPrinter,
DWORD dwError,
HWND hWnd,
LPWSTR pszText,
LPWSTR pszCaption,
DWORD dwType
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [PrinterMessageBox]\n"));
#endif
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
AddMonitorW(
LPWSTR pszName,
DWORD dwLevel,
LPBYTE pbMonitorInfo
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [AddMonitor]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
DeleteMonitorW(
LPWSTR pszName,
LPWSTR pszEnvironment,
LPWSTR pszMonitorName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeleteMonitor]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
DeletePrintProcessorW(
LPWSTR pszName,
LPWSTR pszEnvironment,
LPWSTR pszPrintProcessorName
)
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NWSPL [DeletePrintProcessor]\n"));
#endif
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
//------------------------------------------------------------------
//
// Print Provider Miscellaneous Functions
//
//------------------------------------------------------------------
VOID
NwpGetUserInfo(
LPWSTR *ppszUser,
BOOL *pfGateway
)
/*++
Routine Description:
Get the user information of the impersonating client.
Arguments:
ppszUser - A pointer to buffer to store the Unicode string if
the impersonated client's user name can be looked up
successfully. If the conversion was unsuccessful, it points
to NULL.
pfGateway - A pointer to a boolean to store whether the user is
printing through a gateway or not. We assume that
if the user sid and the current logon user sid is not
the same, then the user is printing through gateway.
Else the user is printing locally.
Return Value:
None.
--*/
{
DWORD err;
LPWSTR pszUserSid = NULL;
// LPWSTR pszLogonUserSid = NULL; //Removed for Multi-user code merge
//Terminal Server doesn't user this varible
//There is no single "Logon User" in Terminal Server
//
// If any error occurs while trying to get the username, just
// assume no user name and not gateway printing.
//
*pfGateway = TRUE;
*ppszUser = NULL;
if ( ((err = NwpGetThreadUserInfo( ppszUser, &pszUserSid )) == NO_ERROR)
// && ((err = NwpGetLogonUserInfo( &pszLogonUserSid ))) == NO_ERROR) //Removed from Multi-user code merge
) {
if ( ThreadIsInteractive() ) {
*pfGateway = FALSE;
}
else {
*pfGateway = TRUE;
}
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\nfGateway = %d\n",
*ppszUser, pszUserSid, *pfGateway ));
#endif
// } else {
// if ( _wcsicmp( pszUserSid, pszLogonUserSid ) == 0 ) {
// *pfGateway = FALSE;
// }
//#if DBG
// IF_DEBUG(PRINT)
// KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\nCurrent SID = %ws fGateway = %d\n",
// *ppszUser, pszUserSid, pszLogonUserSid, *pfGateway ));
//#endif
// }
LocalFree( pszUserSid );
}
}
#define SIZE_OF_TOKEN_INFORMATION \
sizeof( TOKEN_USER ) \
+ sizeof( SID ) \
+ sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
DWORD
NwpGetThreadUserInfo(
LPWSTR *ppszUser,
LPWSTR *ppszUserSid
)
/*++
Routine Description:
Get the user name and user sid string of the impersonating client.
Arguments:
ppszUser - A pointer to buffer to store the Unicode string
if the impersonated client's can be looked up. If the
lookup was unsuccessful, it points to NULL.
ppszUserSid - A pointer to buffer to store the string if the impersonated
client's SID can be expanded successfully into unicode string.
If the conversion was unsuccessful, it points to NULL.
Return Value:
The error code.
--*/
{
DWORD err;
HANDLE TokenHandle;
UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
ULONG ReturnLength;
*ppszUser = NULL;
*ppszUserSid = NULL;
// We can use OpenThreadToken because this server thread
// is impersonating a client
if ( !OpenThreadToken( GetCurrentThread(),
TOKEN_READ,
TRUE, /* Open as self */
&TokenHandle ))
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n",
GetLastError()));
#endif
return(GetLastError());
}
// notice that we've allocated enough space for the
// TokenInformation structure. so if we fail, we
// return a NULL pointer indicating failure
if ( !GetTokenInformation( TokenHandle,
TokenUser,
TokenInformation,
sizeof( TokenInformation ),
&ReturnLength ))
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n",
GetLastError()));
#endif
return(GetLastError());
}
CloseHandle( TokenHandle );
// convert the Sid (pointed to by pSid) to its
// equivalent Unicode string representation.
err = NwpGetUserNameFromSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
ppszUser );
err = err? err : NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
ppszUserSid );
if ( err )
{
if ( *ppszUser )
LocalFree( *ppszUser );
if ( *ppszUserSid )
LocalFree( *ppszUserSid );
}
return err;
}
DWORD
NwpGetUserNameFromSid(
PSID pUserSid,
LPWSTR *ppszUserName
)
/*++
Routine Description:
Lookup the user name given the user SID.
Arguments:
pUserSid - Points to the user sid to be looked up
ppszUserName - A pointer to buffer to store the string if the impersonated
client's SID can be expanded successfully into unicode string.
If the conversion was unsuccessful, it points to NULL.
Return Value:
The error code.
--*/
{
NTSTATUS ntstatus;
LSA_HANDLE hlsa;
OBJECT_ATTRIBUTES oa;
SECURITY_QUALITY_OF_SERVICE sqos;
PLSA_REFERENCED_DOMAIN_LIST plsardl = NULL;
PLSA_TRANSLATED_NAME plsatn = NULL;
sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
sqos.ImpersonationLevel = SecurityImpersonation;
sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
sqos.EffectiveOnly = FALSE;
InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
oa.SecurityQualityOfService = &sqos;
ntstatus = LsaOpenPolicy( NULL,
&oa,
POLICY_LOOKUP_NAMES,
&hlsa );
if ( NT_SUCCESS( ntstatus ))
{
ntstatus = LsaLookupSids( hlsa,
1,
&pUserSid,
&plsardl,
&plsatn );
if ( NT_SUCCESS( ntstatus ))
{
UNICODE_STRING *pUnicodeStr = &((*plsatn).Name);
*ppszUserName = LocalAlloc( LMEM_ZEROINIT,
pUnicodeStr->Length+sizeof(WCHAR));
if ( *ppszUserName != NULL )
{
memcpy( *ppszUserName, pUnicodeStr->Buffer, pUnicodeStr->Length );
}
else
{
ntstatus = STATUS_NO_MEMORY;
}
LsaFreeMemory( plsardl );
LsaFreeMemory( plsatn );
}
#if DBG
else
{
KdPrint(("NwpGetUserNameFromSid: LsaLookupSids failed: Error = %d\n",
GetLastError()));
}
#endif
LsaClose( hlsa );
}
#if DBG
else
{
KdPrint(("NwpGetUserNameFromSid: LsaOpenPolicy failed: Error = %d\n",
GetLastError()));
}
#endif
return RtlNtStatusToDosError( ntstatus );
}
DWORD
NwpGetLogonUserInfo(
LPWSTR *ppszUserSid
)
/*++
Routine Description:
Get the logon user sid string from the registry.
Arguments:
ppszUserSid - On return, this points to the current logon user
sid string.
Return Value:
The error code.
--*/
{
DWORD err;
HKEY WkstaKey;
LPWSTR CurrentUser = NULL;
//
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
// \NWCWorkstation\Parameters to get the sid of the CurrentUser
//
err = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
NW_WORKSTATION_REGKEY,
REG_OPTION_NON_VOLATILE,
KEY_READ,
&WkstaKey
);
if ( err == NO_ERROR) {
//
// Read the current user SID string so that we
// know which key is the current user key to open.
//
err = NwReadRegValue(
WkstaKey,
NW_CURRENTUSER_VALUENAME,
&CurrentUser
);
RegCloseKey( WkstaKey );
if ( err == NO_ERROR) {
*ppszUserSid = CurrentUser;
}
}
return(err);
}
#define SIZE_OF_STATISTICS_TOKEN_INFORMATION \
sizeof( TOKEN_STATISTICS )
DWORD
ThreadIsInteractive(
VOID
)
/*++
Routine Description:
Determines if this is an "Interactive" logon thread
Arguments:
none
Return Value:
TRUE - Thread is interactive
FALSE - Thread is not interactive
--*/
{
HANDLE TokenHandle;
UCHAR TokenInformation[ SIZE_OF_STATISTICS_TOKEN_INFORMATION ];
WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
ULONG ReturnLength;
LUID LogonId;
LONG RegError;
HKEY InteractiveLogonKey;
HKEY OneLogonKey;
// We can use OpenThreadToken because this server thread
// is impersonating a client
if ( !OpenThreadToken( GetCurrentThread(),
TOKEN_READ,
TRUE, /* Open as self */
&TokenHandle ))
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("ThreadIsInteractive: OpenThreadToken failed: Error %d\n",
GetLastError()));
#endif
return FALSE;
}
// notice that we've allocated enough space for the
// TokenInformation structure. so if we fail, we
// return a NULL pointer indicating failure
if ( !GetTokenInformation( TokenHandle,
TokenStatistics,
TokenInformation,
sizeof( TokenInformation ),
&ReturnLength ))
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("ThreadIsInteractive: GetTokenInformation failed: Error %d\n",
GetLastError()));
#endif
return FALSE;
}
CloseHandle( TokenHandle );
LogonId = ((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId;
RegError = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
NW_INTERACTIVE_LOGON_REGKEY,
REG_OPTION_NON_VOLATILE,
KEY_READ,
&InteractiveLogonKey
);
if (RegError != ERROR_SUCCESS) {
#if DBG
IF_DEBUG(PRINT)
KdPrint(("ThreadIsInteractive: RegOpenKeyExW failed: Error %d\n",
GetLastError()));
#endif
return FALSE;
}
NwLuidToWStr(&LogonId, LogonIdKeyName);
//
// Open the <LogonIdKeyName> key under Logon
//
RegError = RegOpenKeyExW(
InteractiveLogonKey,
LogonIdKeyName,
REG_OPTION_NON_VOLATILE,
KEY_READ,
&OneLogonKey
);
if ( RegError == ERROR_SUCCESS ) {
(void) RegCloseKey(OneLogonKey);
(void) RegCloseKey(InteractiveLogonKey);
return TRUE; /* We found it */
}
else {
(void) RegCloseKey(InteractiveLogonKey);
return FALSE; /* We did not find it */
}
}
DWORD
NwpCitrixGetUserInfo(
LPWSTR *ppszUserSid
)
/*++
Routine Description:
Get the user sid string of the client.
Arguments:
ppszUserSid - A pointer to buffer to store the string.
Return Value:
The error code.
--*/
{
DWORD err;
HANDLE TokenHandle;
UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
ULONG ReturnLength;
*ppszUserSid = NULL;
// We can use OpenThreadToken because this server thread
// is impersonating a client
if ( !OpenThreadToken( GetCurrentThread(),
TOKEN_READ,
TRUE, /* Open as self */
&TokenHandle ))
{
err = GetLastError();
if ( err == ERROR_NO_TOKEN ) {
if ( !OpenProcessToken( GetCurrentProcess(),
TOKEN_READ,
&TokenHandle )) {
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n",
GetLastError()));
#endif
return(GetLastError());
}
}
else
return( err );
}
// notice that we've allocated enough space for the
// TokenInformation structure. so if we fail, we
// return a NULL pointer indicating failure
if ( !GetTokenInformation( TokenHandle,
TokenUser,
TokenInformation,
sizeof( TokenInformation ),
&ReturnLength ))
{
#if DBG
IF_DEBUG(PRINT)
KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n",
GetLastError()));
#endif
return(GetLastError());
}
CloseHandle( TokenHandle );
// convert the Sid (pointed to by pSid) to its
// equivalent Unicode string representation.
err = NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
ppszUserSid );
if ( err )
{
if ( *ppszUserSid )
LocalFree( *ppszUserSid );
}
return err;
}