882 lines
19 KiB
C
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;
|
|
}
|
|
|
|
|
|
|