#include "cstore.hxx" HRESULT GetAppmgmtIniFilePath( PSID pSid, LPWSTR* ppwszPath ) { UNICODE_STRING SidString; PTOKEN_USER pTokenUser; WCHAR wszPath[MAX_PATH]; WCHAR * pwszSystemDir; DWORD AllocLength; DWORD Length; DWORD Size; DWORD Status; BOOL bStatus; Status = ERROR_SUCCESS; *ppwszPath = 0; pwszSystemDir = wszPath; AllocLength = sizeof(wszPath) / sizeof(WCHAR); for (;;) { Length = GetSystemDirectory( pwszSystemDir, AllocLength ); if ( 0 == Length ) return HRESULT_FROM_WIN32(GetLastError()); if ( Length >= AllocLength ) { AllocLength = Length + 1; // // No check for failure of alloca since it throws an // exception on failure // pwszSystemDir = (WCHAR *) alloca( AllocLength * sizeof(WCHAR) ); continue; } break; } if ( pSid ) { if ( ERROR_SUCCESS == Status ) { Status = RtlConvertSidToUnicodeString( &SidString, pSid, TRUE ); } if ( Status != ERROR_SUCCESS ) return HRESULT_FROM_WIN32(Status); } else { RtlInitUnicodeString( &SidString, L"MACHINE" ); } // System dir + \appmgmt\ + Sid \ + inifilename \ + null *ppwszPath = new WCHAR[Length + 11 + (SidString.Length / 2) + (sizeof(APPMGMT_INI_FILENAME) / sizeof(WCHAR))]; if ( *ppwszPath ) { lstrcpy( *ppwszPath, pwszSystemDir ); if ( pwszSystemDir[lstrlen(pwszSystemDir)-1] != L'\\' ) lstrcat( *ppwszPath, L"\\" ); lstrcat( *ppwszPath, L"appmgmt\\" ); lstrcat( *ppwszPath, SidString.Buffer ); lstrcat( *ppwszPath, APPMGMT_INI_FILENAME ); } else { Status = ERROR_OUTOFMEMORY; } if ( pSid ) RtlFreeUnicodeString( &SidString ); return HRESULT_FROM_WIN32(Status); } HRESULT ReadClassStorePath(PSID pSid, LPWSTR* ppwszClassStorePath) { HRESULT hr; LPWSTR wszIniFilePath; hr = GetAppmgmtIniFilePath( pSid, &wszIniFilePath); if (FAILED(hr)) { return hr; } DWORD nBufferSize; DWORD nCharsReceived; LPWSTR wszResult; nBufferSize = DEFAULT_CSPATH_LENGTH; wszResult = NULL; // // The GetPrivateProfileString function is so horribly designed // that we have to write this disgusting code below to deal with it // for (DWORD dwRetry = 0; dwRetry < 7; dwRetry++) { WCHAR DefaultBuffer = L'\0'; wszResult = new WCHAR [nBufferSize]; if (!wszResult) { hr = E_OUTOFMEMORY; break; } // // It turns out that this api has other issues as well -- if the file // doesn't exist it doesn't even return an error that would // make sense (like 0) -- instead, I've seen it return 8! // To get around this interesting behavior, I'll set the first // character of the string to L'\0' before calling the api -- this means that // subsequent code will treat the failure as if we read a // zero length class store path from the file, which is the // desired behavior. // *wszResult = L'\0'; nCharsReceived = GetPrivateProfileString( APPMGMT_INI_CSTORE_SECTIONNAME, APPMGMT_INI_CSPATH_KEYNAME, &DefaultBuffer, wszResult, nBufferSize, wszIniFilePath); // // If nothing is written, then there's no point in going forward // since this api returns the number of characters we need to write // if (!nCharsReceived) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); break; } if (nCharsReceived != (nBufferSize - 1)) { break; } // // Double the size of the allocation // nBufferSize *= 2; // // Free the previous allocation // delete [] wszResult; wszResult = NULL; } if (wszResult && nCharsReceived) { LPWSTR wszAllocatedCSPathForCaller; *ppwszClassStorePath = new WCHAR[nCharsReceived + 1]; if (*ppwszClassStorePath) { wcscpy(*ppwszClassStorePath, wszResult); } else { hr = E_OUTOFMEMORY; } } delete [] wszResult; delete [] wszIniFilePath; return hr; }