Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

785 lines
19 KiB

/* ---File: util.c --------------------------------------------------------
*
* Description:
* Contains Print Manager/Spooler memory allocation routines.
*
* This document contains confidential/proprietary information.
* Copyright (c) 1990-1992 Microsoft Corporation, All Rights Reserved.
*
* Revision History:
*
* ---------------------------------------------------------------------- */
/* Notes -
Global Functions:
AllocSplMem () -
AllocSplStr () -
FreeSplMem () -
FreeSplStr () -
ReallocSplMem () -
ReallocSplStr () -
Local Functions:
*/
/* =========================================================================
Header files
========================================================================= */
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include "printman.h"
#include <memory.h>
#include <winspool.h>
#include <winnls.h>
#include <lmerr.h>
LPVOID
AllocSplMem(
DWORD cb)
{
LPDWORD pMem;
pMem=(LPDWORD)LocalAlloc(LPTR, cb);
if (!pMem)
{
DBGMSG( DBG_WARNING, ( "LocalAlloc failed: Error %d\n", GetLastError( ) ) );
return NULL;
}
DBGMSG(DBG_ALLOC, ("Allocated %d bytes @%08x\n", cb, pMem));
return (LPVOID)pMem;
}
BOOL
FreeSplMem(
LPVOID pMem)
{
return LocalFree((HLOCAL)pMem) == NULL;
}
LPVOID
ReallocSplMem(
LPVOID lpOldMem,
DWORD cbNew)
{
if (lpOldMem)
return LocalReAlloc(lpOldMem, cbNew, LMEM_MOVEABLE);
else
return AllocSplMem(cbNew);
}
LPTSTR
AllocSplStr(
LPTSTR lpStr
)
/*++
Routine Description:
This function will allocate enough local memory to store the specified
string, and copy that string to the allocated memory
Arguments:
lpStr - Pointer to the string that needs to be allocated and stored
Return Value:
NON-NULL - A pointer to the allocated memory containing the string
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
LPTSTR lpMem;
if (!lpStr)
return 0;
if (lpMem = AllocSplMem( (_tcslen(lpStr) + 1 )*sizeof(TCHAR)))
_tcscpy(lpMem, lpStr);
return lpMem;
}
BOOL
FreeSplStr(
LPTSTR lpStr
)
{
return lpStr ? FreeSplMem(lpStr) : FALSE;
}
BOOL
ReallocSplStr(
LPTSTR *plpStr,
LPTSTR lpStr
)
{
FreeSplStr(*plpStr);
*plpStr=AllocSplStr(lpStr);
return TRUE;
}
/* EnumGeneric
*
* A function which calls the spooler Enum* APIs and handles all the
* memory reallocation stuff when it's needed.
* Saves lots of hassle.
*
* Parameters:
*
* fnEnum - The Enum* function to be called (e.g. EnumPrinters).
*
* Level - The level of information requested.
*
* ppEnumData - The address of a pointer to a buffer of cbBuf length
* to receive the data, which must have been allocated by
* AllocSplMem. The buffer pointer may be NULL.
* If the buffer is not large enough, the function will reallocate.
*
* cbBuf - The initial length of the buffer pointed to by *ppEnumData.
*
* pcbReturned - A pointer to a DWORD to receive the size of the buffer
* returned.
*
* pcReturned - The count of objects returned in the buffer.
*
* Arg1, Arg2, Arg3 - Arguments specific to the Enum* function called,
* as commented below.
*
* Returns:
*
* TRUE if the function is successful.
* A return of false occurs if the specific Enum* call fails
* or if the attempt to reallocate the buffer fails.
*
* Author:
*
* andrewbe, August 1992
*
*/
#define COMMON_ARGS Level, (LPBYTE)*ppEnumData, cbBuf, pcbReturned, pcReturned
BOOL
EnumGeneric(
IN PROC fnEnum,
IN DWORD Level,
IN PBYTE *ppEnumData,
IN DWORD cbBuf,
OUT LPDWORD pcbReturned,
OUT LPDWORD pcReturned,
IN PVOID Arg1,
IN PVOID Arg2,
IN PVOID Arg3 )
{
BOOL rc;
BOOL UnknownFunction = FALSE;
DWORD cbRealloc;
if( fnEnum == (PROC)EnumPrinters )
rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// Flags Name
else if( fnEnum == (PROC)EnumJobs )
rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS );
// hPrinter FirstJob NoJobs
else if( fnEnum == (PROC)EnumPrinterDrivers )
rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// pName pEnvironment
else if( fnEnum == (PROC)EnumForms )
rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS );
// hPrinter
else if( fnEnum == (PROC)EnumMonitors )
rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS );
// pName
else if( fnEnum == (PROC)EnumPorts )
rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS );
// pName
else if( fnEnum == (PROC)EnumPrintProcessors )
rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// pName pEnvironment
else if( fnEnum == (PROC)EnumPrintProcessorDatatypes )
rc = EnumPrintProcessorDatatypes( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// pName pPrintProcessorName
else
{
*ppEnumData = NULL;
UnknownFunction = TRUE;
DBGMSG( DBG_ERROR, ( "EnumGeneric called with unknown function\n" ) );
rc = FALSE;
}
if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) )
{
if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER )
{
cbRealloc = *pcbReturned;
DBGMSG( DBG_TRACE, ( "EnumGeneric: Reallocating %d (0x%x) bytes @%08x\n",
cbBuf, cbBuf, *ppEnumData ) );
if( cbBuf == 0 )
*ppEnumData = AllocSplMem( cbRealloc );
else
*ppEnumData = ReallocSplMem( *ppEnumData, cbRealloc );
cbBuf = cbRealloc;
if( *ppEnumData )
{
DBGMSG( DBG_TRACE, ( "EnumGeneric: %d (0x%x) bytes reallocated @%08x\n",
cbBuf, cbBuf, *ppEnumData ) );
if( fnEnum == (PROC)EnumPrinters )
rc = EnumPrinters( (DWORD)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// Flags Name
else if( fnEnum == (PROC)EnumJobs )
rc = EnumJobs( (HANDLE)Arg1, (DWORD)Arg2, (DWORD)Arg3, COMMON_ARGS );
// hPrinter FirstJob NoJobs
else if( fnEnum == (PROC)EnumPrinterDrivers )
rc = EnumPrinterDrivers( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// pName pEnvironment
else if( fnEnum == (PROC)EnumForms )
rc = EnumForms( (HANDLE)Arg1, COMMON_ARGS );
// hPrinter
else if( fnEnum == (PROC)EnumMonitors )
rc = EnumMonitors( (LPTSTR)Arg1, COMMON_ARGS );
// pName
else if( fnEnum == (PROC)EnumPorts )
rc = EnumPorts( (LPTSTR)Arg1, COMMON_ARGS );
// pName
else if( fnEnum == (PROC)EnumPrintProcessors )
rc = EnumPrintProcessors( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// pName pEnvironment
else if( fnEnum == (PROC)EnumPrintProcessorDatatypes )
rc = EnumPrintProcessorDatatypes( (LPTSTR)Arg1, (LPTSTR)Arg2, COMMON_ARGS );
// pName pPrintProcessorName
/* If things haven't worked out, free up the buffer.
* We do this because otherwise the caller will not know
* whether the pointer is valid any more,
* since ReallocSplMem might have failed.
*/
if( rc == FALSE )
{
if( *ppEnumData )
FreeSplMem( *ppEnumData );
*ppEnumData = NULL;
*pcbReturned = 0;
*pcReturned = 0;
}
/* Don't rely on pcbReturned having the same value
* that was passed in:
*/
else
*pcbReturned = cbRealloc;
}
}
else
{
if( *ppEnumData )
FreeSplMem( *ppEnumData );
*ppEnumData = NULL;
*pcbReturned = 0;
*pcReturned = 0;
rc = FALSE;
}
}
else
*pcbReturned = cbBuf;
return rc;
}
/* GetGeneric
*
* A function which calls the spooler Get* APIs and handles all the
* memory reallocation stuff when it's needed.
* Based on the EnumGeneric function.
*
* Parameters:
*
* fnGet - The Get* function to be called (e.g. GetPrinter).
*
* Level - The level of information requested.
*
* ppGetData - The address of a pointer to a buffer of cbBuf length
* to receive the data, which must have been allocated by
* AllocSplMem. The buffer pointer may be NULL.
* If the buffer is not large enough, the function will reallocate.
*
* cbBuf - The initial length of the buffer pointed to by *ppGetData.
*
* pcbReturned - A pointer to a DWORD to receive the size of the buffer
* returned.
*
* Arg1, Arg2 - Arguments specific to the Get* function called,
* as commented below.
*
* Returns:
*
* TRUE if the function is successful.
* A return of false occurs if the specific Get* call fails
* or if the attempt to reallocate the buffer fails.
*
* Author:
*
* andrewbe, August 1992
*
*/
#define GET_ARGS Level, (LPBYTE)*ppGetData, cbBuf, pcbReturned
BOOL
GetGeneric(
IN PROC fnGet,
IN DWORD Level,
IN PBYTE *ppGetData,
IN DWORD cbBuf,
OUT LPDWORD pcbReturned,
IN PVOID Arg1,
IN PVOID Arg2 )
{
BOOL rc = FALSE;
BOOL UnknownFunction = FALSE;
DWORD cbRealloc;
if( fnGet == (PROC)GetPrinter )
rc = GetPrinter( (HANDLE)Arg1, GET_ARGS );
// hPrinter
else
{
*ppGetData = NULL;
UnknownFunction = TRUE;
}
if( ( rc == FALSE ) && ( UnknownFunction == FALSE ) )
{
if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER )
{
cbRealloc = *pcbReturned;
*ppGetData = ReallocSplMem( *ppGetData, cbRealloc );
cbBuf = cbRealloc;
if( *ppGetData )
{
if( fnGet == (PROC)GetPrinter )
rc = GetPrinter( (HANDLE)Arg1, GET_ARGS );
// hPrinter
/* If things haven't worked out, free up the buffer.
* We do this because otherwise the caller will not know
* whether the pointer is valid any more,
* since ReallocSplMem might have failed.
*/
if( rc == FALSE )
{
if( *ppGetData )
FreeSplMem( *ppGetData );
*ppGetData = NULL;
*pcbReturned = 0;
}
}
}
else
{
if( *ppGetData )
FreeSplMem( *ppGetData );
*ppGetData = NULL;
*pcbReturned = 0;
rc = FALSE;
}
}
else
*pcbReturned = cbBuf;
return rc;
}
/*
*
*/
VOID ShowHelp(HWND hWnd, UINT Type, DWORD Data)
{
if( !WinHelp( hWnd, szPrintManHlp, Type, Data ) )
Message( hWnd, MSG_ERROR, IDS_PRINTMANAGER, IDS_COULDNOTSHOWHELP );
}
/* Strip out carriage return and linefeed characters,
* and convert them to spaces:
*/
VOID RemoveCrLf( LPTSTR pString )
{
while( *pString )
{
if( ( 0x0d == *pString ) || ( 0x0a == *pString ) )
*pString = SPACE;
pString++;
}
}
/*
*
*/
LPTSTR
GetErrorString(
DWORD Error
)
{
TCHAR Buffer[1024];
LPTSTR pErrorString = NULL;
DWORD dwFlags;
HANDLE hModule;
if ((Error >= NERR_BASE) && (Error <= MAX_NERR)){
hModule = LoadLibrary(TEXT("NETMSG.DLL"));
dwFlags = FORMAT_MESSAGE_FROM_HMODULE;
}
else {
hModule = NULL;
dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
}
if( FormatMessage( dwFlags, hModule,
Error, 0, Buffer,
sizeof(Buffer)/sizeof(Buffer[0]), NULL )
== 0 )
LoadString( hInst, IDS_UNKNOWN_ERROR, Buffer, sizeof(Buffer)/sizeof(Buffer[0]));
pErrorString = AllocSplStr(Buffer);
if (hModule) {
FreeLibrary(hModule);
}
return pErrorString;
}
/* We need to report failures resulting from the user having insufficient
* privilege differently from other errors.
* This routine allows the caller to pass the resource ID of the string
* to use for each eventuality.
*
* It assumes that the default error string contains one replaceable %s,
* which will be replaced by the error returned.
*
* An attempt will also be made to find a generic error message.
*
* The error code is returned.
*
*/
DWORD ReportFailure( HWND hwndParent,
DWORD idInsufficientPrivilege,
DWORD idDefaultError )
{
DWORD ErrorID;
DWORD MsgType = MSG_ERROR;
LPTSTR pErrorString;
ErrorID = GetLastError( );
if( ( ErrorID == ERROR_ACCESS_DENIED ) && ( idInsufficientPrivilege != 0 ) )
Message( hwndParent, MsgType, IDS_PRINTMANAGER,
idInsufficientPrivilege );
else
{
pErrorString = GetErrorString( ErrorID );
Message( hwndParent, MsgType, IDS_PRINTMANAGER,
idDefaultError, pErrorString );
FreeSplStr( pErrorString );
}
return ErrorID;
}
/* GetUnicodeString
*
* Easy way to get a pointer to a resource string.
* (Remember to free it.)
*/
LPWSTR GetUnicodeString(int id)
{
WCHAR ResString[RESOURCE_STRING_LENGTH];
DWORD length = 0;
LPWSTR pUnicode;
DWORD cbUnicode;
length = LoadStringW(hInst, id, ResString, sizeof(ResString)/sizeof(TCHAR));
cbUnicode = ( length * sizeof ( WCHAR ) + sizeof ( WCHAR ) );
pUnicode = AllocSplMem( cbUnicode );
if( pUnicode )
memcpy( pUnicode, ResString, cbUnicode );
return pUnicode;
}
VOID StripBlanks( LPTSTR p )
{
while( *p++ )
if( *p == SPACE )
*p = TEXT('_');
}
LPTSTR Make8dot3Name( LPTSTR pSourceName )
{
LPTSTR p, pName;
TCHAR NameBuffer[MAX_PRINTER_NAME_LEN+MAX_SHARE_NAME_LEN+1];
LPTSTR p8dot3Name = NULL;
pName = pSourceName;
/* Skip initial blanks:
*/
while( *pName && ( *pName == SPACE ) )
pName++;
/* Skip over all backslashes:
*/
if( p = _tcsrchr( pName, BACKSLASH ) )
{
/* If there's another character after the backslash,
* make that the first character of the name:
*/
if( *(p+1) )
{
pName = p+1;
}
/* Try to find another string before the backslash:
*/
else
{
/* Back through any backslashes at the end of the name:
*/
while( ( *p == BACKSLASH ) && ( p > pName ) )
p--;
/* Back up to any preceding backslash or the beginning
* of the name:
*/
while( ( *p != BACKSLASH ) && ( p > pName ) )
p--;
if( *p == BACKSLASH )
p++;
pName = p;
}
}
/* Copy the complete name:
*/
_tcscpy( NameBuffer, pName );
StripBlanks( NameBuffer );
NameBuffer[8] = NULLC;
FreeSplStr( pSourceName );
return AllocSplStr( NameBuffer );
}
BOOL
Is8dot3Name(
IN LPTSTR FileName)
/*++
Routine Description:
This routine computes whether or not the given file name would
be appropriate under DOS's 8.3 naming convention.
Arguments:
FileName - Supplies the file name to check.
Return Value:
FALSE - The supplied name is not a DOS file name.
TRUE - The supplied name is a valid DOS file name.
--*/
{
ULONG i, n, name_length, ext_length;
BOOLEAN dot_yet;
PTUCHAR p;
n = lstrlen(FileName);
p = (PTUCHAR) FileName;
name_length = n;
ext_length = 0;
if (n > 12) {
return FALSE;
}
dot_yet = FALSE;
for (i = 0; i < n; i++) {
if (p[i] < 32) {
return FALSE;
}
switch (p[i]) {
case L'*':
case L'?':
case L'/':
case L'\\':
case L'|':
case L',':
case L';':
case L':':
case L'+':
case L'=':
case L'<':
case L'>':
case L'[':
case L']':
case L'"':
return FALSE;
case L'.':
if (dot_yet) {
return FALSE;
}
dot_yet = TRUE;
name_length = i;
ext_length = n - i - 1;
break;
}
}
if (!name_length) {
return dot_yet && n == 1;
}
if (name_length > 8 || p[name_length - 1] == L' ') {
return FALSE;
}
if (!ext_length) {
return !dot_yet;
}
if (ext_length > 3 || p[name_length + 1 + ext_length - 1] == L' ') {
return FALSE;
}
return TRUE;
}
#if DBG
VOID EnterProtectedData( PMDIWIN_INFO pInfo )
{
DWORD CurrentThreadId;
CurrentThreadId = GetCurrentThreadId();
if( pInfo->DataMutexOwner != CurrentThreadId )
{
DBGMSG( DBG_MUTEX, ( "Thread %d: %x WaitForSingleObject( %x ) (DATA)\n",
CurrentThreadId, pInfo, pInfo->DataMutex ) );
}
WaitForSingleObject( pInfo->DataMutex, INFINITE );
if( pInfo->DataMutexOwner != CurrentThreadId )
{
DBGMSG( DBG_MUTEX, ( "Thread %d: %x WaitForSingleObject( %x ) (DATA) returned\n",
CurrentThreadId, pInfo, pInfo->DataMutex ) );
}
pInfo->DataMutexOwner = CurrentThreadId;
pInfo->DataMutexCount++;
DBGMSG( DBG_MUTEX, ( "Owner %d: %x Mutex %x; Count %d\n",
CurrentThreadId, pInfo, pInfo->DataMutex, pInfo->DataMutexCount ) );
}
VOID LeaveProtectedData( PMDIWIN_INFO pInfo )
{
DWORD CurrentThreadId;
CurrentThreadId = GetCurrentThreadId();
if( pInfo->DataMutexCount == 0 )
{
DBGMSG( DBG_ERROR, ( "%x Mutex count == 0 in LeaveProtectedData\n",
pInfo) );
}
pInfo->DataMutexCount--;
pInfo->DataMutexOwner = ( pInfo->DataMutexCount ?
pInfo->DataMutexOwner :
0 );
if( !pInfo->DataMutexCount )
{
DBGMSG( DBG_MUTEX, ( "Thread %d: %x ReleaseMutex( %x ) (DATA)\n",
CurrentThreadId, pInfo, pInfo->DataMutex ) );
}
DBGMSG( DBG_MUTEX, ( "Owner %d: %x Mutex %x; Count %d\n",
pInfo->DataMutexOwner, pInfo, pInfo->DataMutex, pInfo->DataMutexCount ) );
ReleaseMutex( pInfo->DataMutex );
}
#endif /* DBG */
#if DBG
VOID DbgMsg( CHAR *MsgFormat, ... )
{
CHAR MsgText[256];
va_list vargs;
va_start( vargs, MsgFormat );
wvsprintfA( MsgText, MsgFormat, vargs );
va_end( vargs );
if( *MsgText )
OutputDebugStringA( "PRINTMAN: " );
OutputDebugStringA( MsgText );
}
#endif /* DBG*/