summaryrefslogtreecommitdiffstats
path: root/private/net/dosprint
diff options
context:
space:
mode:
Diffstat (limited to 'private/net/dosprint')
-rw-r--r--private/net/dosprint/dosprint.c1363
-rw-r--r--private/net/dosprint/dosprtp.c440
-rw-r--r--private/net/dosprint/dosprtw.c2284
-rw-r--r--private/net/dosprint/dosspool.c614
-rw-r--r--private/net/dosprint/dosspool.h125
-rw-r--r--private/net/dosprint/makefile6
-rw-r--r--private/net/dosprint/myspool.h125
-rw-r--r--private/net/dosprint/sources47
8 files changed, 5004 insertions, 0 deletions
diff --git a/private/net/dosprint/dosprint.c b/private/net/dosprint/dosprint.c
new file mode 100644
index 000000000..0a9eb2ca1
--- /dev/null
+++ b/private/net/dosprint/dosprint.c
@@ -0,0 +1,1363 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ dosprint.c
+
+Abstract:
+
+ This module provides the ANSI mapping layer from the old DosPrint APIs to
+ the new all singing all dancing beautiful Print APIs. (The UNICODE mapping
+ layer is in DosPrtW.c in this directory.)
+
+Author:
+
+ Dave Snipp (DaveSn) 26-Apr-1991
+
+Revision History:
+
+ 09-Jul-1992 JohnRo
+ RAID 10324: net print vs. UNICODE.
+ Fixed many wrong error codes.
+ Use PREFIX_ equates.
+ Use offsetof() as provided by implmentation, not our own (nonportable).
+ Made changes suggested by PC-LINT, including one bug fix.
+ 03-Oct-1992 JohnRo
+ RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124. (4&5 too.)
+ RAID 8333: view printer queues hangs DOS LM enh client.
+ Make sure data type in job level 1 is null terminated.
+ Fixed job submitted times.
+ Fixed DosPrintQEnumA level 5 array bug.
+ Fixed DosPrintJobEnumA levels 2 and 3.
+ Also implemented DosPrintJobGetInfo levels 0, 1, and 3.
+ Fixed bug calling OpenPrinter with wrong char set here and there.
+ Fixed job comment field (was set to document by mistake).
+ Fixed error code if GlobalAlloc fails.
+ Avoid compiler warnings due to new winspool.h.
+ 04-Dec-1992 JohnRo
+ RAID 1661: downlevel to NT DosPrintDestEnum not supported.
+ Added code to track down empty queue name.
+ Quiet normal debug output.
+ Avoid const vs. volatile compiler warnings.
+ Avoid new compiler warnings.
+ Made changes suggested by PC-LINT 5.0
+ 08-Feb-1993 JohnRo
+ RAID 10164: Data misalignment error during XsDosPrintQGetInfo().
+ 22-Mar-1993 JohnRo
+ RAID 2974: NET PRINT says NT printer is held when it isn't.
+ DosPrint API cleanup: reduced this file to just ANSI wrappers.
+ Made more changes suggested by PC-LINT 5.0
+ Added some IN and OUT keywords.
+ Clarified many debug messages.
+ 07-Apr-1993 JohnRo
+ RAID 5670: "NET PRINT \\server\share" gives err 124 (bad level) on NT.
+ 11-May-1993 JohnRo
+ RAID 9942: workaround Windows For Workgroups (WFW) bug in DosPrintQEnum.
+ Also fixed "NET PRINT \\server\share" and "NET SHARE printshare /DEL"
+ GP faults.
+
+--*/
+
+
+#define NOMINMAX
+#define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
+#include <windows.h>
+
+#include <lmcons.h>
+
+#include <dosprint.h> // My prototypes.
+#include <dosprtp.h> // IF_DEBUG(), some of my prototypes.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <netdebug.h> // DBGSTATIC, NetpKdPrint(()), etc.
+#include <prefix.h> // PREFIX_ equates.
+#include <stddef.h> // offsetof().
+#include <string.h> // memcpy(), strncpy().
+#include <tstring.h> // NetpAlloc{type}From{type}.
+#include <winerror.h> // NO_ERROR, ERROR_ equates.
+
+
+#define MAX_WORD ( (WORD) (~0) )
+
+
+SPLERR SPLENTRY DosPrintQGetInfoA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PUSHORT pcbNeeded
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ USHORT cbNeeded;
+ LPWSTR QueueNameW = NULL;
+ LPWSTR ServerNameW = NULL;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQGetInfoA(%s, %s, %d, %x, %d, %x)\n",
+ (pszServer!=NULL) ? pszServer : "(local)",
+ (pszQueueName!=NULL) ? pszQueueName : "(missing)",
+ uLevel,
+ pbBuf,
+ cbBuf,
+ pcbNeeded));
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBuf * sizeof(WCHAR),
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ //
+ // Process the API (locally or remotely) and get results (with
+ // UNICODE strings).
+ //
+ rc = DosPrintQGetInfoW(
+ ServerNameW,
+ QueueNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ (PUSHORT) &cbNeeded);
+ *pcbNeeded = cbNeeded; // BUGBUG: really?
+
+ //
+ // Convert results back from UNICODE.
+ //
+ if (rc == NO_ERROR) {
+ LPBYTE StringAreaA = (LPBYTE)pbBuf + cbBuf;
+
+ // Translate UNICODE strings back to ANSI.
+ rc = NetpConvertPrintQCharSet(
+ uLevel,
+ FALSE, // not add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ FALSE, // no, don't convert to UNICODE.
+ & StringAreaA ); // conv strings and update ptr
+
+ if (rc == ERROR_MORE_DATA)
+ {
+ *pcbNeeded = (USHORT)cbBufW ; // Unicode call succeeded but no room to go
+ // Ansi. we know the Unicode buffer size is
+ // definitely good enough. This is temporary
+ // fix.
+ }
+ }
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return rc;
+}
+
+
+SPLERR SPLENTRY DosPrintJobGetInfoA(
+ IN LPSTR pszServer OPTIONAL,
+ IN WORD uJobId,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PUSHORT pcbNeeded
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ USHORT cbNeeded;
+ LPWSTR ServerNameW = NULL;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintJobGetInfoA(" FORMAT_LPSTR ", %d, %d, %x, %d, %x)\n",
+ pszServer ? pszServer : "(local)",
+ uJobId,
+ uLevel,
+ pbBuf,
+ cbBuf,
+ pcbNeeded));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ // Process the API (local or remote) and get results (with UNICODE strings).
+ rc = DosPrintJobGetInfoW(
+ ServerNameW,
+ uJobId,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ &cbNeeded);
+ *pcbNeeded = cbNeeded; // BUGBUG: is this right?
+
+ if (rc == NO_ERROR) {
+ LPBYTE StringAreaA = (LPBYTE)pbBuf + cbBuf;
+
+ // Translate UNICODE strings back to ANSI.
+ rc = NetpConvertPrintJobCharSet(
+ uLevel,
+ FALSE, // not add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ FALSE, // no, don't convert to UNICODE.
+ & StringAreaA ); // conv strings and update ptr
+ }
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintJobDelA(
+ LPSTR pszServer,
+ WORD uJobId
+)
+{
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobDelA...\n" ));
+ }
+
+ rc = DosPrintJobDelW( ServerNameW, uJobId );
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintJobContinueA(
+ LPSTR pszServer,
+ WORD uJobId
+)
+{
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ }
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobContinueA(%d)\n", uJobId));
+ }
+
+ rc = DosPrintJobContinueW( ServerNameW, uJobId );
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintJobPauseA(
+ IN LPSTR pszServer,
+ IN WORD uJobId
+ )
+{
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ }
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintJobPauseA(" FORMAT_LPSTR ", %d)\n",
+ pszServer ? pszServer : "(local)",
+ uJobId));
+ }
+
+ rc = DosPrintJobPauseW( ServerNameW, uJobId );
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+
+ return rc;
+}
+
+SPLERR SPLENTRY DosPrintJobEnumA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PWORD pcReturned,
+ OUT PWORD pcTotal
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ LPWSTR QueueNameW = NULL;
+ LPWSTR ServerNameW = NULL;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintJobEnumA(" FORMAT_LPSTR ", %s, %d, %x, %d, %x, %x)\n",
+ pszServer ? pszServer : "(local)",
+ pszQueueName, uLevel, pbBuf, cbBuf, pcReturned, pcTotal));
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ // Process API (local/remote), get UNICODE results.
+ rc = DosPrintJobEnumW(
+ ServerNameW,
+ QueueNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ pcReturned,
+ pcTotal);
+
+ if (rc == NO_ERROR) {
+ LPBYTE StringAreaA = (LPBYTE)pbBuf + cbBuf;
+
+ // Translate UNICODE strings back to ANSI.
+ rc = NetpConvertPrintJobArrayCharSet(
+ uLevel,
+ FALSE, // not add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ FALSE, // no, don't convert to UNICODE.
+ & StringAreaA, // conv strings and update ptr
+ (DWORD) (*pcTotal) );
+ }
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+
+ return (rc);
+}
+
+
+SPLERR SPLENTRY
+DosPrintDestEnumA(
+ IN LPSTR pszServer OPTIONAL,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PUSHORT pcReturned,
+ OUT PUSHORT pcTotal
+ )
+{
+ DWORD cbBufW;
+ WORD cReturned, cTotal;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintDestEnumA(" FORMAT_LPSTR ", %d, %x, %d, %x, %x)\n",
+ (pszServer!=NULL) ? pszServer : "(local)",
+ uLevel, pbBuf, cbBuf, pcReturned, pcTotal));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ // Invoke wide-char version of API, which will do local or downlevel for us.
+ rc = DosPrintDestEnumW(
+ ServerNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ &cReturned,
+ &cTotal);
+ *pcReturned = (USHORT)cReturned;
+ *pcTotal = (USHORT)cTotal;
+
+ // Convert from wide chars for caller.
+ if (rc == NO_ERROR) {
+ LPBYTE StringAreaA = (LPBYTE)pbBuf + cbBuf;
+
+ // Translate UNICODE strings back to ANSI.
+ rc = NetpConvertPrintDestArrayCharSet(
+ uLevel,
+ FALSE, // not add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ FALSE, // no, don't convert to UNICODE.
+ & StringAreaA, // conv strings and update ptr
+ cTotal );
+ }
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintDestControlA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszDevName,
+ IN WORD uControl
+ )
+{
+ LPWSTR DestNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintDestEnumA(" FORMAT_LPSTR ", %s, %d)\n",
+ pszServer ? pszServer : "(local)",
+ pszDevName, uControl));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ DestNameW = NetpAllocWStrFromStr( pszDevName );
+ if (DestNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ rc = DosPrintDestControlW(ServerNameW, DestNameW, uControl);
+
+Cleanup:
+ if (DestNameW != NULL) {
+ (VOID) NetApiBufferFree( DestNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ return (rc);
+
+} // DosPrintDestControlA
+
+
+SPLERR SPLENTRY DosPrintDestGetInfoA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszName,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PUSHORT pcbNeeded
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ LPWSTR DestNameW = NULL;
+ LPWSTR ServerNameW = NULL;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintDestGetInfoA(" FORMAT_LPSTR ", %s, %d, %x, %d, %x)\n",
+ pszServer ? pszServer : "(local)",
+ pszName,
+ uLevel,
+ pbBuf,
+ cbBuf,
+ pcbNeeded));
+ }
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ DestNameW = NetpAllocWStrFromStr( pszName );
+ if (DestNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ // Process the API (local or remote) and get results (with UNICODE strings).
+ rc = DosPrintDestGetInfoW(
+ ServerNameW,
+ DestNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ pcbNeeded); // BUGBUG:wrong value returned here?
+
+ if (rc == NO_ERROR) { // BUGBUG: ERROR_MORE_DATA?
+ LPBYTE StringAreaA = (LPBYTE)pbBuf + cbBuf;
+
+ // Translate UNICODE strings back to ANSI.
+ rc = NetpConvertPrintDestCharSet(
+ uLevel,
+ FALSE, // not add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ FALSE, // no, don't convert to UNICODE.
+ & StringAreaA ); // conv strings and update ptr
+ }
+
+Cleanup:
+ if (DestNameW != NULL) {
+ (VOID) NetApiBufferFree( DestNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintDestAddA(
+ IN LPSTR pszServer OPTIONAL,
+ IN WORD uLevel,
+ IN PBYTE pbBuf,
+ IN WORD cbBuf
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPBYTE StringAreaW;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintDestAddA(" FORMAT_LPSTR ", %d, %x, %d)\n",
+ pszServer ? pszServer : "(local)",
+ uLevel, pbBuf, cbBuf));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ StringAreaW = (LPBYTE)TempBufferW + cbBufW;
+
+ rc = NetpConvertPrintDestCharSet(
+ uLevel,
+ TRUE, // yes, is add or setinfo API
+ pbBuf, // from info
+ TempBufferW, // to info
+ TRUE, // yes, convert to UNICODE.
+ & StringAreaW ); // conv strings and update ptr
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ rc = DosPrintDestAddW(
+ ServerNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW);
+
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+
+SPLERR SPLENTRY DosPrintDestSetInfoA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszName,
+ IN WORD uLevel,
+ IN PBYTE pbBuf,
+ IN WORD cbBuf,
+ IN WORD uParmNum
+ )
+{
+ DWORD cbBufW;
+ LPWSTR DestNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPBYTE StringAreaW;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintDestSetInfoA(" FORMAT_LPSTR ", %s, %d, %x, %d, %d)\n",
+ pszServer ? pszServer : "(local)",
+ pszName,
+ uLevel,
+ pbBuf,
+ cbBuf,
+ uParmNum));
+ }
+
+ if (pszServer && *pszServer) {
+
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ DestNameW = NetpAllocWStrFromStr( pszName );
+ if (DestNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ StringAreaW = (LPBYTE)TempBufferW + cbBufW;
+
+ rc = NetpConvertPrintDestCharSet(
+ uLevel,
+ TRUE, // yes, is add or setinfo API
+ pbBuf, // from info
+ TempBufferW, // to info
+ TRUE, // yes, convert to UNICODE.
+ & StringAreaW ); // conv strings and update ptr
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ rc = DosPrintDestSetInfoW(
+ ServerNameW,
+ DestNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ uParmNum);
+
+Cleanup:
+ if (DestNameW != NULL) {
+ (VOID) NetApiBufferFree( DestNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintDestDelA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszPrinterName
+ )
+{
+ LPWSTR PrinterNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintDestDelA(" FORMAT_LPSTR ", %s)\n",
+ pszServer ? pszServer : "(local)",
+ pszPrinterName));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ PrinterNameW = NetpAllocWStrFromStr( pszPrinterName );
+ if (PrinterNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ rc = DosPrintDestDelW(
+ ServerNameW,
+ PrinterNameW);
+
+Cleanup:
+ if (PrinterNameW != NULL) {
+ (VOID) NetApiBufferFree( PrinterNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQEnumA(
+ IN LPSTR pszServer OPTIONAL,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PUSHORT pcReturned,
+ OUT PUSHORT pcTotal
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPVOID TempBufferW = NULL; // queue structure with UNICODE strings.
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQEnumA(" FORMAT_LPSTR ", %d, %x, %d, %x, %x)\n",
+ pszServer ? pszServer : "(local)",
+ uLevel, pbBuf, cbBuf, pcReturned, pcTotal));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ // Process local/remote, get UNICODE results.
+ rc = DosPrintQEnumW(
+ ServerNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ pcReturned,
+ pcTotal);
+
+ // Convert back to UNICODE.
+ if (rc == NO_ERROR) {
+ LPBYTE StringAreaA = (LPBYTE)pbBuf + cbBuf;
+ rc = (DWORD) NetpConvertPrintQArrayCharSet(
+ uLevel,
+ FALSE, // not add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ FALSE, // no, not converting to UNICODE
+ &StringAreaA, // string area; update ptr
+ *pcReturned ); // Q count
+
+ }
+
+
+Cleanup:
+
+#if DBG
+ IF_DEBUG( DOSPRINT ) {
+ if (rc == NO_ERROR) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQEnumA: returning array:\n" ));
+ NetpDbgDisplayPrintQArray(
+ uLevel,
+ pbBuf,
+ *pcReturned,
+ FALSE );
+ }
+ }
+#endif
+
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+
+
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQSetInfoA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName,
+ IN WORD uLevel,
+ IN PBYTE pbBuf,
+ IN WORD cbBuf,
+ IN WORD uParmNum
+ )
+{
+ DWORD cbBufW;
+ LPWSTR QueueNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPBYTE StringAreaW;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQSetInfoA(" FORMAT_LPSTR ", %s, %d, %x, %d, %d)\n",
+ pszServer ? pszServer : "(local)",
+ pszQueueName, uLevel, pbBuf, cbBuf, uParmNum));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ StringAreaW = (LPBYTE)TempBufferW + cbBufW;
+
+ rc = NetpConvertPrintQCharSet(
+ uLevel,
+ TRUE, // yes, is add or setinfo API
+ pbBuf, // from info
+ TempBufferW, // to info
+ TRUE, // yes, convert to UNICODE.
+ & StringAreaW ); // conv strings and update ptr
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ rc = DosPrintQSetInfoW(
+ ServerNameW,
+ QueueNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ uParmNum);
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQPauseA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName
+ )
+{
+ LPWSTR QueueNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQPauseA(" FORMAT_LPSTR ", %s)\n",
+ pszServer ? pszServer : "(local)",
+ pszQueueName));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ rc = DosPrintQPauseW(ServerNameW, QueueNameW);
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQContinueA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName
+ )
+{
+ LPWSTR QueueNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQContinueA(" FORMAT_LPSTR ", %s)\n",
+ pszServer ? pszServer : "(local)",
+ pszQueueName));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ rc = DosPrintQContinueW( ServerNameW, QueueNameW );
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQPurgeA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName
+ )
+{
+ LPWSTR QueueNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQPurgeA(" FORMAT_LPSTR ", %s)\n",
+ pszServer ? pszServer : "(local)",
+ pszQueueName));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ rc = DosPrintQPurgeW(ServerNameW, QueueNameW);
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQAddA(
+ IN LPSTR pszServer OPTIONAL,
+ IN WORD uLevel,
+ IN PBYTE pbBuf,
+ IN WORD cbBuf
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPBYTE StringAreaW;
+ LPVOID TempBufferW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQAddA(" FORMAT_LPSTR ", %d, %x, %d)\n",
+ pszServer ? pszServer : "(local)",
+ uLevel, pbBuf, cbBuf));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ StringAreaW = (LPBYTE)TempBufferW + cbBufW;
+
+ rc = NetpConvertPrintQCharSet(
+ uLevel,
+ TRUE, // yes, is add or setinfo API
+ pbBuf, // from info
+ TempBufferW, // to info
+ TRUE, // yes, convert to UNICODE.
+ & StringAreaW ); // conv strings and update ptr
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ rc = DosPrintQAddW(
+ ServerNameW,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW );
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQDelA(
+ IN LPSTR pszServer OPTIONAL,
+ IN LPSTR pszQueueName
+ )
+{
+ LPWSTR QueueNameW = NULL;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQDelA(" FORMAT_LPSTR " , %s)\n",
+ pszServer ? pszServer : "(local)",
+ pszQueueName));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ QueueNameW = NetpAllocWStrFromStr( pszQueueName );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ rc = DosPrintQDelW(ServerNameW, QueueNameW);
+
+Cleanup:
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintJobSetInfoA(
+ IN LPSTR pszServer OPTIONAL,
+ IN WORD uJobId,
+ IN WORD uLevel,
+ IN PBYTE pbBuf,
+ IN WORD cbBuf,
+ IN WORD uParmNum
+ )
+{
+ DWORD cbBufW;
+ DWORD rc;
+ LPWSTR ServerNameW = NULL;
+ LPBYTE StringAreaW;
+ LPVOID TempBufferW = NULL; // job structure with UNICODE strings.
+
+ IF_DEBUG( DOSPRINT ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintJobSetInfoA(" FORMAT_LPSTR ":, %d, %d, %x, %d, %d)\n",
+ pszServer ? pszServer : "(local)",
+ uJobId,
+ uLevel,
+ pbBuf,
+ cbBuf,
+ uParmNum));
+ }
+
+ if (pszServer && *pszServer) {
+ ServerNameW = NetpAllocWStrFromStr( pszServer );
+ if (ServerNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ }
+
+ // Compute wide buff size.
+ cbBufW = cbBuf * sizeof(WCHAR);
+ if ( cbBufW > (DWORD) MAX_WORD ) {
+ cbBufW = (DWORD) MAX_WORD;
+ }
+
+ rc = NetApiBufferAllocate(
+ cbBufW,
+ (LPVOID *) (LPVOID) &TempBufferW );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ StringAreaW = (LPBYTE)TempBufferW + cbBufW;
+
+ // Translate ANSI strings to UNICODE.
+ rc = NetpConvertPrintJobCharSet(
+ uLevel,
+ TRUE, // yes, is add or setinfo API
+ TempBufferW, // from info
+ pbBuf, // to info
+ TRUE, // yes, convert to UNICODE.
+ & StringAreaW ); // conv strings and update ptr
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ // Process the actual API.
+ rc = DosPrintJobSetInfoW(
+ ServerNameW,
+ uJobId,
+ uLevel,
+ TempBufferW,
+ (WORD) cbBufW,
+ uParmNum);
+
+Cleanup:
+ if (ServerNameW != NULL) {
+ (VOID) NetApiBufferFree( ServerNameW );
+ }
+ if (TempBufferW != NULL) {
+ (VOID) NetApiBufferFree( TempBufferW );
+ }
+ return (rc);
+}
+
diff --git a/private/net/dosprint/dosprtp.c b/private/net/dosprint/dosprtp.c
new file mode 100644
index 000000000..aa41d0daf
--- /dev/null
+++ b/private/net/dosprint/dosprtp.c
@@ -0,0 +1,440 @@
+/*++
+
+Copyright (c) 1992-1993 Microsoft Corporation
+
+Module Name:
+
+ DosPrtP.c
+
+Abstract:
+
+ This contains macros and prototypes private to the DosPrint APIs.
+
+Author:
+
+ John Rogers (JohnRo) 02-Oct-1992
+
+Notes:
+
+Revision History:
+
+ 02-Oct-1992 JohnRo
+ Created for RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124.
+ (4&5 too.)
+ 08-Feb-1993 JohnRo
+ RAID 10164: Data misalignment error during XsDosPrintQGetInfo().
+ DosPrint API cleanup: avoid const vs. volatile compiler warnings.
+ Extracted job count routine to netlib for use by convprt.c stuff.
+ Added some IN and OUT keywords.
+ 24-Mar-1993 JohnRo
+ RAID 2974: NET PRINT says NT printer is held when it isn't.
+ 17-May-1993 JohnRo
+ FindLocalJob() should use INVALID_HANDLE_VALUE for consistentcy.
+ Use NetpKdPrint() where possible.
+ 29-Mar-1995 AlbertT
+ Support for pause/resume/purge printer queue added.
+
+--*/
+
+
+#ifndef UNICODE
+#error "RxPrint APIs assume RxRemoteApi uses wide characters."
+#endif
+
+#define NOMINMAX
+#define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
+#include <windows.h>
+
+#include <lmcons.h> // NET_API_STATUS.
+#include <netdebug.h> // NetpKdPrint(), etc.
+
+#ifdef _WINSPOOL_
+#error "Include of winspool.h moved, make sure it doesn't get UNICODE."
+#endif
+
+#undef UNICODE
+#include <winspool.h>
+#define UNICODE
+
+#ifndef _WINSPOOL_
+#error "Oops, winspool.h changed, make sure this code is still OK."
+#endif
+
+
+#include <dosprtp.h> // IF_DEBUG(), some of my prototypes.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <lmerr.h> // NO_ERROR, NERR_, and ERROR_ equates.
+#include <lmshare.h> // SHARE_INFO_2, STYPE_ equates, etc.
+#include <prefix.h> // PREFIX_ equates.
+#include <rxprint.h> // PPRQINFOW, etc.
+#include <string.h> // strrchr().
+#include <tstring.h> // NetpAlloc{type}From{type}.
+#include <wchar.h> // wscrchr().
+#include "myspool.h"
+
+NET_API_STATUS
+CommandALocalPrinterW(
+ IN LPWSTR PrinterName,
+ IN DWORD Command // PRINTER_CONTROL_PAUSE, etc.
+ )
+{
+ NET_API_STATUS ApiStatus;
+ HANDLE PrinterHandle = INVALID_HANDLE_VALUE;
+ PRINTER_DEFAULTSW pd = { NULL, NULL, PRINTER_ACCESS_ADMINISTER };
+
+ IF_DEBUG( DOSPRTP ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CommandALocalPrinterW: issuing command " FORMAT_DWORD
+ " for printer " FORMAT_LPWSTR ".\n", Command, PrinterName ));
+ }
+
+ if ( !MyOpenPrinterW(PrinterName, &PrinterHandle, &pd)) {
+ ApiStatus = GetLastError();
+ goto Cleanup;
+ }
+
+ if ( !MySetPrinterW(
+ PrinterHandle,
+ 0, // info level
+ NULL, // no job structure
+ Command) ) {
+
+ ApiStatus = GetLastError();
+
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CommandALocalPrinterW: FAILED COMMAND " FORMAT_DWORD
+ " for printer " FORMAT_LPWSTR ", api status " FORMAT_API_STATUS
+ ".\n", Command, PrinterName, ApiStatus ));
+
+ goto Cleanup;
+
+ } else {
+ ApiStatus = NO_ERROR;
+ }
+
+
+Cleanup:
+ if (PrinterHandle != INVALID_HANDLE_VALUE) {
+ (VOID) MyClosePrinter(PrinterHandle);
+ }
+
+ IF_DEBUG( DOSPRTP ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CommandALocalPrinterW: returning api status "
+ FORMAT_API_STATUS ".\n", ApiStatus ));
+ }
+ return (ApiStatus);
+
+} // CommandALocalPrinterW
+
+
+NET_API_STATUS
+CommandALocalJob(
+ IN HANDLE PrinterHandle, OPTIONAL
+ IN DWORD JobId,
+ IN DWORD Level,
+ IN LPBYTE pJob,
+ IN DWORD Command // JOB_CONTROL_PAUSE, etc.
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a command to a Job based on a JobId. If a PrintHandle
+ is passed in, it is used; otherwise a temporary one is opened
+ and used instead.
+
+ This is the Ansi version.
+
+Arguments:
+
+ PrinterHandle - Print handle to use, may be NULL
+
+ JobId - Job that should be modified
+
+ Level - Specifies pJob info level
+
+ pJob - Information to set about job, level specified by Level
+
+ Command - Command to execute on job
+
+Return Value:
+
+ Return code, may be a win32 error code (!?)
+
+--*/
+
+{
+ NET_API_STATUS ApiStatus;
+ HANDLE PrinterHandleClose = INVALID_HANDLE_VALUE;
+
+ IF_DEBUG( DOSPRTP ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CommandALocalJob: issuing command " FORMAT_DWORD " for job "
+ FORMAT_DWORD ".\n", Command, JobId ));
+ }
+
+ //
+ // If a print handle wasn't passed in, open one ourselves.
+ // We store it in PrinterHandleClose so that we can close it later.
+ //
+ if ( PrinterHandle == NULL ) {
+ if ( !MyOpenPrinter( NULL, &PrinterHandle, NULL )) {
+
+ ApiStatus = GetLastError();
+ goto Cleanup;
+ }
+ PrinterHandleClose = PrinterHandle;
+ }
+
+ if ( !MySetJobA(
+ PrinterHandle,
+ JobId,
+ Level,
+ pJob,
+ Command) ) {
+
+ ApiStatus = GetLastError();
+
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CommandALocalJob: FAILED COMMAND " FORMAT_DWORD " for job "
+ FORMAT_DWORD ", api status " FORMAT_API_STATUS ".\n",
+ Command, JobId, ApiStatus ));
+
+ goto Cleanup;
+
+ } else {
+ ApiStatus = NO_ERROR;
+ }
+
+
+Cleanup:
+ if (PrinterHandleClose != INVALID_HANDLE_VALUE) {
+ (VOID) MyClosePrinter(PrinterHandle);
+ }
+
+ IF_DEBUG( DOSPRTP ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CommandALocalJob: returning api status " FORMAT_API_STATUS
+ ".\n", ApiStatus ));
+ }
+ return (ApiStatus);
+
+} // CommandALocalJob
+
+
+// Note: FindLocalJob() calls SetLastError() to indicate the cause of an error.
+// Return INVALID_HANDLE_VALUE on error.
+HANDLE
+FindLocalJob(
+ IN DWORD JobId
+ )
+{
+ DWORD cbPrinter, cReturned, rc, cbJob, i;
+ LPPRINTER_INFO_1 pPrinter;
+ LPPRINTER_INFO_1 pPrinterArray = NULL;
+ LPJOB_INFO_2 pJob = NULL;
+ HANDLE hPrinter = INVALID_HANDLE_VALUE;
+
+ if (!MyEnumPrinters(PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &cbPrinter,
+ &cReturned)) {
+
+ rc=GetLastError();
+ if (rc != ERROR_INSUFFICIENT_BUFFER) {
+ goto CleanupError;
+ }
+
+ pPrinterArray = (LPVOID) GlobalAlloc(GMEM_FIXED, cbPrinter);
+ if (pPrinterArray == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto CleanupError;
+ }
+
+ if ( !MyEnumPrinters(PRINTER_ENUM_LOCAL,
+ NULL, 1, (LPBYTE)pPrinterArray, cbPrinter,
+ &cbPrinter, &cReturned) ) {
+
+ rc = GetLastError();
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "FindLocalJob: MyEnumPrinters(2nd) failed, rc = "
+ FORMAT_API_STATUS ));
+
+ NetpAssert( FALSE ); // "can't happen".
+ goto CleanupError;
+ }
+ }
+
+ pPrinter = pPrinterArray;
+ for (i=0; i<cReturned; i++) {
+
+ if (MyOpenPrinter(pPrinter->pName, &hPrinter, NULL)) {
+
+ NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
+
+ if (!MyGetJob(hPrinter, JobId, 2, NULL, 0, &cbJob)) {
+
+ rc=GetLastError();
+
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJob);
+ if (pJob == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto CleanupError;
+ }
+
+ if ( !MyGetJob(hPrinter,
+ JobId, 2, (LPBYTE)pJob, cbJob, &cbJob) ) {
+
+ rc = GetLastError();
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "FindLocalJob: MyGetJob(2nd) failed, rc = "
+ FORMAT_API_STATUS ));
+
+ NetpAssert( FALSE ); // "can't happen".
+ goto CleanupError;
+ }
+
+ // Got it!
+ (VOID) GlobalFree(pPrinterArray);
+
+ (VOID) GlobalFree(pJob);
+
+ return(hPrinter);
+ }
+ }
+
+ (VOID) MyClosePrinter(hPrinter);
+ }
+ // BUGBUG: Ignore errors from OpenPrinter?
+
+ // Not in this queue, so keep checking...
+ pPrinter++;
+
+ }
+
+ IF_DEBUG( DOSPRTP ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "FindLocalJob: couldn't find job " FORMAT_DWORD " in "
+ FORMAT_DWORD " queue(s).\n", JobId, cReturned ));
+ }
+
+
+ rc = NERR_JobNotFound;
+
+CleanupError:
+
+ if (pJob != NULL) {
+ (VOID) GlobalFree(pJob);
+ }
+ if (pPrinterArray != NULL) {
+ (VOID) GlobalFree(pPrinterArray);
+ }
+
+ SetLastError( rc );
+
+ return (INVALID_HANDLE_VALUE);
+
+} // FindLocalJob
+
+
+
+LPSTR
+FindQueueNameInPrinterNameA(
+ IN LPCSTR PrinterName
+ )
+{
+ LPSTR QueueName;
+ NetpAssert( PrinterName != NULL );
+
+ QueueName = strrchr( PrinterName, '\\');
+
+ if (QueueName) {
+ ++QueueName; // Skip past the backslash.
+ } else {
+ QueueName = (LPSTR) PrinterName;
+ }
+ NetpAssert( QueueName != NULL );
+ return (QueueName);
+}
+
+
+LPWSTR
+FindQueueNameInPrinterNameW(
+ IN LPCWSTR PrinterName
+ )
+{
+ LPWSTR QueueName;
+ NetpAssert( PrinterName != NULL );
+
+ QueueName = wcsrchr( PrinterName, L'\\');
+ if (QueueName) {
+ ++QueueName; // Skip past the backslash.
+ } else {
+ QueueName = (LPWSTR) PrinterName;
+ }
+ NetpAssert( QueueName != NULL );
+ return (QueueName);
+}
+
+
+WORD
+PrjStatusFromJobStatus(
+ IN DWORD JobStatus
+ )
+{
+ WORD PrjStatus = 0;
+
+ if (JobStatus & JOB_STATUS_SPOOLING)
+
+ PrjStatus |= PRJ_QS_SPOOLING;
+
+ if (JobStatus & JOB_STATUS_PAUSED)
+
+ PrjStatus |= PRJ_QS_PAUSED;
+
+ if (JobStatus & JOB_STATUS_PRINTING)
+
+ PrjStatus |= PRJ_QS_PRINTING;
+
+ if (JobStatus & JOB_STATUS_ERROR)
+
+ PrjStatus |= PRJ_ERROR;
+
+ return (PrjStatus);
+
+} // PrjStatusFromJobStatus
+
+
+WORD
+PrqStatusFromPrinterStatus(
+ IN DWORD PrinterStatus
+ )
+{
+ WORD PrqStatus;
+
+ if (PrinterStatus & PRINTER_STATUS_PAUSED) {
+
+ PrqStatus = PRQ_PAUSED;
+
+ } else if (PrinterStatus & PRINTER_STATUS_ERROR) {
+
+ PrqStatus = PRQ_ERROR;
+
+ } else if (PrinterStatus & PRINTER_STATUS_PENDING_DELETION) {
+
+ PrqStatus = PRQ_PENDING;
+
+ } else {
+
+ PrqStatus = PRQ_ACTIVE;
+
+ }
+
+ return (PrqStatus);
+
+} // PrqStatusFromPrinterStatus
+
+
+
diff --git a/private/net/dosprint/dosprtw.c b/private/net/dosprint/dosprtw.c
new file mode 100644
index 000000000..820fa894d
--- /dev/null
+++ b/private/net/dosprint/dosprtw.c
@@ -0,0 +1,2284 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ DosPrtW.c
+
+Abstract:
+
+ This module provides the UNICODE mapping layer from the old DosPrint APIs
+ to the new all singing all dancing beautiful Print APIs. (The ANSI
+ mapping layer is in DosPrint.c)
+
+Author:
+
+ Dave Snipp (DaveSn) 26-Apr-1991
+
+Revision History:
+
+ 09-Jul-1992 JohnRo
+ Created this file (from DaveSn's DosPrint.c) for RAID 10324: net print
+ vs. UNICODE.
+ 05-Oct-1992 JohnRo
+ RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124. (4&5 too.)
+ RAID 3580: lmsvcs.exe: access violation from OS/2 DosPrintJobGetInfo.
+ RAID 8333: view printer queues hangs DOS LM enh client.
+ Make sure data type in job level 1 is null terminated.
+ Fixed job submitted times.
+ Fixed error code if GlobalAlloc fails.
+ Fixed memory leak in DosPrintQGetInfoW.
+ Fixed DosPrintQEnumW level 5 array bug.
+ Fixed DosPrintJobEnumW levels 2 and 3.
+ 25-Nov-1992 JohnRo
+ RAID 1661: downlevel to NT DosPrintDestEnum not supported.
+ Added code to track down empty queue name.
+ Quiet normal debug output.
+ Avoid const vs. volatile compiler warnings.
+ Avoid other new compiler warnings.
+ 08-Feb-1993 JohnRo
+ RAID 10164: Data misalignment error during XsDosPrintQGetInfo().
+ 22-Mar-1993 JohnRo
+ RAID 2974: NET PRINT says NT printer is held when it isn't.
+ 11-May-1993 JohnRo
+ RAID 9942: fix queue name in job info level 3.
+ 14-May-1993 JohnRo
+ RAID 9961: DosPrintDestEnum returns NO_ERROR to downlevel but
+ pcReturned=0; should return NERR_DestNotFound.
+ Fixed data type returned from PrjInfoFixedSizeW().
+ 18-May-1993 JohnRo
+ DosPrintQGetInfoW underestimates number of bytes needed.
+ Use NetpKdPrint() where possible.
+ Made changes suggested by PC-LINT.
+ 04-Jun-1993 JohnRo
+ RAID 10222: DosPrintQEnumW returns ERROR_INVALID_USER_BUFFER
+ when queue is empty.
+ Made changes suggested by PC-LINT 5.0
+ 08-Jul-1993 JohnRo
+ RAID 15509: GetJob() API sometimes returned TRUE, even on error case.
+ Also added some >64KB checks.
+ Added some assert checks...
+ 13-Jul-1993 JohnRo
+ Intermittent empty print queue (was buggy after some MyEnumJobs calls).
+ 29-Mar-1995 AlbertT
+ Support for pause/resume/purge printer queue added.
+ SetJobInfo 1 comment field (translated into document name) support
+ added so that chicago clients can set the doc name.
+
+--*/
+
+
+#ifndef UNICODE
+#error "RxPrint APIs assume RxRemoteApi uses wide characters."
+#endif
+
+#define NOMINMAX
+#define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
+#include <windows.h>
+
+//#include <lm.h>
+#include <netdebug.h>
+
+#include <string.h>
+
+
+#ifdef _WINSPOOL_
+#error "Include of winspool.h moved, make sure it doesn't get UNICODE."
+#endif
+
+#undef UNICODE
+#include <winspool.h>
+#define UNICODE
+
+#ifndef _WINSPOOL_
+#error "Oops, winspool.h changed, make sure this code is still OK."
+#endif
+
+
+#include <dosprint.h>
+#include <dosprtp.h> // IF_DEBUG(), CommandALocalJob(), etc.
+#include <lmapibuf.h> // NetApiBufferFree(), etc.
+#include <lmerr.h> // NO_ERROR, NERR_, and ERROR_ equates.
+#include <lmshare.h> // LPSHARE_INFO_1, STYPE_ equates, etc.
+#include <prefix.h> // PREFIX_ equates.
+#include <stddef.h> // offsetof().
+#include <timelib.h> // NetpSystemTimeToGmtTime().
+#include <tstring.h> // WCSSIZE(), NetpNCopy{type}To{type}.
+#include <wchar.h> // wsclen(), wcscpy(), etc.
+#include "myspool.h"
+
+
+#define STR_CONV_SIZE(psz) ( (strlen(psz)+1) * sizeof(WCHAR) )
+
+// NULL_STR_CONV_SIZE: Compute size needed for converted string, which
+// is possibly a null pointer but downlevel really wants ptr to null char.
+#define NULL_STR_CONV_SIZE(psz) ( (psz) ? STR_CONV_SIZE(psz) : sizeof(WCHAR) )
+
+
+#define ARRAY_END ((DWORD) -1)
+
+#define MAX_WORD ( (WORD) (~0) )
+
+// BUGBUG: Come up with a better error code for this?
+#define MY_PROTOCOL_LIMIT_ERROR ERROR_NOT_ENOUGH_MEMORY
+
+#define WIN95_ENVIRONMENT "Windows 4.0"
+#define WIN95_DRIVER_SHARE "\\print$\\WIN40\\0"
+
+
+
+DBGSTATIC LPWSTR
+PackAnsiStringsToW(
+ LPSTR *pSource,
+ LPBYTE pDest,
+ CONST DWORD *DestOffsets,
+ LPWSTR pEnd
+)
+{
+ while (*DestOffsets != ARRAY_END) {
+ if (*pSource) {
+ pEnd-=(strlen(*pSource) + 1);
+
+ // Copy the string and convert chars while we're at it.
+ NetpCopyStrToWStr(pEnd, *pSource);
+
+ *(LPWSTR *)(pDest+*DestOffsets) = pEnd;
+ } else {
+
+ // BUGBUG? I think this first version is wrong, as downlevel (e.g.
+ // OS/2 print manager) doesn't handle null pointers well?
+ // --JR, 19-Jun-1992
+ //
+ // *(LPWSTR *)(pDest+*DestOffsets)=0;
+
+ --pEnd; // need 1 char for this.
+ *pEnd = L'\0';
+ *(LPWSTR *)(pDest+*DestOffsets) = pEnd;
+ }
+ pSource++;
+ DestOffsets++;
+ }
+
+ return pEnd;
+}
+
+DBGSTATIC DWORD
+PrjInfoFixedSizeW(
+ IN DWORD Level // assumed valid
+ )
+{
+ switch (Level) {
+
+ case 0:
+ return sizeof(WORD); // job number.
+ case 1:
+ return (sizeof(PRJINFOW));
+ case 2:
+ return (sizeof(PRJINFO2W));
+ case 3:
+ return (sizeof(PRJINFO3W));
+ default:
+ NetpAssert( FALSE );
+ return (0);
+ }
+ /*NOTREACHED*/
+}
+
+DBGSTATIC DWORD
+GetPrjInfoSizeW(
+ IN DWORD Level,
+ IN LPJOB_INFO_2 pJob,
+ IN LPCWSTR QueueNameW,
+ IN LPPRINTER_INFO_2 pPrinter OPTIONAL
+)
+{
+ NetpAssert( pJob != NULL );
+ switch (Level) {
+
+ case 0:
+
+ return sizeof(WORD); // job number.
+
+ case 1:
+
+ return sizeof(PRJINFOW) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pStatus) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ); // fake pszComment
+
+ case 2:
+
+ return sizeof(PRJINFO2W) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pUserName) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + // fake pszComment
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) );
+
+ case 3:
+
+ NetpAssert( pPrinter != NULL );
+ NetpAssert( QueueNameW != NULL );
+
+ return sizeof(PRJINFO3W) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pUserName) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + // fake pszComment
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pNotifyName) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDatatype) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pStatus) ) +
+ WCSSIZE( QueueNameW ) + // pszQueue
+ NULL_STR_CONV_SIZE( (LPSTR) (pPrinter->pPrintProcessor) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pPrinter->pParameters) ) +
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDriverName) ) +
+ // BUGBUG: pDriverData?
+ NULL_STR_CONV_SIZE( (LPSTR) (pJob->pPrinterName) );
+
+ default:
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "GetPrjInfoSizeW: invalid level!\n" ));
+ return 0;
+
+ }
+ /*NOTREACHED*/
+}
+
+// Print job info string table (for level 1).
+DBGSTATIC CONST DWORD PrjInfo1StringsW[]={
+ offsetof(PRJINFOW, pszParms),
+ offsetof(PRJINFOW, pszStatus),
+ offsetof(PRJINFOW, pszComment),
+ ARRAY_END};
+
+// Print job info string table (for level 2).
+DBGSTATIC CONST DWORD PrjInfo2StringsW[]={
+ offsetof(PRJINFO2W, pszUserName),
+ offsetof(PRJINFO2W, pszComment),
+ offsetof(PRJINFO2W, pszDocument),
+ (DWORD) -1};
+
+// Print job info string table (for items which level 3 has on top of level 2).
+DBGSTATIC CONST DWORD PrjInfo3StringsW[]={
+ offsetof(PRJINFO3W, pszNotifyName),
+ offsetof(PRJINFO3W, pszDataType),
+ offsetof(PRJINFO3W, pszParms),
+ offsetof(PRJINFO3W, pszStatus),
+ offsetof(PRJINFO3W, pszQProcName),
+ offsetof(PRJINFO3W, pszQProcParms),
+ offsetof(PRJINFO3W, pszDriverName),
+ offsetof(PRJINFO3W, pszPrinterName),
+ (DWORD) -1};
+
+DBGSTATIC LPWSTR
+CopyJobToPrjInfoW(
+ IN DWORD Level,
+ IN LPJOB_INFO_2 pJob,
+ IN LPCWSTR QueueNameW,
+ IN LPPRINTER_INFO_2 pPrinter OPTIONAL,
+ OUT PBYTE pBuffer,
+ IN OUT LPWSTR pEnd
+ )
+{
+ LPSTR *pSourceStrings;
+ NET_API_STATUS rc;
+
+ NetpAssert( pBuffer != NULL );
+ NetpAssert( pEnd != NULL );
+ NetpAssert( pJob != NULL );
+
+ switch (Level) {
+
+ case 0:
+
+ {
+ PWORD pJobIds = (PWORD) pBuffer;
+ *pJobIds = (WORD)pJob->JobId;
+ }
+ break;
+
+ case 1:
+ {
+ LPSTR SourceStrings[sizeof(PrjInfo1StringsW)/sizeof(DWORD)];
+ PPRJINFOW pPrjInfo = (LPVOID) pBuffer;
+
+ pSourceStrings=SourceStrings;
+ *pSourceStrings++ = (LPSTR) (pJob->pParameters);
+ *pSourceStrings++ = (LPSTR) (pJob->pStatus);
+ *pSourceStrings++ = (LPSTR) (pJob->pDocument); // fake pszComment
+
+ pEnd = PackAnsiStringsToW(
+ SourceStrings,
+ (LPBYTE) (LPVOID) pPrjInfo,
+ PrjInfo1StringsW,
+ pEnd);
+
+ pPrjInfo->uJobId = (WORD)pJob->JobId;
+
+ if (pJob->pUserName)
+ (VOID) NetpNCopyStrToWStr(
+ (LPWSTR) (pPrjInfo->szUserName),
+ (LPSTR) (pJob->pUserName),
+ LM20_UNLEN+1);
+ else
+ pPrjInfo->szUserName[0] = L'\0';
+
+ if (pJob->pNotifyName)
+ (VOID) NetpNCopyStrToWStr(
+ (LPWSTR) (pPrjInfo->szNotifyName),
+ (LPSTR) (pJob->pNotifyName),
+ LM20_CNLEN+1);
+ else
+ pPrjInfo->szNotifyName[0] = L'\0';
+
+ if (pJob->pDatatype) {
+ (VOID) NetpNCopyStrToWStr(
+ (LPWSTR) (pPrjInfo->szDataType),
+ (LPSTR) (pJob->pDatatype),
+ DTLEN+1);
+ pPrjInfo->szDataType[DTLEN] = L'\0';
+ } else {
+ pPrjInfo->szDataType[0] = L'\0';
+ }
+
+ pPrjInfo->uPosition = (WORD)pJob->Position;
+
+ pPrjInfo->fsStatus = PrjStatusFromJobStatus( pJob->Status );
+
+ rc = NetpSystemTimeToGmtTime(
+ &pJob->Submitted,
+ &pPrjInfo->ulSubmitted );
+ NetpAssert( rc == NO_ERROR );
+
+ pPrjInfo->ulSize = pJob->Size;
+ }
+ break;
+
+ case 2: /*FALLTHROUGH*/
+ case 3:
+ {
+ PPRJINFO2W pPrjInfo = (LPVOID) pBuffer;
+ LPSTR SourceStrings[sizeof(PrjInfo2StringsW)/sizeof(DWORD)];
+
+ pSourceStrings=SourceStrings;
+ *pSourceStrings++ = (LPSTR) (pJob->pUserName);
+ *pSourceStrings++ = (LPSTR) (pJob->pDocument); // fake pszComment
+ *pSourceStrings++ = (LPSTR) (pJob->pDocument);
+
+ pEnd = PackAnsiStringsToW(
+ SourceStrings,
+ (LPBYTE) (LPVOID) pPrjInfo,
+ PrjInfo2StringsW,
+ pEnd);
+
+ pPrjInfo->uJobId = (WORD)pJob->JobId;
+ pPrjInfo->uPriority = (WORD)pJob->Priority;
+
+ pPrjInfo->uPosition = (WORD)pJob->Position;
+
+ pPrjInfo->fsStatus = PrjStatusFromJobStatus( pJob->Status );
+
+ rc = NetpSystemTimeToGmtTime(
+ &pJob->Submitted,
+ &pPrjInfo->ulSubmitted );
+ NetpAssert( rc == NO_ERROR );
+
+ pPrjInfo->ulSize = pJob->Size;
+ }
+
+ if (Level == 3) {
+ PPRJINFO3W pPrjInfo = (LPVOID) pBuffer;
+ LPSTR SourceStrings[sizeof(PrjInfo3StringsW)/sizeof(DWORD)];
+
+ NetpAssert( pPrinter != NULL );
+
+ //
+ // Copy queue name first, as it is already right char set.
+ //
+ NetpAssert( QueueNameW != NULL );
+ pEnd-=(wcslen(QueueNameW) + 1);
+
+ (VOID) wcscpy(pEnd, QueueNameW);
+
+ pPrjInfo->pszQueue = pEnd;
+
+ //
+ // Copy and convert other strings.
+ //
+ pSourceStrings=SourceStrings;
+ *pSourceStrings++ = (LPSTR) (pJob->pNotifyName);
+ *pSourceStrings++ = (LPSTR) (pJob->pDatatype);
+ *pSourceStrings++ = (LPSTR) (pJob->pParameters);
+ *pSourceStrings++ = (LPSTR) (pJob->pStatus);
+ *pSourceStrings++ = pPrinter->pPrintProcessor;
+ *pSourceStrings++ = pPrinter->pParameters;
+ *pSourceStrings++ = (LPSTR) (pJob->pDriverName);
+ *pSourceStrings++ = (LPSTR) (pJob->pPrinterName);
+
+ pEnd = PackAnsiStringsToW(
+ SourceStrings,
+ (LPBYTE) (LPVOID) pPrjInfo,
+ PrjInfo3StringsW,
+ pEnd);
+
+ pPrjInfo->pDriverData = NULL;
+ }
+
+ break;
+
+ default:
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CopyJobToPrjInfoW: invalid level!\n" ));
+
+ }
+
+ IF_DEBUG( DOSPRTW ) {
+ if (NetpIsPrintJobLevelValid( Level, FALSE ) ) {
+ NetpKdPrint(( PREFIX_DOSPRINT "CopyJobToPrjInfoW: "
+ " created print job:\n" ));
+ NetpDbgDisplayPrintJob( Level, pBuffer, TRUE ); // Yes, has UNICODE.
+ }
+ }
+
+ return pEnd;
+}
+
+DBGSTATIC DWORD
+GetPrqInfoSizeW(
+ IN DWORD Level,
+ IN LPCWSTR QueueNameW,
+ IN LPPRINTER_INFO_2 pPrinter
+ )
+{
+ NetpAssert( QueueNameW != NULL );
+ NetpAssert( (*QueueNameW) != L'\0' );
+
+ switch (Level) {
+
+ case 0:
+
+ return ( (LM20_QNLEN+1) * sizeof(WCHAR) );
+
+ case 1: /*FALLTHROUGH*/
+ case 2:
+
+ return sizeof(PRQINFOW) +
+ NULL_STR_CONV_SIZE( pPrinter->pSepFile ) +
+ NULL_STR_CONV_SIZE( pPrinter->pPrintProcessor ) +
+ NULL_STR_CONV_SIZE( pPrinter->pPortName ) +
+ NULL_STR_CONV_SIZE( pPrinter->pParameters ) +
+ NULL_STR_CONV_SIZE( pPrinter->pComment );
+
+ case 3: /*FALLTHROUGH*/
+ case 4:
+
+ NetpAssert( QueueNameW != NULL );
+
+ return sizeof(PRQINFO3W) +
+ WCSSIZE( QueueNameW ) + // pszName
+ NULL_STR_CONV_SIZE( pPrinter->pSepFile ) +
+ NULL_STR_CONV_SIZE( pPrinter->pPrintProcessor ) +
+ NULL_STR_CONV_SIZE( pPrinter->pParameters ) +
+ NULL_STR_CONV_SIZE( pPrinter->pComment ) +
+ NULL_STR_CONV_SIZE( pPrinter->pPortName ) +
+ NULL_STR_CONV_SIZE( pPrinter->pDriverName );
+ // BUGBUG: no support for pszDriverData?
+
+ case 5:
+
+ NetpAssert( QueueNameW != NULL );
+
+ return sizeof(LPWSTR) +
+ WCSSIZE( QueueNameW ); // pszName
+
+ default:
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "GetPrqInfoSizeW: invalid level!\n" ));
+
+ }
+
+ return 0;
+}
+
+DBGSTATIC DWORD
+GetDrvInfoSizeW(
+ IN DWORD Level,
+ IN LPDRIVER_INFO_3A pDriverInfo3,
+ IN LPCSTR pUNCSharePath,
+ OUT LPDWORD pdwDependentFileCount
+ )
+{
+ LPSTR psz;
+ DWORD dwSize;
+
+ switch (Level) {
+ case 52:
+ dwSize = sizeof(PRQINFO52W) +
+ NULL_STR_CONV_SIZE(pDriverInfo3->pName) +
+ NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pDriverPath)) +
+ NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pDataFile)) +
+ NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pConfigFile)) +
+ NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pHelpFile)) +
+ NULL_STR_CONV_SIZE(pDriverInfo3->pDefaultDataType) +
+ NULL_STR_CONV_SIZE(pDriverInfo3->pMonitorName) +
+ NULL_STR_CONV_SIZE(pUNCSharePath);
+
+ *pdwDependentFileCount = 0;
+ for ( psz = pDriverInfo3->pDependentFiles;
+ *psz ; psz += strlen(psz) + 1 ) {
+
+ dwSize += NULL_STR_CONV_SIZE(GetFileNameA(psz));
+ (*pdwDependentFileCount)++;
+ }
+
+ //
+ // For the '\0's
+ //
+ dwSize += (MAX_DEPENDENT_FILES-*pdwDependentFileCount)*sizeof(WCHAR);
+ return dwSize;
+
+ default:
+ NetpKdPrint(( PREFIX_DOSPRINT "GetDrvInfoSizeW: invalid level!\n" ));
+
+ }
+ return 0;
+
+}
+
+DBGSTATIC DWORD
+PrqInfoFixedSizeW(
+ IN DWORD Level // assumed valid
+ )
+{
+ switch (Level) {
+ case 0:
+ return ( (LM20_QNLEN+1) * sizeof(WCHAR) );
+ case 1: /*FALLTHROUGH*/
+ case 2:
+ return (sizeof(PRQINFOW));
+ case 3: /*FALLTHROUGH*/
+ case 4:
+ return (sizeof(PRQINFO3W));
+ case 5:
+ return (sizeof(LPWSTR));
+ default:
+ NetpAssert( FALSE ); // Level should be valid!
+ return (0);
+ }
+ /*NOTREACHED*/
+}
+
+// String table for Q levels 1,2
+DBGSTATIC CONST DWORD PrqInfo1StringsW[]={
+ offsetof(PRQINFOW, pszSepFile),
+ offsetof(PRQINFOW, pszPrProc),
+ offsetof(PRQINFOW, pszDestinations),
+ offsetof(PRQINFOW, pszParms),
+ offsetof(PRQINFOW, pszComment),
+ ARRAY_END};
+
+// String table for Q levels 3,4.
+DBGSTATIC CONST DWORD PrqInfo3StringsW[]={
+ offsetof(PRQINFO3W, pszSepFile),
+ offsetof(PRQINFO3W, pszPrProc),
+ offsetof(PRQINFO3W, pszParms),
+ offsetof(PRQINFO3W, pszComment),
+ offsetof(PRQINFO3W, pszPrinters),
+ offsetof(PRQINFO3W, pszDriverName),
+ (DWORD) -1};
+
+// Print driver info3 string table (for level 52)
+DBGSTATIC CONST DWORD PrqInfo52StringsW[]={
+ offsetof(PRQINFO52W, pszModelName),
+ offsetof(PRQINFO52W, pszDriverName),
+ offsetof(PRQINFO52W, pszDataFileName),
+ offsetof(PRQINFO52W, pszMonitorName),
+ offsetof(PRQINFO52W, pszDriverPath),
+ offsetof(PRQINFO52W, pszDefaultDataType),
+ offsetof(PRQINFO52W, pszHelpFile),
+ offsetof(PRQINFO52W, pszConfigFile),
+ offsetof(PRQINFO52W, pszDependentNames[0]),
+ offsetof(PRQINFO52W, pszDependentNames[1]),
+ offsetof(PRQINFO52W, pszDependentNames[2]),
+ offsetof(PRQINFO52W, pszDependentNames[3]),
+ offsetof(PRQINFO52W, pszDependentNames[4]),
+ offsetof(PRQINFO52W, pszDependentNames[5]),
+ offsetof(PRQINFO52W, pszDependentNames[6]),
+ offsetof(PRQINFO52W, pszDependentNames[7]),
+ offsetof(PRQINFO52W, pszDependentNames[8]),
+ offsetof(PRQINFO52W, pszDependentNames[9]),
+ offsetof(PRQINFO52W, pszDependentNames[10]),
+ offsetof(PRQINFO52W, pszDependentNames[11]),
+ offsetof(PRQINFO52W, pszDependentNames[12]),
+ offsetof(PRQINFO52W, pszDependentNames[13]),
+ offsetof(PRQINFO52W, pszDependentNames[14]),
+ offsetof(PRQINFO52W, pszDependentNames[15]),
+ offsetof(PRQINFO52W, pszDependentNames[16]),
+ offsetof(PRQINFO52W, pszDependentNames[17]),
+ offsetof(PRQINFO52W, pszDependentNames[18]),
+ offsetof(PRQINFO52W, pszDependentNames[19]),
+ (DWORD) -1};
+
+DBGSTATIC LPWSTR
+CopyPrinterToPrqInfoW(
+ IN LPPRINTER_INFO_2 pPrinter,
+ IN DWORD Level,
+ OUT LPBYTE pBuffer,
+ IN LPCWSTR QueueNameW,
+ OUT LPWSTR pEnd
+ )
+{
+ LPSTR *pSourceStrings;
+
+ NetpAssert( pEnd != NULL );
+ NetpAssert( QueueNameW != NULL );
+ NetpAssert( (*QueueNameW) != L'\0' );
+
+ switch (Level) {
+
+ case 0:
+ (VOID) wcsncpy(
+ (LPWSTR) (LPVOID) pBuffer,
+ QueueNameW,
+ LM20_QNLEN);
+ break;
+
+ case 1: /*FALLTHROUGH*/
+ case 2:
+
+ {
+ LPSTR SourceStrings[sizeof(PrqInfo1StringsW)/sizeof(DWORD)];
+ PPRQINFOW pPrqInfo = (LPVOID) pBuffer;
+
+ pSourceStrings=SourceStrings;
+ *pSourceStrings++ = pPrinter->pSepFile;
+ *pSourceStrings++ = pPrinter->pPrintProcessor;
+ *pSourceStrings++ = pPrinter->pPortName;
+ *pSourceStrings++ = pPrinter->pParameters;
+ *pSourceStrings++ = pPrinter->pComment;
+
+ pEnd = PackAnsiStringsToW(
+ SourceStrings,
+ (LPBYTE) (LPVOID) pPrqInfo,
+ PrqInfo1StringsW,
+ pEnd);
+
+ NetpAssert( QueueNameW != NULL );
+
+ (VOID) wcsncpy(
+ pPrqInfo->szName, // dest
+ QueueNameW, // src
+ LM20_QNLEN+1); // char count
+
+ pPrqInfo->uPriority = (WORD)pPrinter->Priority;
+ pPrqInfo->uStartTime = (WORD)pPrinter->StartTime;
+ pPrqInfo->uUntilTime = (WORD)pPrinter->UntilTime;
+
+ pPrqInfo->fsStatus = PrqStatusFromPrinterStatus( pPrinter->Status );
+
+ pPrqInfo->cJobs = (WORD)pPrinter->cJobs;
+ }
+
+ break;
+
+ case 3: /*FALLTHROUGH*/
+ case 4:
+ {
+ LPSTR SourceStrings[sizeof(PrqInfo3StringsW)/sizeof(DWORD)];
+ PPRQINFO3W pPrqInfo = (LPVOID) pBuffer;
+
+ //
+ // Copy queue name first, as it is already right char set.
+ //
+ NetpAssert( QueueNameW != NULL );
+ pEnd-=(wcslen(QueueNameW) + 1);
+
+ (VOID) wcscpy(pEnd, QueueNameW);
+
+ pPrqInfo->pszName = pEnd;
+
+ //
+ // Copy and convert other strings.
+ //
+ pSourceStrings=SourceStrings;
+ *pSourceStrings++ = pPrinter->pSepFile;
+ *pSourceStrings++ = pPrinter->pPrintProcessor;
+ *pSourceStrings++ = pPrinter->pParameters;
+ *pSourceStrings++ = pPrinter->pComment;
+ *pSourceStrings++ = pPrinter->pPortName; // pszPrinters
+ *pSourceStrings++ = pPrinter->pDriverName;
+
+ pEnd = PackAnsiStringsToW(
+ SourceStrings,
+ (LPBYTE) (LPVOID) pPrqInfo,
+ PrqInfo3StringsW,
+ pEnd);
+
+ pPrqInfo->uPriority = (WORD)pPrinter->Priority;
+ pPrqInfo->uStartTime = (WORD)pPrinter->StartTime;
+ pPrqInfo->uUntilTime = (WORD)pPrinter->UntilTime;
+
+ pPrqInfo->fsStatus = PrqStatusFromPrinterStatus( pPrinter->Status );
+
+ pPrqInfo->cJobs = (WORD)pPrinter->cJobs;
+ pPrqInfo->pDriverData = NULL; // BUGBUG better support for this?
+
+ // Note: if level is 4, caller will add array of jobs after this.
+
+ break;
+ }
+
+ case 5:
+ NetpAssert( QueueNameW != NULL );
+
+ pEnd -= (wcslen( QueueNameW ) + 1);
+ * (LPWSTR *) pBuffer = pEnd;
+
+ (VOID) wcscpy(
+ pEnd, // dest
+ QueueNameW ); // src
+
+
+ break;
+
+ default:
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CopyPrinterToPrqInfoW: invalid level!\n" ));
+
+ }
+
+#if DBG
+ IF_DEBUG( DOSPRTW ) {
+ if (NetpIsPrintQLevelValid( Level, FALSE) ) {
+ DWORD PretendLevel = Level; // we can use this level unless...
+ NetpKdPrint(( PREFIX_DOSPRINT "CopyPrinterToPrqInfoW: "
+ " created print queue:\n" ));
+ if ( (Level == 2) || (Level == 4) ) {
+ if (Level == 2) {
+ PretendLevel = 1;
+ } else {
+ PretendLevel = 3;
+ }
+ NetpKdPrint((
+ " (no jobs copied yet, so pretending info level is "
+ FORMAT_DWORD ", real info level is "
+ FORMAT_DWORD ").\n",
+ PretendLevel, Level ));
+ }
+ NetpDbgDisplayPrintQ(
+ PretendLevel,
+ pBuffer,
+ TRUE ); // Yes, has UNICODE.
+ }
+ }
+#endif
+
+ return pEnd;
+}
+
+DBGSTATIC LPWSTR
+CopyDriverToPrqInfoW(
+ IN LPDRIVER_INFO_3A pDriver3,
+ IN DWORD dwDependentFileCount,
+ IN LPSTR pUNCSharePath,
+ IN DWORD Level,
+ OUT LPBYTE pBuffer,
+ OUT LPWSTR pEnd
+ )
+{
+ LPSTR *pSourceStrings;
+ LPSTR psz;
+
+ NetpAssert( pEnd != NULL );
+ NetpAssert(MAX_DEPENDENT_FILES == 20);
+
+ switch (Level) {
+
+ case 52:
+ {
+ PPRQINFO52W pPrqInfo = (LPVOID) pBuffer;
+ LPSTR SourceStrings[sizeof(PrqInfo52StringsW)/sizeof(DWORD)];
+
+ ZeroMemory((LPBYTE)SourceStrings, sizeof(SourceStrings));
+
+ pSourceStrings=SourceStrings;
+ *pSourceStrings++ = pDriver3->pName;
+ *pSourceStrings++ = GetFileNameA(pDriver3->pDriverPath);
+ *pSourceStrings++ = GetFileNameA(pDriver3->pDataFile);
+ *pSourceStrings++ = GetFileNameA(pDriver3->pMonitorName);
+ *pSourceStrings++ = pUNCSharePath;
+ *pSourceStrings++ = GetFileNameA(pDriver3->pDefaultDataType);
+ *pSourceStrings++ = GetFileNameA(pDriver3->pHelpFile);
+ *pSourceStrings++ = GetFileNameA(pDriver3->pConfigFile);
+
+ for ( psz = pDriver3->pDependentFiles ; *psz ;
+ psz += strlen(psz) + 1 ) {
+
+ *pSourceStrings++ = GetFileNameA(psz);
+ }
+
+ pEnd = PackAnsiStringsToW(
+ SourceStrings,
+ (LPBYTE) (LPVOID)pPrqInfo,
+ PrqInfo52StringsW,
+ pEnd);
+
+ pPrqInfo->uVersion = (WORD)pDriver3->cVersion;
+ pPrqInfo->cDependentNames = (WORD)dwDependentFileCount;
+ }
+
+ break;
+
+
+ default:
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "CopyPrinterToPrqInfoW: invalid level!\n" ));
+
+ }
+
+ return pEnd;
+}
+
+DBGSTATIC NET_API_STATUS
+ComputeSpaceNeededForJobs(
+ IN LPCWSTR QueueNameW,
+ IN DWORD QLevel,
+ IN HANDLE PrinterHandle,
+ IN LPPRINTER_INFO_2 pPrinter,
+ OUT LPDWORD pcbNeeded
+ )
+{
+ NET_API_STATUS ApiStatus;
+ DWORD cJobs;
+ DWORD cbJobs;
+ DWORD cbNeeded = 0;
+ DWORD JobLevel;
+ LPJOB_INFO_2 pJob = NULL;
+ LPJOB_INFO_2 pJobs = NULL;
+
+ NetpAssert( (QLevel==2) || (QLevel==4) );
+ NetpAssert( QueueNameW != NULL );
+ NetpAssert( pPrinter != NULL );
+
+ if (QLevel==2) {
+ JobLevel = 1;
+ } else {
+ JobLevel = 2;
+ }
+
+
+ if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, &cJobs)) {
+
+ ApiStatus = (NET_API_STATUS) GetLastError();
+ if (ApiStatus == ERROR_INSUFFICIENT_BUFFER) {
+
+ pJobs = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs);
+ if (pJobs == NULL) {
+
+ ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ } else {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "ComputeSpaceNeededForJobs: got error " FORMAT_API_STATUS
+ " from MyEnumJobs(first).\n", ApiStatus ));
+ goto Cleanup;
+ }
+ }
+
+ if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, (LPBYTE)pJobs, cbJobs,
+ &cbJobs, &cJobs)) {
+
+ ApiStatus = (NET_API_STATUS) GetLastError();
+ NetpAssert( ApiStatus != ERROR_INSUFFICIENT_BUFFER );
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "ComputeSpaceNeededForJobs: got error " FORMAT_API_STATUS
+ " from MyEnumJobs(second)\n", ApiStatus ));
+ goto Cleanup;
+ }
+
+ if (cJobs == 0) {
+ cbNeeded = 0;
+ ApiStatus = NO_ERROR;
+ goto Cleanup;
+ }
+ if (pJobs == NULL) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "ComputeSpaceNeededForJobs: never allocated array!\n" ));
+ ApiStatus = NERR_InternalError;
+ goto Cleanup;
+ }
+
+ pJob=pJobs;
+
+ while (cJobs--) {
+ cbNeeded+=GetPrjInfoSizeW(JobLevel, pJob++, QueueNameW, pPrinter);
+ }
+
+ *pcbNeeded=(WORD)cbNeeded; // final byte count for this queue's jobs.
+
+ ApiStatus = NO_ERROR;
+
+Cleanup:
+ if (pJobs != NULL) {
+ (VOID) GlobalFree(pJobs);
+ }
+
+ *pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
+
+ return (ApiStatus);
+
+} // ComputeSpaceNeededForJobs
+
+
+DBGSTATIC NET_API_STATUS
+AppendJobsToPrqW(
+ IN LPCWSTR QueueNameW,
+ IN DWORD QLevel,
+ IN HANDLE PrinterHandle,
+ IN LPPRINTER_INFO_2 pPrinter,
+ OUT LPBYTE pbBuf,
+ IN DWORD cbBuf,
+ IN LPVOID pEnd,
+ OUT LPVOID * pNewEnd,
+ OUT LPDWORD pcbNeeded,
+ OUT LPDWORD pcReturned
+ )
+{
+ DWORD cJobs;
+ DWORD cbJobs;
+ DWORD cbNeeded = 0;
+ DWORD cbPrj;
+ DWORD JobLevel;
+ DWORD rc;
+ LPJOB_INFO_2 pJob = NULL;
+ LPJOB_INFO_2 pJobs = NULL;
+
+ NetpAssert( (QLevel==2) || (QLevel==4) );
+ NetpAssert( QueueNameW != NULL );
+ NetpAssert( pPrinter != NULL );
+
+ if (QLevel==2) {
+ cbPrj = sizeof(PRJINFOW);
+ JobLevel = 1;
+ } else {
+ cbPrj = sizeof(PRJINFO2W);
+ JobLevel = 2;
+ }
+
+
+ if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, pcReturned)) {
+
+ rc = GetLastError();
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ pJobs = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs);
+ if (pJobs == NULL) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ } else {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "AppendJobsToPrqW: got error " FORMAT_API_STATUS
+ " from MyEnumJobs(first)\n", rc ));
+ goto Cleanup;
+ }
+ }
+
+ if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, (LPBYTE)pJobs, cbJobs,
+ &cbJobs, pcReturned)) {
+
+ rc = GetLastError();
+ NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER );
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "AppendJobsToPrqW: got error " FORMAT_API_STATUS
+ " from MyEnumJobs(second)\n", rc ));
+ goto Cleanup;
+ }
+
+ if (*pcReturned == 0) {
+ cbNeeded = 0;
+ rc = NO_ERROR;
+ goto Cleanup;
+ }
+ if (pJobs == NULL) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "AppendJobsToPrqW: never allocated array!\n" ));
+ rc = NERR_InternalError;
+ goto Cleanup;
+ }
+
+ cJobs = *pcReturned;
+ pJob=pJobs;
+
+ while (cJobs--)
+ cbNeeded+=GetPrjInfoSizeW(JobLevel, pJob++, QueueNameW, pPrinter);
+
+ *pcbNeeded=(WORD)cbNeeded; // final byte count for this queue's jobs.
+
+ if (cbNeeded <= cbBuf) {
+
+ cJobs = *pcReturned;
+ pJob=pJobs;
+ while (cJobs--) {
+ pEnd = CopyJobToPrjInfoW(JobLevel, pJob++, QueueNameW,
+ pPrinter,
+ pbBuf,
+ pEnd);
+ pbBuf += cbPrj; // Note: Wasn't DWORD aligned
+ }
+ rc = NO_ERROR;
+
+ } else {
+
+ rc = NERR_BufTooSmall;
+ }
+
+Cleanup:
+ if (pJobs != NULL) {
+ (VOID) GlobalFree(pJobs);
+ }
+
+ *pcbNeeded=(WORD)cbNeeded; // final byte count for this queue's jobs.
+
+ if (pNewEnd != NULL) {
+ *pNewEnd = pEnd;
+ }
+
+ return (rc);
+
+}
+SPLERR SPLENTRY DosPrintQGetInfoW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ PUSHORT pcbNeeded
+ )
+{
+ DWORD cJobsReturned;
+ LPWSTR pEnd;
+ DWORD rc;
+ HANDLE hPrinter = INVALID_HANDLE_VALUE;
+ LPPRINTER_INFO_2 pPrinter = NULL;
+ LPDRIVER_INFO_3A pDriver = NULL;
+ CHAR szDriverDir[MAX_PATH];
+ DWORD cbNeeded, dwDependentFileCount;
+ DWORD cbNeededForJobs;
+
+ if (pszServer && *pszServer) {
+ rc = RxPrintQGetInfo(pszServer, pszQueueName, uLevel, pbBuf,
+ cbBuf, &cbNeeded);
+ if (cbNeeded > MAX_WORD) {
+ rc = MY_PROTOCOL_LIMIT_ERROR;
+ goto Cleanup;
+ }
+ *pcbNeeded = (USHORT)cbNeeded;
+ goto Cleanup;
+ }
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQGetInfoW(NULL, "
+ FORMAT_LPWSTR ", " FORMAT_DWORD ", " FORMAT_LPVOID ", "
+ FORMAT_DWORD ", " FORMAT_LPVOID ")\n",
+ (pszQueueName!=NULL) ? pszQueueName : (LPWSTR) L"(missing)",
+ uLevel,
+ pbBuf,
+ cbBuf,
+ pcbNeeded));
+ }
+
+ *pcbNeeded = 0; // in case an error occurs.
+ if ( !NetpIsPrintQLevelValid( uLevel, FALSE ) ) {
+ rc = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+ if ( (pszQueueName==NULL) || ((*pszQueueName)==L'\0') ) {
+ rc = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if ( !MyOpenPrinterW( pszQueueName, &hPrinter, NULL) ) {
+
+ rc = GetLastError();
+ if ( rc == ERROR_INVALID_PRINTER_NAME )
+ rc = NERR_QNotFound;
+ goto Cleanup;
+
+ }
+
+ //
+ // Level 52 is meant for point and print from a Windows 95 clients
+ // can't use with other clients since no environment info is passed
+ //
+ if ( uLevel == 52 ) {
+
+ cbNeeded = sizeof(szDriverDir)-2;
+ szDriverDir[0] = szDriverDir[1] = '\\';
+ if ( !GetComputerNameA(szDriverDir+2, &cbNeeded) ) {
+
+ rc = GetLastError();
+ goto Cleanup;
+ }
+
+ if ( strlen(szDriverDir) + strlen(WIN95_DRIVER_SHARE) + 1
+ > sizeof(szDriverDir) ) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ NetpAssert( rc != NO_ERROR ); // Always break
+ goto Cleanup;
+ }
+
+ strcat(szDriverDir, WIN95_DRIVER_SHARE);
+
+ (VOID)MyGetPrinterDriver(hPrinter, WIN95_ENVIRONMENT, 3,
+ NULL, 0, &cbNeeded);
+ rc = GetLastError();
+ if ( rc != ERROR_INSUFFICIENT_BUFFER )
+ goto Cleanup;
+
+ pDriver = (LPVOID) GlobalAlloc(GMEM_FIXED, cbNeeded);
+ if ( !pDriver ) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ if ( !MyGetPrinterDriver(hPrinter, WIN95_ENVIRONMENT, 3,
+ (LPVOID)pDriver, cbNeeded, &cbNeeded) ) {
+
+ rc = GetLastError();
+ goto Cleanup;
+ }
+
+ cbNeeded=GetDrvInfoSizeW(uLevel, pDriver,
+ szDriverDir, &dwDependentFileCount);
+ if ( dwDependentFileCount > MAX_DEPENDENT_FILES ) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ } else {
+
+ if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbNeeded)) {
+
+ rc = GetLastError();
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbNeeded);
+ if (pPrinter == NULL) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ } else {
+ goto Cleanup;
+ }
+
+ }
+
+ if (!MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbNeeded, &cbNeeded)) {
+
+ rc = GetLastError();
+ goto Cleanup;
+ }
+
+ // How much for just the queue structure and its strings?
+ cbNeeded=GetPrqInfoSizeW(uLevel, pszQueueName, pPrinter);
+ }
+
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintQGetInfoW: got " FORMAT_DWORD " for Q size.\n",
+ (DWORD) cbNeeded ));
+ }
+ if (cbNeeded > MAX_WORD) {
+ rc = MY_PROTOCOL_LIMIT_ERROR;
+ goto Cleanup;
+ }
+ *pcbNeeded = (WORD)cbNeeded; // Tell caller the size (so far).
+
+ //
+ // Build the queue structure itself.
+ //
+ if (cbNeeded <= (DWORD) cbBuf) {
+
+ if ( uLevel == 52 ) {
+
+ ZeroMemory(pbBuf, cbNeeded);
+ pEnd = CopyDriverToPrqInfoW(pDriver, dwDependentFileCount,
+ szDriverDir, uLevel, pbBuf,
+ (LPWSTR) (pbBuf+cbBuf) );
+ } else {
+
+ pEnd = CopyPrinterToPrqInfoW(pPrinter, uLevel, pbBuf, pszQueueName,
+ (LPWSTR) (pbBuf+cbBuf) );
+ }
+
+ } else {
+
+ //
+ // Too small. Well, need to find total size before we can tell caller.
+ //
+ if ( (uLevel==2) || (uLevel==4) ) {
+ rc = ComputeSpaceNeededForJobs(
+ pszQueueName,
+ uLevel, // Q info level
+ hPrinter,
+ pPrinter,
+ & cbNeededForJobs );
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+ cbNeeded += cbNeededForJobs;
+ }
+ if (cbNeeded > MAX_WORD) {
+ rc = MY_PROTOCOL_LIMIT_ERROR;
+ goto Cleanup;
+ }
+ rc = NERR_BufTooSmall;
+ goto Cleanup;
+ }
+
+ //
+ // Append jobs if necessary.
+ //
+
+ if ( (uLevel==2) || (uLevel==4) ) {
+ DWORD cbPrq = PrqInfoFixedSizeW( uLevel );
+
+ rc = AppendJobsToPrqW(
+ pszQueueName,
+ uLevel, // Q info level
+ hPrinter,
+ pPrinter,
+ pbBuf + cbPrq, // put first job here
+ cbBuf - cbNeeded, // bytes avail for jobs
+ pEnd, // str area
+ NULL, // don't need new pEnd
+ & cbNeededForJobs,
+ & cJobsReturned );
+
+ *pcbNeeded = (USHORT) (cbNeeded + cbNeededForJobs);
+
+ //
+ // Update job count in queue structure, as it may be out of date.
+ //
+
+ NetpSetJobCountForQueue(
+ uLevel, // queue info level
+ pbBuf, // queue structure to update
+ TRUE, // yes, UNICODE strings
+ cJobsReturned ); // actual job count
+
+ if (rc != NO_ERROR) {
+ goto Cleanup;
+ }
+
+ }
+
+ rc = NO_ERROR;
+
+Cleanup:
+
+ if (hPrinter != INVALID_HANDLE_VALUE) {
+ (VOID) MyClosePrinter( hPrinter );
+ }
+
+ if (pPrinter) {
+ (VOID) GlobalFree( pPrinter );
+ }
+
+ if (pDriver) {
+
+ (VOID) GlobalFree( pDriver );
+ }
+
+ return rc;
+}
+
+
+SPLERR SPLENTRY DosPrintJobGetInfoW(
+ LPWSTR pszServer,
+ WORD uJobId,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ PUSHORT pcbNeeded
+)
+{
+ DWORD cb;
+ DWORD cbPrinter;
+ HANDLE hPrinter = INVALID_HANDLE_VALUE;
+ LPSTR QueueNameA = NULL;
+ LPWSTR QueueNameW = NULL;
+ LPJOB_INFO_2 pJob = NULL;
+ LPWSTR pEnd;
+ LPPRINTER_INFO_2 pPrinter = NULL;
+ DWORD rc;
+ DWORD cbNeeded;
+
+ if (pszServer && *pszServer) {
+ rc = RxPrintJobGetInfo(pszServer, uJobId, uLevel, pbBuf,
+ cbBuf, &cbNeeded);
+ *pcbNeeded = (USHORT)cbNeeded;
+ return rc;
+ }
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobGetInfoW(NULL, " FORMAT_DWORD
+ ", " FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD
+ ", " FORMAT_LPVOID ")\n",
+ uJobId, uLevel, pbBuf, cbBuf, pcbNeeded));
+ }
+
+ *pcbNeeded = 0; // in case an error occurs.
+
+ if ( !NetpIsPrintJobLevelValid( uLevel, FALSE ) ) {
+ rc = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ hPrinter = FindLocalJob(uJobId);
+ if (hPrinter == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ goto Cleanup;
+ }
+
+ if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbPrinter)) {
+
+ rc = GetLastError();
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbPrinter);
+ if (pPrinter == NULL) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ } else {
+ goto Cleanup;
+ }
+
+ }
+
+ if (!MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbPrinter, &cbPrinter)) {
+
+ rc = GetLastError();
+ goto Cleanup;
+ }
+
+ if (!MyGetJob(hPrinter, uJobId, 2, NULL, 0, &cb)) {
+
+ rc=GetLastError();
+
+ NetpAssert( rc != NO_ERROR );
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cb);
+ if (pJob == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ if ( !MyGetJob(hPrinter, uJobId, 2, (LPBYTE)pJob, cb, &cb) ) {
+ rc=GetLastError();
+ NetpAssert( rc != NO_ERROR );
+ goto Cleanup;
+ }
+
+ } else {
+ if (rc == ERROR_INVALID_PARAMETER) {
+ rc = NERR_JobNotFound;
+ }
+ goto Cleanup; // Job deleted? Not enough mem?
+ }
+
+ }
+ if (pJob == NULL) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobGetInfoW: "
+ "*** STILL INVALID RESULT FROM MyGetJob, pJob IS NULL!\n" ));
+ rc = NERR_InternalError;
+ goto Cleanup;
+ }
+
+ NetpAssert( pJob != NULL );
+ NetpAssert( pPrinter != NULL );
+ NetpAssert( pPrinter->pPrinterName != NULL );
+ QueueNameA = FindQueueNameInPrinterNameA(
+ (pPrinter->pPrinterName) );
+ NetpAssert( QueueNameA != NULL );
+ QueueNameW = NetpAllocWStrFromStr( QueueNameA );
+ if (QueueNameW == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ NetpAssert( QueueNameW != NULL );
+
+ cb=GetPrjInfoSizeW(uLevel, pJob, QueueNameW, pPrinter);
+
+ *pcbNeeded=(WORD)cb;
+
+ if (cb > (DWORD) cbBuf) {
+ rc = NERR_BufTooSmall;
+ goto Cleanup;
+ }
+
+ pEnd = (LPVOID) (pbBuf+cbBuf);
+
+ (VOID) CopyJobToPrjInfoW(uLevel, pJob, QueueNameW, pPrinter, pbBuf, pEnd);
+
+ rc = NO_ERROR;
+
+Cleanup:
+
+ if (hPrinter != INVALID_HANDLE_VALUE) {
+ (VOID) MyClosePrinter( hPrinter );
+ }
+ if (pJob != NULL) {
+ (VOID) GlobalFree( pJob );
+ }
+ if (pPrinter != NULL) {
+ (VOID) GlobalFree( pPrinter );
+ }
+ if (QueueNameW != NULL) {
+ (VOID) NetApiBufferFree( QueueNameW );
+ }
+
+ return (rc);
+
+}
+
+SPLERR SPLENTRY DosPrintJobDelW(
+ LPWSTR pszServer,
+ WORD uJobId
+)
+{
+
+ if (pszServer && *pszServer)
+ return RxPrintJobDel(pszServer, uJobId);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintJobDelW(NULL, " FORMAT_DWORD ")\n", uJobId ));
+ }
+
+ return (CommandALocalJob( NULL, uJobId, 0, NULL, JOB_CONTROL_CANCEL ) );
+}
+
+SPLERR SPLENTRY DosPrintJobContinueW(
+ LPWSTR pszServer,
+ WORD uJobId
+)
+{
+
+ if (pszServer && *pszServer)
+ return RxPrintJobContinue(pszServer, uJobId);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobContinueW(NULL, "
+ FORMAT_DWORD ")\n", uJobId));
+ }
+
+ return (CommandALocalJob( NULL, uJobId, 0, NULL, JOB_CONTROL_RESUME ) );
+}
+
+SPLERR SPLENTRY DosPrintJobPauseW(
+ LPWSTR pszServer,
+ WORD uJobId
+)
+{
+
+ if (pszServer && *pszServer)
+ return RxPrintJobPause(pszServer, uJobId);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintJobPauseW(NULL, " FORMAT_DWORD ")\n",
+ uJobId));
+ }
+
+ return (CommandALocalJob( NULL, uJobId, 0, NULL, JOB_CONTROL_PAUSE ) );
+}
+
+SPLERR SPLENTRY DosPrintJobEnumW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ PWORD pcReturned,
+ PWORD pcTotal
+)
+{
+ DWORD cbPrinter;
+ LPJOB_INFO_2 pJob = NULL;
+ LPJOB_INFO_2 pJobs;
+ DWORD cb, cbJobs, cReturned, cJobs;
+ HANDLE hPrinter = INVALID_HANDLE_VALUE;
+ LPWSTR pEnd;
+ LPPRINTER_INFO_2 pPrinter = NULL;
+ DWORD rc;
+ DWORD cTotal;
+
+ if (pszServer && *pszServer) {
+ rc = RxPrintJobEnum(pszServer, pszQueueName, uLevel, pbBuf,
+ cbBuf, &cReturned, &cTotal);
+ *pcReturned = (WORD)cReturned;
+ *pcTotal = (WORD)cTotal;
+ goto Cleanup;
+ }
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobEnumW(NULL, " FORMAT_LPWSTR
+ ", " FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD
+ ", " FORMAT_LPVOID ", " FORMAT_LPVOID ")\n",
+ pszQueueName,
+ uLevel,
+ pbBuf,
+ cbBuf,
+ pcReturned,
+ pcTotal));
+ }
+
+ *pcReturned=0;
+ *pcTotal = 0;
+
+ if ( !NetpIsPrintJobLevelValid( uLevel, FALSE ) ) {
+ rc = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (!MyOpenPrinterW( pszQueueName, &hPrinter, NULL)) {
+ rc = GetLastError();
+ goto Cleanup;
+ }
+ NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
+
+ if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbPrinter)) {
+
+ rc = GetLastError();
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbPrinter);
+ if (pPrinter == NULL) {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ } else {
+ goto Cleanup;
+ }
+
+ }
+
+ if (!MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbPrinter,
+ &cbPrinter)) {
+
+ rc = GetLastError();
+ NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER );
+ goto Cleanup;
+ }
+
+ if (!MyEnumJobs(hPrinter, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, &cReturned)) {
+
+ rc = GetLastError();
+ NetpAssert( rc != NO_ERROR );
+ if (rc == ERROR_INSUFFICIENT_BUFFER) {
+
+ if (pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs)) {
+
+ if (!MyEnumJobs(hPrinter, 0, (DWORD) -1, 2, (LPBYTE)pJob, cbJobs,
+ &cbJobs, &cReturned)) {
+
+ rc = GetLastError();
+ NetpAssert( rc != NO_ERROR );
+ NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER ); // BUGBUG
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintJobEnumW: got error " FORMAT_API_STATUS
+ " from MyEnumJobs(first)\n", rc ));
+ goto Cleanup;
+ }
+ } else {
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+ } else {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintJobEnumW: got error " FORMAT_API_STATUS
+ " from MyEnumJobs(first)\n", rc ));
+ goto Cleanup;
+ }
+ }
+
+ if (cReturned == 0) {
+ *pcReturned = 0;
+ *pcTotal = 0;
+ rc = NO_ERROR;
+ goto Cleanup;
+ }
+ if (pJob == NULL) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintJobEnumW: never allocated array!\n" ));
+ rc = NERR_InternalError;
+ goto Cleanup;
+ }
+
+
+ *pcTotal = (WORD)cReturned;
+
+ cb=0;
+ cJobs=cReturned;
+ pJobs=pJob;
+ while (cJobs--)
+ cb+=GetPrjInfoSizeW(uLevel, pJobs++, pszQueueName, pPrinter);
+
+ if (cb <= (DWORD) cbBuf) {
+
+ DWORD cbFixedPortion = PrjInfoFixedSizeW( uLevel );
+ NetpAssert( cbFixedPortion != 0 ); // level already checked!
+
+ pEnd = (LPWSTR)(pbBuf+cbBuf);
+
+ cJobs=cReturned;
+ pJobs=pJob;
+
+ while (cJobs--) {
+
+ pEnd = CopyJobToPrjInfoW(uLevel, pJobs++,
+ pszQueueName,
+ pPrinter,
+ pbBuf, pEnd);
+ pbBuf += cbFixedPortion;
+ }
+
+ *pcReturned = (WORD)cReturned;
+ rc = NO_ERROR;
+
+ } else {
+
+ rc = NERR_BufTooSmall;
+ goto Cleanup;
+ }
+
+Cleanup:
+
+ if (hPrinter != INVALID_HANDLE_VALUE) {
+ (VOID) MyClosePrinter( hPrinter );
+ }
+ if (pJob != NULL) {
+ (VOID) GlobalFree( pJob );
+ }
+ if (pPrinter) {
+ (VOID) GlobalFree( pPrinter );
+ }
+
+ return rc;
+}
+
+SPLERR SPLENTRY
+DosPrintDestEnumW(
+ IN LPWSTR pszServer OPTIONAL,
+ IN WORD uLevel,
+ OUT PBYTE pbBuf,
+ IN WORD cbBuf,
+ OUT PUSHORT pcReturned,
+ OUT PUSHORT pcTotal
+ )
+{
+ DWORD cReturned, cTotal, rc;
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint(( PREFIX_DOSPRINT "DosPrintDestEnumW(" FORMAT_LPWSTR ", "
+ FORMAT_DWORD
+ ", " FORMAT_LPVOID ", " FORMAT_DWORD ", " FORMAT_LPVOID
+ ", " FORMAT_LPVOID ")\n",
+ (pszServer!=NULL) ? pszServer : (LPWSTR) L"(local)",
+ uLevel, pbBuf, cbBuf, pcReturned, pcTotal));
+ }
+
+ if (pszServer && *pszServer) {
+ rc = RxPrintDestEnum(pszServer, uLevel, pbBuf, cbBuf,
+ &cReturned, &cTotal);
+ *pcReturned = (USHORT)cReturned;
+ *pcTotal = (USHORT)cTotal;
+ return rc;
+ }
+
+ // Stub for local dest enum - no entries, dest not found.
+ *pcReturned = 0;
+ *pcTotal = 0;
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintDestControlW(
+ LPWSTR pszServer,
+ LPWSTR pszDevName,
+ WORD uControl
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintDestControl(pszServer, pszDevName, uControl);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintDestEnumW(NULL, "
+ FORMAT_LPWSTR ", " FORMAT_DWORD ")\n", pszDevName, uControl));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+SPLERR SPLENTRY DosPrintDestGetInfoW(
+ LPWSTR pszServer,
+ LPWSTR pszName,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ PUSHORT pcbNeeded
+)
+{
+ DWORD cbNeeded, rc;
+
+ if (pszServer && *pszServer) {
+ rc = RxPrintDestGetInfo(pszServer, pszName, uLevel, pbBuf,
+ cbBuf, &cbNeeded);
+ *pcbNeeded = (USHORT)cbNeeded;
+ return rc;
+ }
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintDestGetInfoW(NULL, "
+ FORMAT_LPWSTR ", " FORMAT_DWORD ", " FORMAT_LPVOID
+ ", " FORMAT_DWORD ", " FORMAT_LPVOID ")\n",
+ pszName, uLevel, pbBuf, cbBuf, pcbNeeded));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintDestAddW(
+ LPWSTR pszServer,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintDestAdd(pszServer, uLevel, pbBuf, cbBuf);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintDestAddW(NULL, "
+ FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD ")\n",
+ uLevel, pbBuf, cbBuf));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintDestSetInfoW(
+ LPWSTR pszServer,
+ LPWSTR pszName,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ WORD uParmNum
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintDestSetInfo(pszServer, pszName, uLevel, pbBuf,
+ cbBuf, uParmNum);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintDestSetInfoW(NULL, " FORMAT_LPWSTR
+ ", " FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD
+ ", " FORMAT_DWORD ")\n",
+ pszName, uLevel, pbBuf, cbBuf, uParmNum));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintDestDelW(
+ LPWSTR pszServer,
+ LPWSTR pszPrinterName
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintDestDel(pszServer, pszPrinterName);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintDestDelW(NULL, "
+ FORMAT_LPWSTR ")\n",
+ pszPrinterName));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintQEnumW(
+ LPWSTR pszServer,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ PUSHORT pcReturned,
+ PUSHORT pcTotal
+)
+{
+ DWORD cJobsReturned;
+ DWORD Total, cbNeeded, rc;
+ HANDLE hPrinter = INVALID_HANDLE_VALUE;
+ DWORD i;
+ DWORD JobFixedEntrySize = 0;
+ DWORD JobLevel;
+ LPSHARE_INFO_1 pShareInfo = NULL;
+ DWORD cbPrinter;
+ LPPRINTER_INFO_2 pPrinter = NULL;
+ BOOL BufferTooSmall=FALSE;
+ DWORD cReturned, cTotal;
+#if DBG
+ LPVOID OutputBufferStart = pbBuf;
+#endif
+ LPVOID pEnd;
+ DWORD SharesRead;
+
+ if ( !NetpIsPrintQLevelValid( uLevel, FALSE ) ) {
+ rc = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (pszServer && *pszServer) {
+ rc = RxPrintQEnum(pszServer, uLevel, pbBuf, cbBuf, &cReturned, &cTotal);
+ *pcReturned = (USHORT)cReturned;
+ *pcTotal = (USHORT)cTotal;
+ goto Cleanup;
+ }
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQEnumW(NULL, "
+ FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD ", "
+ FORMAT_LPVOID ", " FORMAT_LPVOID ")\n",
+ uLevel, pbBuf, cbBuf, pcReturned, pcTotal));
+ }
+
+ *pcReturned = 0;
+ *pcTotal = 0;
+
+ rc=NetShareEnum(
+ NULL,
+ 1,
+ (LPBYTE *)(LPVOID)&pShareInfo,
+ MAX_PREFERRED_LENGTH,
+ &SharesRead,
+ &Total,
+ NULL);
+ if (rc != NO_ERROR) {
+
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQEnumW: NetShareEnum returned "
+ FORMAT_API_STATUS "\n", rc));
+ goto Cleanup;
+ }
+
+ pEnd = (pbBuf + cbBuf);
+
+ if (uLevel==2) {
+ JobLevel = 1;
+ JobFixedEntrySize = PrjInfoFixedSizeW( JobLevel );
+ } else if (uLevel == 4) {
+ JobLevel = 2;
+ JobFixedEntrySize = PrjInfoFixedSizeW( JobLevel );
+ }
+
+ for (i=0; i<SharesRead; i++) {
+
+ if (pShareInfo[i].shi1_type != STYPE_PRINTQ) {
+ continue;
+ }
+
+ NetpAssert( pShareInfo[i].shi1_netname != NULL );
+ NetpAssert( (*pShareInfo[i].shi1_netname) != L'\0' );
+ if (STRLEN( pShareInfo[i].shi1_netname ) > LM20_QNLEN) {
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintQEnumW: ignoring long share name of '"
+ FORMAT_LPTSTR "'.\n",
+ pShareInfo[i].shi1_netname ));
+ }
+ continue;
+ }
+
+ if ( !MyOpenPrinterW(pShareInfo[i].shi1_netname, &hPrinter, NULL)) {
+ rc = (NET_API_STATUS) GetLastError();
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintQEnumW: MyOpenPrinter failed, status "
+ FORMAT_API_STATUS ".\n", rc ));
+ NetpAssert( rc != NO_ERROR );
+ goto Cleanup;
+ }
+ NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
+
+ if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbPrinter)) {
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ rc = (NET_API_STATUS) GetLastError();
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintQEnumW: MyGetPrinter(first) failed, status "
+ FORMAT_API_STATUS ".\n", rc ));
+ NetpAssert( rc != NO_ERROR );
+ goto Cleanup;
+ }
+ }
+ NetpAssert( cbPrinter != 0 );
+
+ pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbPrinter);
+ if (pPrinter == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ if ( !MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter,
+ cbPrinter, &cbPrinter)) {
+ rc = (NET_API_STATUS) GetLastError();
+ NetpKdPrint(( PREFIX_DOSPRINT
+ "DosPrintQEnumW: MyGetPrinter(second) failed, status "
+ FORMAT_API_STATUS ".\n", rc ));
+ NetpAssert( rc != NO_ERROR );
+ goto Cleanup;
+ }
+
+ cbNeeded=GetPrqInfoSizeW(uLevel,
+ pShareInfo[i].shi1_netname, // Q nam
+ pPrinter);
+ NetpAssert( cbNeeded > 0 );
+ NetpAssert( cbNeeded <= (DWORD) MAX_WORD );
+
+ if ( (!BufferTooSmall) && ((DWORD)cbBuf >= cbNeeded) ) {
+
+ LPVOID pbQueue = pbBuf;
+ //
+ // Handle queue structure itself.
+ //
+ pEnd = CopyPrinterToPrqInfoW(pPrinter,
+ uLevel,
+ pbBuf,
+ pShareInfo[i].shi1_netname,
+ pEnd);
+
+ pbBuf += PrqInfoFixedSizeW( uLevel );
+ cbBuf -= (WORD) cbNeeded;
+
+ //
+ // Append job structures if needed.
+ //
+ if ( (uLevel==2) || (uLevel==4) ) { // info level includes jobs
+
+ NetpAssert( pbBuf < (LPBYTE) pEnd );
+ rc = AppendJobsToPrqW(
+ pShareInfo[i].shi1_netname,
+ uLevel, // Q info level
+ hPrinter,
+ pPrinter,
+ pbBuf, // first job here
+ cbBuf, // bytes avail
+ pEnd, // str area
+ & pEnd, // set new end ptr
+ & cbNeeded,
+ & cJobsReturned );
+ if (rc == NERR_BufTooSmall) {
+ BufferTooSmall = TRUE; // continue, as we need pcTotal...
+ } else if (rc != NO_ERROR) {
+ goto Cleanup;
+ } else { // Must be NO_ERROR.
+ NetpAssert( cbNeeded <= (DWORD) MAX_WORD );
+ NetpAssert( pbBuf < (LPBYTE) pEnd );
+ NetpAssert( JobFixedEntrySize !=0 );
+
+ pbBuf += (JobFixedEntrySize * cJobsReturned);
+ cbBuf -= (WORD) cbNeeded;
+ (*pcReturned)++;
+
+ // Correct possible out of date
+ // job count in queue structure.
+ NetpSetJobCountForQueue(
+ uLevel,
+ pbQueue,
+ TRUE, // yes, UNICODE strs
+ cJobsReturned );
+ }
+
+ } else { // info level does not include jobs
+
+ (*pcReturned)++;
+ }
+
+ } else { // not enough mem for Q struct
+
+ BufferTooSmall = TRUE;
+ // Continue, as we want to compute pcTotal for subsequent queues.
+ }
+
+ (*pcTotal)++;
+
+ NetpAssert( pPrinter != NULL );
+ (VOID) GlobalFree(pPrinter);
+ pPrinter = NULL;
+
+ NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
+ (VOID) MyClosePrinter(hPrinter);
+ hPrinter = INVALID_HANDLE_VALUE;
+
+ } // for each share
+
+Cleanup:
+
+#if DBG
+ IF_DEBUG( DOSPRTW ) {
+ if (rc == NO_ERROR) {
+ NetpKdPrint((PREFIX_DOSPRINT
+ "DosPrintQEnumW: returning array:\n" ));
+ NetpDbgDisplayPrintQArray( uLevel,
+ OutputBufferStart,
+ *pcReturned, TRUE );
+ }
+ }
+#endif
+
+ if (hPrinter != INVALID_HANDLE_VALUE) {
+ (VOID) MyClosePrinter( hPrinter );
+ }
+ if (pPrinter != NULL) {
+ (VOID) GlobalFree( pPrinter );
+ }
+ if (pShareInfo != NULL) {
+ (VOID) NetApiBufferFree(pShareInfo);
+ }
+
+ if (BufferTooSmall) {
+ rc = NERR_BufTooSmall;
+ }
+
+ return (rc);
+}
+
+SPLERR SPLENTRY DosPrintQSetInfoW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ WORD uParmNum
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintQSetInfo(pszServer, pszQueueName, uLevel, pbBuf,
+ cbBuf, uParmNum);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQSetInfoW(NULL, " FORMAT_LPWSTR
+ ", " FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD ", "
+ FORMAT_DWORD ")\n",
+ pszQueueName, uLevel, pbBuf, cbBuf, uParmNum));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintQPauseW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintQPause(pszServer, pszQueueName);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQPauseW(NULL, "
+ FORMAT_LPWSTR ")\n",
+ pszQueueName));
+ }
+
+ return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_PAUSE ) );
+}
+
+SPLERR SPLENTRY DosPrintQContinueW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintQContinue(pszServer, pszQueueName);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQContinueW(NULL, "
+ FORMAT_LPWSTR ")\n", pszQueueName));
+ }
+
+ return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_RESUME ) );
+}
+
+SPLERR SPLENTRY DosPrintQPurgeW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintQPurge(pszServer, pszQueueName);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQPurgeW(NULL, "
+ FORMAT_LPWSTR ")\n",
+ pszQueueName));
+ }
+
+ return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_PURGE ) );
+}
+
+SPLERR SPLENTRY DosPrintQAddW(
+ LPWSTR pszServer,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintQAdd(pszServer, uLevel, pbBuf, cbBuf);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQAddW(NULL, " FORMAT_DWORD ", "
+ FORMAT_LPVOID ", " FORMAT_DWORD ")\n",
+ uLevel, pbBuf, cbBuf));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintQDelW(
+ LPWSTR pszServer,
+ LPWSTR pszQueueName
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintQDel(pszServer, pszQueueName);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintQDelW(NULL, " FORMAT_LPWSTR ")\n",
+ pszQueueName));
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+SPLERR SPLENTRY DosPrintJobSetInfoW(
+ LPWSTR pszServer,
+ WORD uJobId,
+ WORD uLevel,
+ PBYTE pbBuf,
+ WORD cbBuf,
+ WORD uParmNum
+)
+{
+ if (pszServer && *pszServer)
+ return RxPrintJobSetInfo(pszServer, uJobId, uLevel, pbBuf,
+ cbBuf, uParmNum);
+
+ IF_DEBUG( DOSPRTW ) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW(NULL, " FORMAT_DWORD
+ ", " FORMAT_DWORD ", " FORMAT_LPVOID ", " FORMAT_DWORD
+ ", " FORMAT_DWORD ")\n",
+ uJobId, uLevel, pbBuf, cbBuf, uParmNum));
+ }
+
+ //
+ // Hack for Chicago: support Level 1, ParmNum 0xb so that jobs
+ // are set with the comment field.
+ //
+ if (uLevel == 1 && uParmNum == PRJ_COMMENT_PARMNUM) {
+
+ HANDLE hPrinter = INVALID_HANDLE_VALUE;
+ CHAR szDocument[MAX_PATH];
+ PJOB_INFO_1 pJob = NULL;
+ DWORD cbJob;
+ SPLERR rc;
+
+ //
+ // Allocate maximum size of JOB_INFO_1A. Later, this
+ // should be moved into the spooler's header file.
+ //
+ cbJob = sizeof(JOB_INFO_1) + 6 * MAX_PATH;
+
+ pJob = (PJOB_INFO_1) GlobalAlloc(GMEM_FIXED, cbJob);
+
+ if (pJob == NULL) {
+ rc = GetLastError();
+ goto Cleanup;
+ }
+
+ //
+ // The 3.51 spooler has been changed to accept Get/SetJobs on the
+ // local server handle. We will still do security checks against
+ // the Job's security descriptor. This also avoids the costly
+ // FindLocalJob() call.
+ //
+ if (!MyOpenPrinter( NULL, &hPrinter, NULL)) {
+ rc = GetLastError();
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
+ "MyOpenPrinter( NULL, &hPrinter, NULL ) failed"
+ FORMAT_API_STATUS "\n", rc ));
+
+ hPrinter = INVALID_HANDLE_VALUE;
+ goto Cleanup;
+ }
+ NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
+
+ //
+ // We need to get a copy of the old job info. Later, the
+ // spooler should be changed to allow "don't change" values.
+ //
+ if (!MyGetJob( hPrinter, uJobId, 1, (PBYTE)pJob, cbJob, &cbJob )) {
+ rc = GetLastError();
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
+ "MyGetJob failed" FORMAT_API_STATUS "\n", rc ));
+
+ goto Cleanup;
+ }
+
+ //
+ // Put in new document name.
+ //
+ NetpNCopyWStrToStr( szDocument,
+ (LPWSTR)pbBuf,
+ sizeof( szDocument ) / sizeof( szDocument[0] ));
+
+ pJob->pDocument = szDocument;
+
+ //
+ // Don't try and change the position, since this requires
+ // admin access (and isn't necessary).
+ //
+ pJob->Position = JOB_POSITION_UNSPECIFIED;
+
+ rc = CommandALocalJob( hPrinter, uJobId, 1, (PBYTE)pJob, 0 );
+
+ if (rc) {
+ NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
+ "CommandALocalJob failed " FORMAT_API_STATUS "\n", rc ));
+ }
+
+Cleanup:
+ if (pJob) {
+ GlobalFree( pJob );
+ }
+ if (hPrinter != INVALID_HANDLE_VALUE) {
+ MyClosePrinter( hPrinter );
+ }
+ return rc;
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
diff --git a/private/net/dosprint/dosspool.c b/private/net/dosprint/dosspool.c
new file mode 100644
index 000000000..a161a4684
--- /dev/null
+++ b/private/net/dosprint/dosspool.c
@@ -0,0 +1,614 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dosspool.c
+
+Abstract:
+
+ Contains the entry points for the functions that live in a
+ separate DLL. The entry points are made available here, but
+ will not load the WINSPOOL.DRV until it is needed.
+
+ Contains:
+
+Author:
+
+ Congpa You (CongpaY) 22-Jan-1993
+
+Environment:
+
+Notes:
+
+Revision History:
+
+--*/
+#include <windows.h>
+#include <netdebug.h> // NetpAssert()
+#include "dosspool.h"
+
+/*
+ * global defines.
+ */
+
+#define WINSPOOL_DLL_NAME TEXT("WINSPOOL.DRV")
+
+/*
+ * global data.
+ *
+ * here we store handles to the MPRUI dll and pointers to the function
+ * all of below is protect in multi threaded case with MprLoadLibSemaphore.
+ */
+
+HINSTANCE vhWinspoolDll = NULL ;
+
+PF_ClosePrinter pfClosePrinter = NULL ;
+PF_EnumJobsA pfEnumJobsA = NULL ;
+PF_EnumPrintersA pfEnumPrintersA = NULL ;
+PF_GetJobA pfGetJobA = NULL ;
+PF_GetPrinterA pfGetPrinterA = NULL ;
+PF_OpenPrinterA pfOpenPrinterA = NULL ;
+PF_OpenPrinterW pfOpenPrinterW = NULL ;
+PF_SetJobA pfSetJobA = NULL ;
+PF_SetPrinterW pfSetPrinterW = NULL ;
+PF_GetPrinterDriverA pfGetPrinterDriverA = NULL;
+
+/*
+ * global functions
+ */
+BOOL MakeSureDllIsLoaded(void) ;
+
+/*******************************************************************
+
+ NAME: GetFileNameA
+
+ SYNOPSIS: Gets the filename part from a fully qualified path
+
+
+ HISTORY:
+ MuhuntS 06-Feb-1996 Created
+
+********************************************************************/
+LPSTR
+GetFileNameA(
+ LPSTR pPathName
+ )
+{
+ LPSTR pSlash = pPathName, pTemp;
+
+ if ( pSlash ) {
+
+ while ( pTemp = strchr(pSlash, '\\') )
+ pSlash = pTemp+1;
+
+ if ( !*pSlash )
+ pSlash = NULL;
+
+ NetpAssert(pSlash != NULL);
+ }
+
+ return pSlash;
+}
+
+
+/*******************************************************************
+
+ NAME: MyClosePrinter
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyClosePrinter (HANDLE hPrinter)
+{
+ PF_ClosePrinter pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfClosePrinter == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_ClosePrinter)
+ GetProcAddress(vhWinspoolDll,
+ "ClosePrinter") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ {
+ pfClosePrinter = pfTemp;
+ }
+
+ }
+
+ return ((*pfClosePrinter)(hPrinter));
+}
+
+/*******************************************************************
+
+ NAME: MyEnumJobs
+
+ SYNOPSIS: calls thru to the superset function
+
+ NOTES: This is defined ANSI version. If change to UNICODE version
+ in the future, you should change the code to make it call
+ UNICODE version!!!
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyEnumJobs (HANDLE hPrinter,
+ DWORD FirstJob,
+ DWORD NoJobs,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded,
+ LPDWORD pcReturned)
+{
+ PF_EnumJobsA pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfEnumJobsA == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_EnumJobsA)
+ GetProcAddress(vhWinspoolDll,
+ "EnumJobsA") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ {
+ pfEnumJobsA = pfTemp;
+ }
+ }
+
+ return ((*pfEnumJobsA)(hPrinter,
+ FirstJob,
+ NoJobs,
+ Level,
+ pJob,
+ cbBuf,
+ pcbNeeded,
+ pcReturned));
+}
+
+/*******************************************************************
+
+ NAME: MyEnumPrinters
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyEnumPrinters(DWORD Flags,
+ LPSTR Name,
+ DWORD Level,
+ LPBYTE pPrinterEnum,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded,
+ LPDWORD pcReturned)
+
+{
+ PF_EnumPrintersA pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfEnumPrintersA == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_EnumPrintersA)
+ GetProcAddress(vhWinspoolDll,
+ "EnumPrintersA") ;
+
+ if (pfTemp == NULL)
+ {
+ return(TRUE);
+ }
+ else
+ pfEnumPrintersA = pfTemp;
+ }
+
+ return ((*pfEnumPrintersA)(Flags,
+ Name,
+ Level,
+ pPrinterEnum,
+ cbBuf,
+ pcbNeeded,
+ pcReturned));
+}
+
+/*******************************************************************
+
+ NAME: MyGetJob
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyGetJob (HANDLE hPrinter,
+ DWORD JobId,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded)
+{
+ PF_GetJobA pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfGetJobA == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_GetJobA)
+ GetProcAddress(vhWinspoolDll,
+ "GetJobA") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ pfGetJobA = pfTemp;
+ }
+
+ return ((*pfGetJobA)(hPrinter,
+ JobId,
+ Level,
+ pJob,
+ cbBuf,
+ pcbNeeded));
+}
+
+/*******************************************************************
+
+ NAME: MyGetPrinter
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyGetPrinter (HANDLE hPrinter,
+ DWORD Level,
+ LPBYTE pPrinter,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded)
+{
+ PF_GetPrinterA pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfGetPrinterA == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_GetPrinterA)
+ GetProcAddress(vhWinspoolDll,
+ "GetPrinterA") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ pfGetPrinterA = pfTemp;
+ }
+
+ return ((*pfGetPrinterA)(hPrinter,
+ Level,
+ pPrinter,
+ cbBuf,
+ pcbNeeded));
+}
+
+
+/*******************************************************************
+
+ NAME: MyOpenPrinter
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyOpenPrinter (LPSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTSA pDefault)
+
+{
+ PF_OpenPrinterA pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfOpenPrinterA == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_OpenPrinterA)
+ GetProcAddress(vhWinspoolDll,
+ "OpenPrinterA") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ pfOpenPrinterA = pfTemp;
+ }
+
+ return ((*pfOpenPrinterA)(pPrinterName,
+ phPrinter,
+ pDefault));
+}
+
+
+/*******************************************************************
+
+ NAME: MyOpenPrinterW
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+
+********************************************************************/
+
+BOOL MyOpenPrinterW (LPWSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTSW pDefault)
+
+{
+ PF_OpenPrinterW pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfOpenPrinterW == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_OpenPrinterW)
+ GetProcAddress(vhWinspoolDll,
+ "OpenPrinterW") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ pfOpenPrinterW = pfTemp;
+ }
+
+ return ((*pfOpenPrinterW)(pPrinterName,
+ phPrinter,
+ pDefault));
+}
+/*******************************************************************
+
+ NAME: MySetJobA
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ CongpaY 22-Jan-1993 Created
+ AlbertT 24-Mar-1995 AddedLevel and pJob
+
+********************************************************************/
+
+BOOL MySetJobA (HANDLE hPrinter,
+ DWORD JobId,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD Command)
+
+{
+ PF_SetJobA pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfSetJobA == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_SetJobA)
+ GetProcAddress(vhWinspoolDll,
+ "SetJobA") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ pfSetJobA = pfTemp;
+ }
+
+ return ((*pfSetJobA)(hPrinter,
+ JobId,
+ Level,
+ pJob,
+ Command));
+}
+
+/*******************************************************************
+
+ NAME: MySetPrinterW
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ AlbertT 23-Mar-1995 Created
+
+********************************************************************/
+
+BOOL MySetPrinterW(HANDLE hPrinter,
+ DWORD Level,
+ LPBYTE pPrinter,
+ DWORD Command)
+
+{
+ PF_SetPrinterW pfTemp;
+
+ // if function has not been used before, get its address.
+ if (pfSetPrinterW == NULL)
+ {
+ // make sure DLL Is loaded
+ if (!MakeSureDllIsLoaded())
+ {
+ return(FALSE) ;
+ }
+
+ pfTemp = (PF_SetPrinterW)
+ GetProcAddress(vhWinspoolDll,
+ "SetPrinterW") ;
+
+ if (pfTemp == NULL)
+ {
+ return(FALSE);
+ }
+ else
+ pfSetPrinterW = pfTemp;
+ }
+
+ return ((*pfSetPrinterW)(hPrinter,
+ Level,
+ pPrinter,
+ Command));
+}
+
+/*******************************************************************
+
+ NAME: MyGetPrinterDriver
+
+ SYNOPSIS: calls thru to the superset function
+
+ HISTORY:
+ MuhuntS 06-Feb-1996 Created
+
+********************************************************************/
+
+BOOL
+MyGetPrinterDriver(
+ HANDLE hPrinter,
+ LPSTR pEnvironment,
+ DWORD Level,
+ LPBYTE pDriver,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+ )
+{
+ //
+ // if function has not been used before, get its address.
+ //
+ if ( !pfGetPrinterDriverA ) {
+
+ //
+ // If dll is not loaded yet load it
+ //
+ if ( !MakeSureDllIsLoaded() ) {
+
+ return FALSE;
+ }
+
+ (FARPROC) pfGetPrinterDriverA = GetProcAddress(vhWinspoolDll,
+ "GetPrinterDriverA");
+
+ if ( !pfGetPrinterDriverA )
+ return FALSE;
+ }
+
+ return ((*pfGetPrinterDriverA)(hPrinter,
+ pEnvironment,
+ Level,
+ pDriver,
+ cbBuf,
+ pcbNeeded));
+}
+
+/*******************************************************************
+
+ NAME: MakeSureDllIsLoaded
+
+ SYNOPSIS: loads the WINSPOOL dll if need.
+
+ EXIT: returns TRUE if dll already loaded, or loads
+ successfully. Returns false otherwise. Caller
+ should call GetLastError() to determine error.
+
+ NOTES: it is up to the caller to call EnterLoadLibCritSect
+ before he calls this.
+
+ HISTORY:
+ chuckc 29-Jul-1992 Created
+ congpay 22-Jan-1993 Modified.
+
+********************************************************************/
+
+BOOL MakeSureDllIsLoaded(void)
+{
+ HINSTANCE handle ;
+
+ // if already load, just return TRUE
+ if (vhWinspoolDll != NULL)
+ return TRUE ;
+
+ // load the library. if it fails, it would have done a SetLastError.
+ handle = LoadLibrary(WINSPOOL_DLL_NAME);
+ if (handle == NULL)
+ return FALSE ;
+
+ // we are cool.
+ vhWinspoolDll = handle ;
+ return TRUE ;
+}
+
diff --git a/private/net/dosprint/dosspool.h b/private/net/dosprint/dosspool.h
new file mode 100644
index 000000000..c42b91e69
--- /dev/null
+++ b/private/net/dosprint/dosspool.h
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dosspool.h
+
+Abstract:
+
+ Prototypes and manifests to support dosspool.C.
+
+Author:
+
+ congpay 22-Jan-1993
+
+Environment:
+
+Notes:
+
+Revision History:
+
+ 22-Jan-1993 congpay Created
+
+--*/
+#include <winspool.h>
+
+typedef
+BOOL
+(*PF_ClosePrinter)(
+ HANDLE hPrinter
+);
+
+typedef
+BOOL
+(*PF_EnumJobsA)(
+ HANDLE hPrinter,
+ DWORD FirstJob,
+ DWORD NoJobs,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded,
+ LPDWORD pcReturned
+);
+
+typedef
+BOOL
+(*PF_EnumPrintersA)(
+ DWORD Flags,
+ LPSTR Name,
+ DWORD Level,
+ LPBYTE pPrinterEnum,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded,
+ LPDWORD pcReturned
+);
+
+typedef
+BOOL
+(*PF_GetJobA)(
+ HANDLE hPrinter,
+ DWORD JobId,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
+typedef
+BOOL
+(*PF_GetPrinterA)(
+ HANDLE hPrinter,
+ DWORD Level,
+ LPBYTE pPrinter,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
+typedef
+BOOL
+(*PF_OpenPrinterA)(
+ LPSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTSA pDefault
+);
+
+typedef
+BOOL
+(*PF_OpenPrinterW)(
+ LPWSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTSW pDefault
+);
+
+typedef
+BOOL
+(*PF_SetJobA)(
+ HANDLE hPrinter,
+ DWORD JobId,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD Command
+);
+
+typedef
+BOOL
+(*PF_SetPrinterW)(
+ HANDLE hPrinter,
+ DWORD Level,
+ LPBYTE pPrinter,
+ DWORD Command
+);
+
+typedef
+BOOL
+(*PF_GetPrinterDriverA)(
+ HANDLE hPrinter,
+ LPSTR pEnvironment,
+ DWORD Level,
+ LPBYTE pDriver,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
diff --git a/private/net/dosprint/makefile b/private/net/dosprint/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/net/dosprint/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/net/dosprint/myspool.h b/private/net/dosprint/myspool.h
new file mode 100644
index 000000000..c7d1e26e3
--- /dev/null
+++ b/private/net/dosprint/myspool.h
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ myspool.h
+
+Abstract:
+
+ Prototypes and manifests for the functions used in dosprint.c, dosprtw.c
+ and dosprtp.c.
+
+Author:
+
+ congpay 25-Jan-1993
+
+Environment:
+
+Notes:
+
+Revision History:
+
+ 25-Jan-1993 congpay Created
+
+--*/
+
+
+BOOL
+MyClosePrinter(
+ HANDLE hPrinter
+);
+
+
+BOOL
+MyEnumJobs(
+ HANDLE hPrinter,
+ DWORD FirstJob,
+ DWORD NoJobs,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded,
+ LPDWORD pcReturned
+);
+
+
+BOOL
+MyEnumPrinters(
+ DWORD Flags,
+ LPSTR Name,
+ DWORD Level,
+ LPBYTE pPrinterEnum,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded,
+ LPDWORD pcReturned
+);
+
+BOOL
+MyGetJob(
+ HANDLE hPrinter,
+ DWORD JobId,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
+
+BOOL
+MyGetPrinter(
+ HANDLE hPrinter,
+ DWORD Level,
+ LPBYTE pPrinter,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+);
+
+BOOL
+MyOpenPrinter(
+ LPSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTSA pDefault
+);
+
+
+BOOL
+MyOpenPrinterW(
+ LPWSTR pPrinterName,
+ LPHANDLE phPrinter,
+ LPPRINTER_DEFAULTSW pDefault
+);
+
+BOOL
+MySetJobA(
+ HANDLE hPrinter,
+ DWORD JobId,
+ DWORD Level,
+ LPBYTE pJob,
+ DWORD Command
+);
+
+BOOL
+MySetPrinterW(
+ HANDLE hPrinter,
+ DWORD Level,
+ LPBYTE pPrinter,
+ DWORD Command
+);
+
+BOOL
+MyGetPrinterDriver(
+ HANDLE hPrinter,
+ LPSTR pEnvironment,
+ DWORD Level,
+ LPBYTE pDriver,
+ DWORD cbBuf,
+ LPDWORD pcbNeeded
+ );
+
+LPSTR
+GetFileNameA(
+ LPSTR pPathName
+ );
+
diff --git a/private/net/dosprint/sources b/private/net/dosprint/sources
new file mode 100644
index 000000000..e05053738
--- /dev/null
+++ b/private/net/dosprint/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989-1992 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=windows
+MINORCOMP=dosprint
+
+TARGETNAME=dosprint
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=LIBRARY
+TARGETLIBS=\nt\public\sdk\lib\*\winspool.lib
+
+INCLUDES=..\inc;..\..\inc
+C_DEFINES=-DNO_WINSPOOLH
+
+!IFNDEF DISABLE_NET_UNICODE
+UNICODE=1
+NET_C_DEFINES=-DUNICODE
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=\
+ dosspool.c \
+ DosPrint.c \
+ DosPrtP.c \
+ DosPrtW.c