windows-nt/Source/XPSP1/NT/printscan/print/spooler/spoolss/client/util.c
2020-09-26 16:20:57 +08:00

882 lines
19 KiB
C

/*++
Copyright (c) 1990 - 1995 Microsoft Corporation
Module Name:
util.c
Abstract:
Client Side Utility Routines
Author:
Dave Snipp (DaveSn) 15-Mar-1991
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "client.h"
HANDLE hCSR = INVALID_HANDLE_VALUE;
BOOL
InCSRProcess(
VOID
)
{
//
// hCSR == INVALID_HANDLE_VALUE Not initialized, must check.
// NULL Not running in CSR
// hModule value Running in CSR
//
if (hCSR != NULL) {
//
// Check if we are running in CSR. If so, then don't try
// any notifications.
//
if (hCSR == INVALID_HANDLE_VALUE) {
hCSR = GetModuleHandle( gszCSRDll );
}
}
return hCSR != NULL;
}
LPVOID
DllAllocSplMem(
DWORD cb
)
/*++
Routine Description:
This function will allocate local memory. It will possibly allocate extra
memory and fill this with debugging information for the debugging version.
Arguments:
cb - The amount of memory to allocate
Return Value:
NON-NULL - A pointer to the allocated memory
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
PDWORD_PTR pMem;
DWORD cbNew;
cb = DWORD_ALIGN_UP(cb);
cbNew = cb+sizeof(DWORD_PTR)+sizeof(DWORD);
pMem= LocalAlloc(LPTR, cbNew);
if (!pMem) {
DBGMSG( DBG_WARNING, ("Memory Allocation failed for %d bytes\n", cbNew ));
return 0;
}
*pMem=cb;
*(LPDWORD)((LPBYTE)pMem+cbNew-sizeof(DWORD))=0xdeadbeef;
return (LPVOID)(pMem+1);
}
BOOL
DllFreeSplMem(
LPVOID pMem
)
{
DWORD_PTR cbNew;
PDWORD_PTR pNewMem;
if( !pMem ){
return TRUE;
}
pNewMem = pMem;
pNewMem--;
cbNew = *pNewMem;
if (*(LPDWORD)((LPBYTE)pMem + cbNew) != 0xdeadbeef) {
DBGMSG(DBG_ERROR, ("DllFreeSplMem Corrupt Memory in winspool : %0p\n", pNewMem));
return FALSE;
}
memset(pNewMem, 0x65, (size_t) cbNew);
LocalFree((LPVOID)pNewMem);
return TRUE;
}
LPVOID
ReallocSplMem(
LPVOID pOldMem,
DWORD cbOld,
DWORD cbNew
)
{
LPVOID pNewMem;
pNewMem=AllocSplMem(cbNew);
if (pOldMem && pNewMem) {
if (cbOld) {
CopyMemory( pNewMem, pOldMem, min(cbNew, cbOld));
}
FreeSplMem(pOldMem);
}
return pNewMem;
}
LPTSTR
AllocSplStr(
LPCTSTR pStr
)
/*++
Routine Description:
This function will allocate enough local memory to store the specified
string, and copy that string to the allocated memory
Arguments:
pStr - 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 pMem;
if (!pStr)
return 0;
if (pMem = AllocSplMem( _tcslen(pStr)*sizeof(TCHAR) + sizeof(TCHAR) ))
_tcscpy(pMem, pStr);
return pMem;
}
BOOL
DllFreeSplStr(
LPTSTR pStr
)
{
return pStr ?
DllFreeSplMem(pStr) :
FALSE;
}
BOOL
ReallocSplStr(
LPTSTR *ppStr,
LPCTSTR pStr
)
{
LPWSTR pOldStr = *ppStr;
*ppStr=AllocSplStr(pStr);
FreeSplStr(pOldStr);
return TRUE;
}
/* Message
*
* Displays a message by loading the strings whose IDs are passed into
* the function, and substituting the supplied variable argument list
* using the varargs macros.
*
*/
INT
Message(
HWND hwnd,
DWORD Type,
INT CaptionID,
INT TextID,
...
)
{
TCHAR MsgText[256];
TCHAR MsgFormat[256];
TCHAR MsgCaption[40];
va_list vargs;
if( ( LoadString( hInst, TextID, MsgFormat,
COUNTOF(MsgFormat)) > 0 )
&& ( LoadString( hInst, CaptionID, MsgCaption, COUNTOF(MsgCaption) ) > 0 ) )
{
va_start( vargs, TextID );
wvsprintf( MsgText, MsgFormat, vargs );
va_end( vargs );
return MessageBox( hwnd, MsgText, MsgCaption, Type );
}
else
return 0;
}
/*
*
*/
LPTSTR
GetErrorString(
DWORD Error
)
{
TCHAR Buffer[1024];
LPTSTR pErrorString = NULL;
DWORD dwFlags;
HANDLE hModule;
if ((Error >= NERR_BASE) && (Error <= MAX_NERR)){
hModule = LoadLibrary(szNetMsgDll);
dwFlags = FORMAT_MESSAGE_FROM_HMODULE;
}
else {
hModule = NULL;
dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
}
if( FormatMessage( dwFlags, hModule,
Error, 0, Buffer,
COUNTOF(Buffer), NULL )
== 0 )
LoadString( hInst, IDS_UNKNOWN_ERROR, Buffer,
COUNTOF(Buffer));
pErrorString = AllocSplStr(Buffer);
if (hModule) {
FreeLibrary(hModule);
}
return pErrorString;
}
DWORD ReportFailure( HWND hwndParent,
DWORD idTitle,
DWORD idDefaultError )
{
DWORD ErrorID;
DWORD MsgType;
LPTSTR pErrorString;
ErrorID = GetLastError( );
MsgType = MB_OK | MB_ICONSTOP;
pErrorString = GetErrorString( ErrorID );
Message( hwndParent, MsgType, idTitle,
idDefaultError, pErrorString );
FreeSplStr( pErrorString );
return ErrorID;
}
/*
*
*/
#define ENTRYFIELD_LENGTH 256
LPTSTR AllocDlgItemText(HWND hwnd, int id)
{
TCHAR string[ENTRYFIELD_LENGTH];
GetDlgItemText (hwnd, id, string, COUNTOF(string));
return ( *string ? AllocSplStr(string) : NULL );
}
PSECURITY_DESCRIPTOR
BuildInputSD(
PSECURITY_DESCRIPTOR pPrinterSD,
PDWORD pSizeSD
)
/*++
--*/
{
SECURITY_DESCRIPTOR AbsoluteSD;
PSECURITY_DESCRIPTOR pRelative;
BOOL Defaulted = FALSE;
BOOL DaclPresent = FALSE;
BOOL SaclPresent = FALSE;
PSID pOwnerSid = NULL;
PSID pGroupSid = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
DWORD SDLength = 0;
//
// Initialize *pSizeSD = 0;
//
*pSizeSD = 0;
if (!IsValidSecurityDescriptor(pPrinterSD)) {
return(NULL);
}
if (!InitializeSecurityDescriptor (&AbsoluteSD, SECURITY_DESCRIPTOR_REVISION1)) {
return(NULL);
}
if(!GetSecurityDescriptorOwner(pPrinterSD,
&pOwnerSid, &Defaulted)){
return(NULL);
}
SetSecurityDescriptorOwner(&AbsoluteSD,
pOwnerSid, Defaulted );
if(! GetSecurityDescriptorGroup( pPrinterSD,
&pGroupSid, &Defaulted )){
return(NULL);
}
SetSecurityDescriptorGroup( &AbsoluteSD,
pGroupSid, Defaulted );
if(!GetSecurityDescriptorDacl( pPrinterSD,
&DaclPresent, &pDacl, &Defaulted )){
return(NULL);
}
SetSecurityDescriptorDacl( &AbsoluteSD,
DaclPresent, pDacl, Defaulted );
if(!GetSecurityDescriptorSacl( pPrinterSD,
&SaclPresent, &pSacl, &Defaulted)){
return(NULL);
}
SetSecurityDescriptorSacl( &AbsoluteSD,
SaclPresent, pSacl, Defaulted );
SDLength = GetSecurityDescriptorLength( &AbsoluteSD);
pRelative = LocalAlloc(LPTR, SDLength);
if (!pRelative) {
return(NULL);
}
if (!MakeSelfRelativeSD (&AbsoluteSD, pRelative, &SDLength)) {
LocalFree(pRelative);
return(NULL);
}
*pSizeSD = SDLength;
return(pRelative);
}
PKEYDATA
CreateTokenList(
LPWSTR pKeyData
)
{
DWORD cTokens;
DWORD cb;
PKEYDATA pResult;
LPWSTR pDest;
LPWSTR psz = pKeyData;
LPWSTR *ppToken;
if (!psz || !*psz)
return NULL;
cTokens=1;
/* Scan through the string looking for commas,
* ensuring that each is followed by a non-NULL character:
*/
while ((psz = wcschr(psz, L',')) && psz[1]) {
cTokens++;
psz++;
}
cb = sizeof(KEYDATA) + (cTokens-1) * sizeof(LPWSTR) +
wcslen(pKeyData)*sizeof(WCHAR) + sizeof(WCHAR);
if (!(pResult = (PKEYDATA)AllocSplMem(cb)))
return NULL;
pResult->cb = cb;
/* Initialise pDest to point beyond the token pointers:
*/
pDest = (LPWSTR)((LPBYTE)pResult + sizeof(KEYDATA) +
(cTokens-1) * sizeof(LPWSTR));
/* Then copy the key data buffer there:
*/
wcscpy(pDest, pKeyData);
ppToken = pResult->pTokens;
psz = pDest;
do {
*ppToken++ = psz;
if ( psz = wcschr(psz, L',') )
*psz++ = L'\0';
} while (psz);
pResult->cTokens = cTokens;
return( pResult );
}
LPWSTR
GetPrinterPortList(
HANDLE hPrinter
)
{
LPBYTE pMem;
LPTSTR pPort;
DWORD dwPassed = 1024; //Try 1K to start with
LPPRINTER_INFO_2 pPrinter;
DWORD dwLevel = 2;
DWORD dwNeeded;
PKEYDATA pKeyData;
DWORD i = 0;
LPWSTR pPortNames = NULL;
pMem = AllocSplMem(dwPassed);
if (pMem == NULL) {
return FALSE;
}
if (!GetPrinter(hPrinter, dwLevel, pMem, dwPassed, &dwNeeded)) {
DBGMSG(DBG_TRACE, ("Last error is %d\n", GetLastError()));
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return NULL;
}
pMem = ReallocSplMem(pMem, dwPassed, dwNeeded);
dwPassed = dwNeeded;
if (!GetPrinter(hPrinter, dwLevel, pMem, dwPassed, &dwNeeded)) {
FreeSplMem(pMem);
return (NULL);
}
}
pPrinter = (LPPRINTER_INFO_2)pMem;
//
// Fixes the null pPrinter->pPortName problem where
// downlevel may return null
//
if (!pPrinter->pPortName) {
FreeSplMem(pMem);
return(NULL);
}
pPortNames = AllocSplStr(pPrinter->pPortName);
FreeSplMem(pMem);
return(pPortNames);
}
BOOL
UpdateString(
IN LPCTSTR pszString, OPTIONAL
OUT LPTSTR* ppszOut
)
/*++
Routine Description:
Updates an output string if the input is non-NULL.
Arguments:
pszString - String to update to. If NULL or -1, function does nothing.
Return Value:
TRUE - Success
FALSE - FAILED. *ppszOut = NULL
--*/
{
if( pszString && pszString != (LPCTSTR)-1 ){
FreeSplStr( *ppszOut );
*ppszOut = AllocSplStr( pszString );
if( !*ppszOut ){
return FALSE;
}
}
return TRUE;
}
DWORD
RouterFreeBidiResponseContainer(
PBIDI_RESPONSE_CONTAINER pData
)
{
BIDI_RESPONSE_DATA *p;
DWORD Count = 0;
DWORD NumOfRspns;
DWORD dwRet = ERROR_SUCCESS;
try
{
if(pData)
{
Count = pData->Count;
for(NumOfRspns= 0,
p = &pData->aData[0];
NumOfRspns < Count;
NumOfRspns++,
p++
)
{
if(p)
{
if(p->pSchema)
{
MIDL_user_free(p->pSchema);
}
switch(p->data.dwBidiType)
{
//
// Text Data (ANSI String)
//
case BIDI_TEXT:
//
// String (UNICODE string)
//
case BIDI_ENUM:
//
// Enumeration Data (ANSI String)
//
case BIDI_STRING:
{
if(p->data.u.sData)
{
MIDL_user_free(p->data.u.sData);
}
}
break;
//
// Binary Data (BLOB)
//
case BIDI_BLOB:
{
if(p->data.u.biData.pData)
{
MIDL_user_free(p->data.u.biData.pData);
}
}
break;
//
// Undefined Type
//
default:
{
//
// Nothing really , just return
//
}
break;
}
}
}
MIDL_user_free(pData);
}
}
except(1)
{
dwRet = TranslateExceptionCode(GetExceptionCode());
DBGMSG(DBG_ERROR, ("RouterFreeBidiResponseContainer raised an exception : %u \n", dwRet));
}
return(dwRet);
}
ClientVersion
GetClientVer()
{
ClientVersion ClientVer;
return(ClientVer = sizeof(ULONG_PTR));
}
ServerVersion
GetServerVer()
{
ULONG_PTR ul;
NTSTATUS st;
ServerVersion CurrVer;
st = NtQueryInformationProcess(NtCurrentProcess(),
ProcessWow64Information,
&ul,
sizeof(ul),
NULL);
if (NT_SUCCESS(st))
{
// If this call succeeds, we're on Win2000 or newer machines.
if (0 != ul)
{
// 32-bit code running on Win64
CurrVer = THUNKVERSION;
} else
{
// 32-bit code running on Win2000 or later 32-bit OS
CurrVer = NATIVEVERSION;
}
} else
{
CurrVer = NATIVEVERSION;
}
return(CurrVer);
}
BOOL
RunInWOW64()
{
return((GetClientVer() == RUN32BINVER) &&
(GetServerVer() == THUNKVERSION) &&
!bLoadedBySpooler);
/*return(bLoadedBySpooler ? FALSE : TRUE);*/
}
HWND
GetForeGroundWindow(
VOID
)
{
//
// get the foreground window first
//
HWND hWndOwner;
HWND hWndLastPopup;
HWND hWndForeground = GetForegroundWindow();
//
// climb up to the top parent in case it's a child window...
//
HWND hWndParent = hWndForeground;
while ( hWndParent = GetParent(hWndParent) )
{
hWndForeground = hWndParent;
}
//
// get the owner in case the top parent is owned
//
hWndOwner= GetWindow(hWndForeground, GW_OWNER);
if ( hWndOwner )
{
hWndForeground = hWndOwner;
}
hWndLastPopup = GetLastActivePopup(hWndForeground);
return(hWndLastPopup);
}
LPCWSTR
FindFileName(
IN LPCWSTR pPathName
)
/*++
Routine Description:
Retrieve the filename portion of a path.
This will can the input string until it finds the last backslash,
then return the portion of the string immediately following it.
If the string terminates with a backslash, then NULL is returned.
Note: this can return illegal file names; no validation is done.
Arguments:
pPathName - Path name to parse.
Return Value:
Last portion of file name or NULL if none available.
--*/
{
LPCWSTR pSlash;
LPCWSTR pTemp;
if( !pPathName ){
return NULL;
}
pTemp = pPathName;
while( pSlash = wcschr( pTemp, L'\\' )) {
pTemp = pSlash+1;
}
if( !*pTemp ){
return NULL;
}
return pTemp;
}
/*++
Name:
BuildSpoolerObjectPath
Description:
This function addresses bug 461462. When the spooler is not running,
this function can build the path to the drivers directory or the print
processors directory. The result of this function is a path like:
C:\Windows\System32\spool\Drivers\w32x86
or
C:\Windows\System32\spool\Prtprocs\w32x86
depending on the pszPath argument.
Arguments:
pszPath - can be "drivers" or "prtprocs"
pszName - must be NULL or ""
pszEnvironment - can be "windows nt x86" etc. This argument must be validated by the caller
(GetPrinterDriverDirectoryW and GetPrintProcessorDirectoryW)
Level - must be 1
pDriverDirectory - buffer where to store the path
cbBuf - count of bytes in the buffer
pcbNeeded - count of bytes needed to store the path
Return Value:
TRUE - the function succeeded, pDriverDirectory can be used
FALSE - the function failed, pDriverDirectory cannot be used.
Last error:
This function sets the last error in both failure and success cases.
--*/
BOOL
BuildSpoolerObjectPath(
IN PCWSTR pszPath,
IN PCWSTR pszName,
IN PCWSTR pszEnvironment,
IN DWORD Level,
IN PBYTE pDriverDirectory,
IN DWORD cbBuf,
IN PDWORD pcbNeeded
)
{
DWORD Error = ERROR_INVALID_PARAMETER;
if (pcbNeeded && (!pszName || !*pszName))
{
HKEY hkRoot = NULL;
HKEY hkEnv = NULL;
DWORD cchDir = MAX_PATH;
WCHAR szDir[MAX_PATH];
Error = GetSystemWindowsDirectory(szDir, cchDir) ? ERROR_SUCCESS : GetLastError();
if (Error == ERROR_SUCCESS &&
(Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
gszRegEnvironments,
0,
KEY_READ,
&hkRoot)) == ERROR_SUCCESS &&
(Error = RegOpenKeyEx(hkRoot,
pszEnvironment,
0,
KEY_READ,
&hkEnv)) == ERROR_SUCCESS &&
(Error = StrNCatBuff(szDir,
cchDir,
szDir,
szSlash,
gszSystem32Spool,
szSlash,
pszPath,
szSlash,
NULL)) == ERROR_SUCCESS)
{
DWORD Length = wcslen(szDir);
DWORD cbAvailable = (cchDir - Length) * sizeof(WCHAR);
if ((Error = RegQueryValueEx(hkEnv,
gszEnivronmentDirectory,
NULL,
NULL,
(PBYTE)&szDir[Length],
&cbAvailable)) == ERROR_SUCCESS)
{
*pcbNeeded = (wcslen(szDir) + 1) * sizeof(WCHAR);
if (cbBuf >= *pcbNeeded)
{
wcscpy((PWSTR)pDriverDirectory, szDir);
}
else
{
Error = ERROR_INSUFFICIENT_BUFFER;
}
}
}
else if (Error == ERROR_FILE_NOT_FOUND)
{
//
// If we cannot open the "pszEnvironment" key then the environment is invalid.
//
Error = ERROR_INVALID_ENVIRONMENT;
}
if (hkRoot) RegCloseKey(hkRoot);
if (hkEnv) RegCloseKey(hkEnv);
}
SetLastError(Error);
return Error == ERROR_SUCCESS;
}