Source code of Windows XP (NT5)
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.

808 lines
23 KiB

  1. /************************************************************************
  2. Copyright (c) 2000 - 2000 Microsoft Corporation
  3. Module Name :
  4. helpers.cpp
  5. Abstract :
  6. General helper functions.
  7. Author :
  8. Revision History :
  9. ***********************************************************************/
  10. #include "qmgrlibp.h"
  11. #include <bitsmsg.h>
  12. #include <sddl.h>
  13. #include <shlwapi.h>
  14. #if !defined(BITS_V12_ON_NT4)
  15. #include "helpers.tmh"
  16. #endif
  17. FILETIME GetTimeAfterDelta( UINT64 uDelta )
  18. {
  19. FILETIME ftCurrentTime;
  20. GetSystemTimeAsFileTime( &ftCurrentTime );
  21. UINT64 uCurrentTime = FILETIMEToUINT64( ftCurrentTime );
  22. uCurrentTime += uDelta;
  23. return UINT64ToFILETIME( uCurrentTime );
  24. }
  25. //---------------------------------------------------------------------
  26. // QmgrFileExists
  27. // Checks if a file exists.
  28. //
  29. // Returns: TRUE if false exists, FALSE otherwise
  30. //---------------------------------------------------------------------
  31. BOOL QMgrFileExists(LPCTSTR szFile)
  32. {
  33. DWORD dwAttr = GetFileAttributes(szFile);
  34. if (dwAttr == 0xFFFFFFFF) //failed
  35. return FALSE;
  36. return (BOOL)(!(dwAttr & FILE_ATTRIBUTE_DIRECTORY));
  37. }
  38. //
  39. // Class for managing global static data that is different per installation
  40. //
  41. class GlobalInfo *g_GlobalInfo = NULL;
  42. GlobalInfo::GlobalInfo( TCHAR * QmgrDirectory,
  43. LARGE_INTEGER PerformanceCounterFrequency,
  44. HKEY QmgrRegistryRoot,
  45. UINT64 JobInactivityTimeout,
  46. UINT64 TimeQuantaLength,
  47. UINT32 DefaultNoProgressTimeout,
  48. UINT32 DefaultMinimumRetryDelay,
  49. SECURITY_DESCRIPTOR *MetadataSecurityDescriptor,
  50. DWORD MetadataSecurityDescriptorLength,
  51. SidHandle AdministratorsSid,
  52. SidHandle LocalSystemSid,
  53. SidHandle NetworkUsersSid
  54. ) :
  55. m_QmgrDirectory( QmgrDirectory ),
  56. m_PerformanceCounterFrequency( PerformanceCounterFrequency ),
  57. m_QmgrRegistryRoot( QmgrRegistryRoot ),
  58. m_JobInactivityTimeout( JobInactivityTimeout ),
  59. m_TimeQuantaLength( TimeQuantaLength ),
  60. m_DefaultNoProgressTimeout( DefaultNoProgressTimeout ),
  61. m_DefaultMinimumRetryDelay( DefaultMinimumRetryDelay ),
  62. m_MetadataSecurityDescriptor( MetadataSecurityDescriptor ),
  63. m_MetadataSecurityDescriptorLength( MetadataSecurityDescriptorLength ),
  64. m_AdministratorsSid( AdministratorsSid ),
  65. m_LocalSystemSid( LocalSystemSid ),
  66. m_NetworkUsersSid( NetworkUsersSid )
  67. {
  68. }
  69. GlobalInfo::~GlobalInfo()
  70. {
  71. delete[] (TCHAR*)m_QmgrDirectory;
  72. delete (SECURITY_DESCRIPTOR*)m_MetadataSecurityDescriptor;
  73. if ( m_QmgrRegistryRoot )
  74. CloseHandle( m_QmgrRegistryRoot );
  75. }
  76. DWORD
  77. GlobalInfo::RegGetDWORD(
  78. HKEY hKey,
  79. const TCHAR * pValue,
  80. DWORD dwDefault )
  81. {
  82. DWORD dwValue;
  83. DWORD dwType = REG_DWORD;
  84. DWORD dwSize = sizeof(dwValue);
  85. LONG lResult =
  86. RegQueryValueEx( //SEC: REVIEWED 2002-03-28
  87. hKey,
  88. pValue,
  89. NULL,
  90. &dwType,
  91. (LPBYTE)&dwValue,
  92. &dwSize );
  93. if ( ERROR_SUCCESS != lResult ||
  94. dwType != REG_DWORD ||
  95. dwSize != sizeof(dwValue)
  96. )
  97. {
  98. LogWarning( "Unable to read the registry value %!ts!, using default value of %u",
  99. pValue, dwDefault );
  100. return dwDefault;
  101. }
  102. LogInfo( "Retrieved registry value %u from key value %!ts!",
  103. dwValue, pValue );
  104. return dwValue;
  105. }
  106. SidHandle
  107. BITSAllocateAndInitializeSid(
  108. BYTE nSubAuthorityCount, // count of subauthorities
  109. DWORD dwSubAuthority0, // subauthority 0
  110. DWORD dwSubAuthority1 ) // subauthority 1
  111. {
  112. ASSERT( nSubAuthorityCount <= 2 );
  113. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
  114. PSID pSid = NULL;
  115. if(! AllocateAndInitializeSid( //SEC: REVIEWED 2002-03-28
  116. &Authority,
  117. nSubAuthorityCount,
  118. dwSubAuthority0,
  119. dwSubAuthority1,
  120. 0, 0, 0, 0, 0, 0,
  121. &pSid) )
  122. {
  123. HRESULT hResult = HRESULT_FROM_WIN32(GetLastError());
  124. LogError( "AllocateAndInitializeSid failed, error %!winerr!\n" , hResult );
  125. throw ComError( hResult );
  126. }
  127. SidHandle NewSid( DuplicateSid( pSid ) );
  128. FreeSid( pSid );
  129. pSid = NULL;
  130. if ( !NewSid.get())
  131. {
  132. LogError( "Unable to duplicate sid, error %!winerr!\n" , E_OUTOFMEMORY );
  133. throw ComError( E_OUTOFMEMORY );
  134. }
  135. return NewSid;
  136. }
  137. StringHandle
  138. BITSSHGetFolderPath(
  139. HWND hwndOwner,
  140. int nFolder,
  141. HANDLE hToken,
  142. DWORD dwFlags )
  143. {
  144. auto_ptr<WCHAR> Folder( new WCHAR[ MAX_PATH ] );
  145. HRESULT hResult =
  146. SHGetFolderPath(
  147. hwndOwner,
  148. nFolder,
  149. hToken,
  150. dwFlags,
  151. Folder.get() );
  152. if (FAILED(hResult))
  153. {
  154. LogError( "SHGetFolderPathFailed, error %!winerr!", hResult );
  155. throw ComError( hResult );
  156. }
  157. return StringHandle( Folder.get() );
  158. }
  159. HRESULT GlobalInfo::Init()
  160. /*
  161. Initialize the global info for BITS.
  162. */
  163. {
  164. GlobalInfo *pGlobalInfo = NULL;
  165. HKEY hQmgrKey = NULL;
  166. HKEY hQmgrPolicyKey = NULL;
  167. PACL pDacl = NULL;
  168. LogInfo( "Starting init of global info\n" );
  169. try
  170. {
  171. DWORD dwResult;
  172. HRESULT hResult = E_FAIL;
  173. DWORD dwReturnLength;
  174. LARGE_INTEGER PerformanceCounterFrequency;
  175. BOOL bResult = QueryPerformanceFrequency( &PerformanceCounterFrequency );
  176. if ( !bResult )
  177. throw ComError( E_FAIL );
  178. SidHandle AdministratorsSid =
  179. BITSAllocateAndInitializeSid(
  180. 2,
  181. SECURITY_BUILTIN_DOMAIN_RID,
  182. DOMAIN_ALIAS_RID_ADMINS );
  183. SidHandle LocalSystemSid =
  184. BITSAllocateAndInitializeSid(
  185. 1,
  186. SECURITY_LOCAL_SYSTEM_RID, 0 );
  187. SidHandle NetworkUsersSid =
  188. BITSAllocateAndInitializeSid(
  189. 1,
  190. SECURITY_NETWORK_RID, 0);
  191. // initialize the metadata's security descriptor.
  192. auto_ptr<char> TempSDDataPtr( new char[SECURITY_DESCRIPTOR_MIN_LENGTH] );
  193. PSECURITY_DESCRIPTOR pTempSD = (PSECURITY_DESCRIPTOR)TempSDDataPtr.get();
  194. InitializeSecurityDescriptor(pTempSD, SECURITY_DESCRIPTOR_REVISION); //SEC: REVIEWED 2002-03-28
  195. auto_ptr<EXPLICIT_ACCESS> ExplicitAccessPtr( new EXPLICIT_ACCESS[2] );
  196. EXPLICIT_ACCESS *ExplicitAccess = ExplicitAccessPtr.get();
  197. memset( ExplicitAccess, 0, sizeof(EXPLICIT_ACCESS) * 2); //SEC: REVIEWED 2002-03-28
  198. ExplicitAccess[0].grfAccessPermissions = GENERIC_ALL;
  199. ExplicitAccess[0].grfAccessMode = SET_ACCESS;
  200. ExplicitAccess[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  201. ExplicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  202. ExplicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  203. ExplicitAccess[0].Trustee.ptstrName = (LPTSTR) AdministratorsSid.get();
  204. ExplicitAccess[1].grfAccessPermissions = GENERIC_ALL;
  205. ExplicitAccess[1].grfAccessMode = SET_ACCESS;
  206. ExplicitAccess[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  207. ExplicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  208. ExplicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_USER;
  209. ExplicitAccess[1].Trustee.ptstrName = (LPTSTR) LocalSystemSid.get();
  210. dwResult = SetEntriesInAcl( //SEC: REVIEWED 2002-03-28
  211. 2,
  212. ExplicitAccess,
  213. NULL,
  214. &pDacl );
  215. if ( ERROR_SUCCESS != dwResult )
  216. {
  217. hResult = HRESULT_FROM_WIN32( dwResult );
  218. LogError( "SetEntiesInAcl, error %!winerr!\n", hResult );
  219. throw ComError( hResult );
  220. }
  221. if (!SetSecurityDescriptorDacl( //SEC: REVIEWED 2002-03-28
  222. pTempSD,
  223. TRUE, // fDaclPresent flag
  224. pDacl,
  225. FALSE)) // not a default DACL
  226. {
  227. hResult = HRESULT_FROM_WIN32( GetLastError() );
  228. LogError( "SetSecurityDescriptorDacl, error %!winerr!", hResult );
  229. throw ComError( hResult );
  230. }
  231. DWORD dwRequiredSecurityDescriptorLength = 0;
  232. MakeSelfRelativeSD( pTempSD, NULL, &dwRequiredSecurityDescriptorLength );
  233. auto_ptr<SECURITY_DESCRIPTOR> pMetadataSecurityDescriptor(
  234. (SECURITY_DESCRIPTOR*)new char[dwRequiredSecurityDescriptorLength] );
  235. if (!pMetadataSecurityDescriptor.get())
  236. {
  237. throw ComError( E_OUTOFMEMORY );
  238. }
  239. if (!MakeSelfRelativeSD( pTempSD, pMetadataSecurityDescriptor.get(), &dwRequiredSecurityDescriptorLength ) )
  240. {
  241. hResult = HRESULT_FROM_WIN32(GetLastError());
  242. LogError( "MakeSelfRelativeSD, error %!winerr!", hResult );
  243. throw ComError( hResult );
  244. }
  245. LocalFree( pDacl );
  246. pDacl = NULL;
  247. SECURITY_ATTRIBUTES MetadataSecurityAttributes;
  248. MetadataSecurityAttributes.nLength = sizeof(MetadataSecurityAttributes);
  249. MetadataSecurityAttributes.lpSecurityDescriptor = pMetadataSecurityDescriptor.get();
  250. MetadataSecurityAttributes.bInheritHandle = FALSE;
  251. // Build path where the metadata will be stored.
  252. #if defined( BITS_V12_ON_NT4 )
  253. size_t Length = MAX_PATH * 2 + 1;
  254. auto_ptr<TCHAR> QmgrDirectory( new TCHAR[ Length ] );
  255. dwResult = (DWORD)GetWindowsDirectory( //SEC: REVIEWED 2002-03-28
  256. QmgrDirectory.get(), // buffer for Windows directory
  257. MAX_PATH+1 // size of directory buffer
  258. );
  259. if ( !dwResult || dwResult > MAX_PATH+1 )
  260. {
  261. HRESULT Error = GetLastError();
  262. LogError( "Unable to lookup windows directory, error %!winerr!", Error );
  263. throw ComError( Error );
  264. }
  265. THROW_HRESULT( StringCchCat( QmgrDirectory.get(), Length, _T("\\System32\\BITS") ));
  266. #else
  267. StringHandle AllUsersDirectory =
  268. BITSSHGetFolderPath(
  269. NULL,
  270. CSIDL_COMMON_APPDATA,
  271. NULL,
  272. SHGFP_TYPE_CURRENT );
  273. size_t Length = lstrlen( AllUsersDirectory ) + lstrlen(C_QMGR_DIRECTORY) + 1; //SEC: REVIEWED 2002-03-28
  274. auto_ptr<TCHAR> QmgrDirectory( new TCHAR[ Length ] );
  275. THROW_HRESULT( StringCchCopy( QmgrDirectory.get(), Length, AllUsersDirectory ));
  276. THROW_HRESULT( StringCchCat( QmgrDirectory.get(), Length, C_QMGR_DIRECTORY ));
  277. // Create the BITS directory if needed.
  278. dwResult = GetFileAttributes( QmgrDirectory.get() );
  279. if ( (-1 == dwResult) || !(dwResult & FILE_ATTRIBUTE_DIRECTORY))
  280. {
  281. LogError( "BITS directory doesn't exist, attempt to create %!ts!.\n", QmgrDirectory.get() );
  282. bResult = CreateDirectory(QmgrDirectory.get(), &MetadataSecurityAttributes); //SEC: REVIEWED 2002-03-28
  283. if ( !bResult )
  284. {
  285. hResult = HRESULT_FROM_WIN32( GetLastError() );
  286. LogError( "Unable to create BITS directory, error %!winerr!\n", hResult );
  287. throw ComError( hResult );
  288. }
  289. }
  290. #endif
  291. // Open the main policy registry key
  292. dwResult =
  293. (DWORD)RegOpenKey(
  294. HKEY_LOCAL_MACHINE,
  295. C_QMGR_POLICY_REG_KEY,
  296. &hQmgrPolicyKey);
  297. if ( ERROR_SUCCESS != dwResult )
  298. {
  299. LogWarning("Unable to open the main policy registry key\n");
  300. }
  301. // Open the main qmgr registry key
  302. dwResult =
  303. (DWORD)RegCreateKeyEx(
  304. HKEY_LOCAL_MACHINE, // root key
  305. C_QMGR_REG_KEY, // subkey
  306. 0, // reserved
  307. NULL, // class name
  308. REG_OPTION_NON_VOLATILE, // option
  309. KEY_ALL_ACCESS, // security // SEC: REVIEWED 2002-03-28
  310. &MetadataSecurityAttributes,// security attribute
  311. &hQmgrKey,
  312. NULL);
  313. if ( ERROR_SUCCESS != dwResult )
  314. {
  315. hResult = HRESULT_FROM_WIN32( dwResult );
  316. LogError( "Unable to open main BITS key, error %!winerr!\n", hResult );
  317. throw ComError( hResult );
  318. }
  319. UINT64 JobInactivityTimeout;
  320. // Get the inactivity timeout value for job;
  321. {
  322. DWORD dwValue;
  323. DWORD dwType = REG_DWORD;
  324. DWORD dwSize = sizeof(dwValue);
  325. LONG lResult;
  326. if ( hQmgrPolicyKey )
  327. {
  328. lResult =
  329. RegQueryValueEx( //SEC: REVIEWED 2002-03-28
  330. hQmgrPolicyKey,
  331. C_QMGR_JOB_INACTIVITY_TIMEOUT,
  332. NULL,
  333. &dwType,
  334. (LPBYTE)&dwValue,
  335. &dwSize );
  336. }
  337. if ( !hQmgrPolicyKey ||
  338. ERROR_SUCCESS != lResult ||
  339. dwType != REG_DWORD ||
  340. dwSize != sizeof(dwValue)
  341. )
  342. {
  343. JobInactivityTimeout =
  344. RegGetDWORD( hQmgrKey, C_QMGR_JOB_INACTIVITY_TIMEOUT, C_QMGR_JOB_INACTIVITY_TIMEOUT_DEFAULT);
  345. JobInactivityTimeout *= NanoSec100PerSec;
  346. }
  347. else
  348. {
  349. LogInfo("Retrieved job inactivity timeout of %u days from policy", dwValue );
  350. JobInactivityTimeout = dwValue * NanoSec100PerSec * 60/*secs per min*/ * 60/*mins per hour*/ * 24 /* hours per day*/;
  351. }
  352. }
  353. UINT64 TimeQuantaLength =
  354. RegGetDWORD( hQmgrKey, C_QMGR_TIME_QUANTA_LENGTH, C_QMGR_TIME_QUANTA_LENGTH_DEFAULT );
  355. TimeQuantaLength *= NanoSec100PerSec;
  356. UINT32 DefaultNoProgressTimeout = // global data is in seconds.
  357. RegGetDWORD( hQmgrKey, C_QMGR_NO_PROGRESS_TIMEOUT, C_QMGR_NO_PROGRESS_TIMEOUT_DEFAULT );
  358. UINT32 DefaultMinimumRetryDelay = // global data is in seconds
  359. RegGetDWORD( hQmgrKey, C_QMGR_MINIMUM_RETRY_DELAY, C_QMGR_MINIMUM_RETRY_DELAY_DEFAULT );
  360. pGlobalInfo =
  361. new GlobalInfo( QmgrDirectory.get(),
  362. PerformanceCounterFrequency,
  363. hQmgrKey,
  364. JobInactivityTimeout,
  365. TimeQuantaLength,
  366. DefaultNoProgressTimeout,
  367. DefaultMinimumRetryDelay,
  368. pMetadataSecurityDescriptor.get(),
  369. dwRequiredSecurityDescriptorLength,
  370. AdministratorsSid,
  371. LocalSystemSid,
  372. NetworkUsersSid
  373. );
  374. if ( !pGlobalInfo )
  375. throw ComError( E_OUTOFMEMORY );
  376. QmgrDirectory.release();
  377. pMetadataSecurityDescriptor.release();
  378. if ( hQmgrPolicyKey )
  379. CloseHandle( hQmgrPolicyKey );
  380. }
  381. catch( ComError Error )
  382. {
  383. LogError( "An exception occured creating global info, error %!winerr!", Error.Error() );
  384. if ( hQmgrKey )
  385. CloseHandle( hQmgrKey );
  386. hQmgrKey = NULL;
  387. if ( hQmgrPolicyKey )
  388. CloseHandle( hQmgrPolicyKey );
  389. hQmgrPolicyKey = NULL;
  390. // LocalFree has if guard
  391. LocalFree( pDacl );
  392. return Error.Error();
  393. }
  394. LogInfo( "Finished init of global info" );
  395. g_GlobalInfo = pGlobalInfo;
  396. return S_OK;
  397. }
  398. HRESULT GlobalInfo::Uninit()
  399. {
  400. delete g_GlobalInfo;
  401. g_GlobalInfo = NULL;
  402. return S_OK;
  403. }
  404. LONG
  405. ExternalFuncExceptionFilter(
  406. struct _EXCEPTION_POINTERS *ExceptionInfo
  407. )
  408. {
  409. // This function is called by the exception filter that wraps external functions.
  410. // The purpose is to treat unhandled exceptions as unhandled instead of propagating
  411. // across the network
  412. // If this exception is a MSVCRT exception, bash the exception code
  413. // so that MSVCRT won't call ExitProcess.
  414. if ( ExceptionInfo &&
  415. ExceptionInfo->ExceptionRecord &&
  416. ('msc' | 0xE0000000) == ExceptionInfo->ExceptionRecord->ExceptionCode )
  417. {
  418. ExceptionInfo->ExceptionRecord->ExceptionCode = ('BIT' | 0xE0000000);
  419. }
  420. LONG Result = UnhandledExceptionFilter( ExceptionInfo );
  421. if ( EXCEPTION_CONTINUE_SEARCH == Result )
  422. {
  423. // Need to act like the dispatcher. Call kernel again specifying second change semantics
  424. NtRaiseException( ExceptionInfo->ExceptionRecord, ExceptionInfo->ContextRecord, FALSE );
  425. }
  426. // exception handler returns RPC_E_SERVERFAULT
  427. return EXCEPTION_EXECUTE_HANDLER;
  428. }
  429. SidHandle & SidHandle::operator=( const SidHandle & r )
  430. {
  431. if (m_pValue == r.m_pValue )
  432. {
  433. return *this;
  434. }
  435. if (InterlockedDecrement(m_pRefs) == 0)
  436. {
  437. delete m_pRefs;
  438. delete m_pValue;
  439. }
  440. m_pValue = r.m_pValue;
  441. m_pRefs = r.m_pRefs;
  442. InterlockedIncrement(m_pRefs);
  443. return *this;
  444. }
  445. StringHandle::StringData StringHandle::s_EmptyString =
  446. {
  447. 0, 1, { L'\0' } // Initialize with 1 ref so it is never deleted
  448. };
  449. bool
  450. CSidSorter::operator()(
  451. const SidHandle & handle1,
  452. const SidHandle & handle2
  453. ) const
  454. {
  455. const PSID psid1 = handle1.get();
  456. const PSID psid2 = handle2.get();
  457. if ( !psid1 || !psid2 )
  458. return (INT_PTR)psid1 < (INT_PTR)psid2;
  459. if (*GetSidSubAuthorityCount( psid1 ) < *GetSidSubAuthorityCount( psid2 ))
  460. {
  461. return true;
  462. }
  463. // at this point, we known psd1 is >= psd2. // Stop if psid1 is
  464. // longer so that the preceding for loop doesn't overstep the sid
  465. // array on psd2.
  466. if ( *GetSidSubAuthorityCount( psid1 ) > *GetSidSubAuthorityCount( psid2 ) )
  467. return false;
  468. // arrays have equal length
  469. for (UCHAR i=0; i < *GetSidSubAuthorityCount( psid1 ); ++i)
  470. {
  471. if (*GetSidSubAuthority( psid1, i ) < *GetSidSubAuthority( psid2, i ))
  472. return true; // sid1 is less then sid2
  473. else if ( *GetSidSubAuthority( psid1, i ) > *GetSidSubAuthority( psid2, i ) )
  474. return false; // sid1 is greater then sid2
  475. // subauthorities are the same, move on to the next subauthority
  476. }
  477. // arrays are identical
  478. return false;
  479. }
  480. //------------------------------------------------------------------------
  481. PSID DuplicateSid( PSID _Sid )
  482. /*++
  483. Routine Description:
  484. Clones a SID. The new SID is allocated using the global operator new.
  485. At entry:
  486. _Sid is the SID to clone.
  487. At exit:
  488. the return is NULL if an error occurs, otherwise a pointer to the new SID.
  489. --*/
  490. {
  491. DWORD Length = GetLengthSid( _Sid );
  492. SID * psid;
  493. try
  494. {
  495. psid = (SID *) new char[Length];
  496. }
  497. catch( ComError Error )
  498. {
  499. return NULL;
  500. }
  501. if (!CopySid( Length, psid, _Sid )) // SEC: REVIEWED 2002-03-28
  502. {
  503. delete[] psid;
  504. return NULL;
  505. }
  506. return psid;
  507. }
  508. LPCWSTR
  509. TruncateString( LPCWSTR String, SIZE_T MaxLength, auto_ptr<WCHAR> & AutoPointer )
  510. {
  511. if ( wcslen( String ) <= MaxLength ) // SEC: REVIEWED 2002-03-28
  512. return String;
  513. AutoPointer = auto_ptr<WCHAR>( new WCHAR[ MaxLength + 1 ] );
  514. wcsncpy( AutoPointer.get(), String, MaxLength ); // SEC: REVIEWED 2002-03-28
  515. AutoPointer.get()[ MaxLength ] = L'\0';
  516. return AutoPointer.get();
  517. }
  518. PLATFORM_PRODUCT_VERSION g_PlatformVersion;
  519. bool bIsWin9x;
  520. BOOL DetectProductVersion()
  521. {
  522. OSVERSIONINFO VersionInfo;
  523. VersionInfo.dwOSVersionInfoSize = sizeof( VersionInfo );
  524. if ( !GetVersionEx( &VersionInfo ) )
  525. return FALSE;
  526. switch( VersionInfo.dwPlatformId )
  527. {
  528. case VER_PLATFORM_WIN32_WINDOWS:
  529. g_PlatformVersion = ( VersionInfo.dwMajorVersion > 0 ) ?
  530. WIN98_PLATFORM : WIN95_PLATFORM;
  531. bIsWin9x = true;
  532. return TRUE;
  533. case VER_PLATFORM_WIN32_NT:
  534. bIsWin9x = false;
  535. #if defined( BITS_V12_ON_NT4 )
  536. if ( VersionInfo.dwMajorVersion < 4 )
  537. return FALSE;
  538. if ( 4 == VersionInfo.dwMajorVersion )
  539. {
  540. g_PlatformVersion = NT4_PLATFORM;
  541. return TRUE;
  542. }
  543. #else
  544. if ( VersionInfo.dwMajorVersion < 5 )
  545. return FALSE;
  546. #endif
  547. if ( VersionInfo.dwMajorVersion > 5 )
  548. {
  549. g_PlatformVersion = WINDOWSXP_PLATFORM;
  550. return TRUE;
  551. }
  552. g_PlatformVersion = ( VersionInfo.dwMinorVersion > 0 ) ?
  553. WINDOWSXP_PLATFORM : WINDOWS2000_PLATFORM;
  554. return TRUE;
  555. default:
  556. return FALSE;
  557. }
  558. }
  559. StringHandle
  560. CombineUrl(
  561. LPCWSTR BaseUrl,
  562. LPCWSTR RelativeUrl,
  563. DWORD Flags
  564. )
  565. {
  566. DWORD Length = 0;
  567. HRESULT hr;
  568. hr = UrlCombine( BaseUrl,
  569. RelativeUrl,
  570. 0,
  571. &Length,
  572. Flags
  573. );
  574. if (hr != E_POINTER)
  575. {
  576. ASSERT( FAILED(hr) );
  577. throw ComError( hr );
  578. }
  579. auto_ptr<WCHAR> AbsoluteUrl ( new WCHAR[ Length ] );
  580. THROW_HRESULT( UrlCombine( BaseUrl,
  581. RelativeUrl,
  582. AbsoluteUrl.get(),
  583. &Length,
  584. Flags
  585. ));
  586. //
  587. // The string handle constructor clones the auto_ptr.
  588. //
  589. return AbsoluteUrl.get();
  590. }
  591. bool IsAnyDebuggerPresent()
  592. {
  593. if (IsDebuggerPresent())
  594. {
  595. return true;
  596. }
  597. SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo = { 0 };
  598. NtQuerySystemInformation(
  599. SystemKernelDebuggerInformation,
  600. &KdInfo,
  601. sizeof(KdInfo),
  602. NULL);
  603. if (KdInfo.KernelDebuggerEnabled)
  604. {
  605. return true;
  606. }
  607. return false;
  608. }
  609. LPWSTR MidlCopyString( LPCWSTR source, size_t Length )
  610. {
  611. if (Length == -1)
  612. {
  613. Length = 1+wcslen( source ); // SEC: REVIEWED 2002-03-28
  614. }
  615. LPWSTR copy = reinterpret_cast<LPWSTR>( CoTaskMemAlloc( Length * sizeof( wchar_t )));
  616. if (!copy)
  617. {
  618. return NULL;
  619. }
  620. if (FAILED(StringCchCopy( copy, Length, source )))
  621. {
  622. CoTaskMemFree( copy );
  623. return NULL;
  624. }
  625. return copy;
  626. }
  627. LPWSTR CopyString( LPCWSTR source, size_t Length )
  628. {
  629. if (Length == -1)
  630. {
  631. Length = 1+wcslen( source ); // SEC: REVIEWED 2002-03-28
  632. }
  633. CAutoString copy( new wchar_t[ Length ]);
  634. THROW_HRESULT( StringCchCopy( copy.get(), Length, source ));
  635. return copy.release();
  636. }