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.

1023 lines
23 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1999 **
  4. //*********************************************************************
  5. //
  6. // UTIL.CPP - utilities
  7. //
  8. // HISTORY:
  9. //
  10. // 1/27/99 a-jaswed Created.
  11. //
  12. // Common utilities for printing out messages
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <objbase.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include "util.h"
  21. #include "appdefs.h"
  22. #include <shlwapi.h>
  23. #include <shlobj.h>
  24. #include <shfolder.h>
  25. #include <wchar.h>
  26. #include <winsvcp.h> // for SC_OOBE_MACHINE_NAME_DONE
  27. ///////////////////////////////////////////////////////////
  28. // Print out the COM/OLE error string for an HRESULT.
  29. //
  30. void ErrorMessage(LPCWSTR message, HRESULT hr)
  31. {
  32. const WCHAR* sz ;
  33. if (message == NULL)
  34. {
  35. sz = L"The following error occured." ;
  36. }
  37. else
  38. {
  39. sz = message ;
  40. }
  41. void* pMsgBuf;
  42. ::FormatMessage(
  43. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  44. NULL,
  45. hr,
  46. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  47. (LPWSTR) &pMsgBuf,
  48. 0,
  49. NULL
  50. );
  51. WCHAR buf[256] ;
  52. wsprintf(buf, L"%s\r\nError: (%x) - %s", sz, hr, (LPWSTR)pMsgBuf) ;
  53. MessageBox(NULL, buf, L"Utility Error Message Box.", MB_OK) ;
  54. // Free the buffer.
  55. LocalFree( pMsgBuf );
  56. }
  57. ////////////////////////////////////////////////////////////
  58. // Check to see if both interfaces are on the same component.
  59. //
  60. BOOL InterfacesAreOnSameComponent(IUnknown* p1, IUnknown* p2)
  61. {
  62. HRESULT hr = S_OK ;
  63. // Get the real IUnknown for the first interface.
  64. IUnknown* pReal1 = NULL ;
  65. hr = p1->QueryInterface(IID_IUnknown, (void**)&pReal1) ;
  66. assert(SUCCEEDED(hr)) ;
  67. // Get the real IUnknown for the second interface.
  68. IUnknown* pReal2 = NULL ;
  69. hr = p2->QueryInterface(IID_IUnknown, (void**)&pReal2) ;
  70. assert(SUCCEEDED(hr)) ;
  71. // Compare the IUnknown pointers.
  72. BOOL bReturn = (pReal1 == pReal2) ;
  73. // Cleanup
  74. pReal1->Release() ;
  75. pReal2->Release() ;
  76. // Return the value.
  77. return bReturn;
  78. }
  79. ///////////////////////////////////////////////////////////
  80. // IsValidAddress
  81. //
  82. BOOL IsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite)
  83. {
  84. return (lp != NULL && !::IsBadReadPtr(lp, nBytes) &&
  85. (!bReadWrite || !::IsBadWritePtr((LPVOID)lp, nBytes)));
  86. }
  87. ///////////////////////////////////////////////////////////
  88. // MyDebug
  89. //
  90. #if ASSERTS_ON
  91. VOID
  92. AssertFail(
  93. IN PSTR FileName,
  94. IN UINT LineNumber,
  95. IN PSTR Condition
  96. )
  97. {
  98. int i;
  99. CHAR Name[MAX_PATH];
  100. PCHAR p;
  101. CHAR Msg[4096];
  102. //
  103. // Use dll name as caption
  104. //
  105. GetModuleFileNameA(NULL,Name,MAX_PATH);
  106. if(p = strrchr(Name,'\\')) {
  107. p++;
  108. } else {
  109. p = Name;
  110. }
  111. wsprintfA(
  112. Msg,
  113. "Assertion failure at line %u in file %s: %s%s",
  114. LineNumber,
  115. FileName,
  116. Condition,
  117. "\n\nCall DebugBreak()?"
  118. );
  119. i = MessageBoxA(
  120. NULL,
  121. Msg,
  122. p,
  123. MB_YESNO | MB_TASKMODAL | MB_ICONSTOP | MB_SETFOREGROUND
  124. );
  125. if(i == IDYES) {
  126. DebugBreak();
  127. }
  128. }
  129. #endif
  130. ///////////////////////////////////////////////////////////
  131. // Trace
  132. //
  133. void __cdecl MyTrace(LPCWSTR lpszFormat, ...)
  134. {
  135. USES_CONVERSION;
  136. va_list args;
  137. va_start(args, lpszFormat);
  138. int nBuf;
  139. WCHAR szBuffer[512];
  140. nBuf = _vsnwprintf(szBuffer, MAX_CHARS_IN_BUFFER(szBuffer), lpszFormat, args);
  141. // was there an error? was the expanded string too long?
  142. assert(nBuf > 0);
  143. #if DBG
  144. DbgPrintEx( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, W2A(szBuffer) );
  145. #endif
  146. va_end(args);
  147. }
  148. //BUGBUG need bettter default
  149. bool GetString(HINSTANCE hInstance, UINT uiID, LPWSTR szString, UINT uiStringLen)
  150. {
  151. // BUGBUG: Should this assume current module if hInstance is NULL??
  152. MYASSERT(NULL != hInstance);
  153. if (NULL != hInstance)
  154. return (0 < LoadString(hInstance, uiID, szString, uiStringLen));
  155. else
  156. return (false);
  157. }
  158. // the goal of this function is to be able to able to get to
  159. // c:\windows dir\system dir\oobe\oobeinfo.ini
  160. // c:\windows dir\system dir\oeminfo.ini
  161. // c:\windows dir\oemaudit.oem
  162. // the canonicalize allows the specification for oemaudit.oem to be ..\oemaudit.oem
  163. bool GetCanonicalizedPath(LPWSTR szCompletePath, LPCWSTR szFileName)
  164. {
  165. if (0 < GetSystemDirectory(szCompletePath, MAX_PATH))
  166. {
  167. lstrcat(szCompletePath, szFileName);
  168. WCHAR szLocal[MAX_PATH];
  169. lstrcpy(szLocal, szCompletePath);
  170. return PathCanonicalize(szCompletePath, (LPCWSTR) szLocal) ? true : false;
  171. }
  172. return false;
  173. }
  174. bool GetOOBEPath(LPWSTR szOOBEPath)
  175. {
  176. if (0 < GetSystemDirectory(szOOBEPath, MAX_PATH))
  177. {
  178. lstrcat(szOOBEPath, L"\\OOBE");
  179. return true;
  180. }
  181. return false;
  182. }
  183. // This returns the path for the localized OOBE files on a system with MUI.
  184. //
  185. bool GetOOBEMUIPath(LPWSTR szOOBEPath)
  186. {
  187. LANGID UILang;
  188. WCHAR szMUIPath[MAX_PATH];
  189. if (GetOOBEPath(szOOBEPath))
  190. {
  191. UILang = GetUserDefaultUILanguage();
  192. if ( UILang != GetSystemDefaultUILanguage() ) {
  193. wsprintf( szMUIPath, L"\\MUI\\%04x", UILang );
  194. lstrcat(szOOBEPath, szMUIPath );
  195. }
  196. return true;
  197. }
  198. return false;
  199. }
  200. HRESULT GetINIKey(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
  201. {
  202. WCHAR szSectionName[MAX_PATH], szKeyName[MAX_PATH];
  203. WCHAR szItem[1024]; //bugbug bad constant
  204. if (GetString(hInstance, uiSectionName, szSectionName) && GetString(hInstance, uiKeyName, szKeyName))
  205. {
  206. WCHAR szINIPath[MAX_PATH];
  207. if (GetCanonicalizedPath(szINIPath, szINIFileName))
  208. {
  209. if (VT_I4 == V_VT(pvResult))
  210. {
  211. V_I4(pvResult) = GetPrivateProfileInt(szSectionName, szKeyName, 0, szINIPath);
  212. return S_OK;
  213. }
  214. else
  215. {
  216. if (GetPrivateProfileString(
  217. szSectionName,
  218. szKeyName,
  219. L"",
  220. szItem,
  221. MAX_CHARS_IN_BUFFER(szItem),
  222. szINIPath))
  223. {
  224. V_BSTR(pvResult) = SysAllocString(szItem);
  225. return S_OK;
  226. }
  227. }
  228. }
  229. }
  230. if (VT_BSTR == V_VT(pvResult))
  231. V_BSTR(pvResult) = SysAllocString(L"\0");
  232. else
  233. V_I4(pvResult) = 0;
  234. return S_OK;
  235. }
  236. HRESULT GetINIKeyBSTR(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
  237. {
  238. VariantInit(pvResult);
  239. V_VT(pvResult) = VT_BSTR;
  240. return (GetINIKey(hInstance, szINIFileName, uiSectionName, uiKeyName, pvResult));
  241. }
  242. HRESULT GetINIKeyUINT(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
  243. {
  244. VariantInit(pvResult);
  245. V_VT(pvResult) = VT_I4;
  246. return (GetINIKey(hInstance, szINIFileName, uiSectionName, uiKeyName, pvResult));
  247. }
  248. HRESULT SetINIKey(HINSTANCE hInstance, LPCWSTR szINIFileName, UINT uiSectionName, UINT uiKeyName, LPVARIANT pvResult)
  249. {
  250. WCHAR szSectionName[MAX_PATH], szKeyName[MAX_PATH];
  251. VariantInit(pvResult);
  252. V_VT(pvResult) = VT_BSTR;
  253. if (GetString(hInstance, uiSectionName, szSectionName) && GetString(hInstance, uiKeyName, szKeyName))
  254. {
  255. if (WritePrivateProfileString(V_BSTR(pvResult), szKeyName,
  256. V_BSTR(pvResult), szINIFileName))
  257. {
  258. return S_OK;
  259. }
  260. }
  261. return E_FAIL;
  262. }
  263. void WINAPI URLEncode(WCHAR* pszUrl, size_t bsize)
  264. {
  265. if (!pszUrl)
  266. return;
  267. WCHAR* pszEncode = NULL;
  268. WCHAR* pszEStart = NULL;
  269. WCHAR* pszEEnd = (WCHAR*)wmemchr( pszUrl, L'\0', bsize );
  270. int iUrlLen = (int)(pszEEnd-pszUrl);
  271. pszEEnd = pszUrl;
  272. WCHAR c;
  273. size_t cch = (iUrlLen+1) * sizeof(WCHAR) * 3;
  274. assert( cch <= bsize );
  275. if (cch <= bsize)
  276. {
  277. pszEncode = (WCHAR*)malloc(BYTES_REQUIRED_BY_CCH(cch));
  278. if(pszEncode)
  279. {
  280. pszEStart = pszEncode;
  281. ZeroMemory(pszEncode, BYTES_REQUIRED_BY_CCH(cch));
  282. for(; c = *(pszUrl); pszUrl++)
  283. {
  284. switch(c)
  285. {
  286. case L' ': //SPACE
  287. memcpy(pszEncode, L"+", 1*sizeof(WCHAR));
  288. pszEncode+=1;
  289. break;
  290. case L'#':
  291. memcpy(pszEncode, L"%23", 3*sizeof(WCHAR));
  292. pszEncode+=3;
  293. break;
  294. case L'&':
  295. memcpy(pszEncode, L"%26", 3*sizeof(WCHAR));
  296. pszEncode+=3;
  297. break;
  298. case L'%':
  299. memcpy(pszEncode, L"%25", 3*sizeof(WCHAR));
  300. pszEncode+=3;
  301. break;
  302. case L'=':
  303. memcpy(pszEncode, L"%3D", 3*sizeof(WCHAR));
  304. pszEncode+=3;
  305. break;
  306. case L'<':
  307. memcpy(pszEncode, L"%3C", 3*sizeof(WCHAR));
  308. pszEncode+=3;
  309. break;
  310. case L'+':
  311. memcpy(pszEncode, L"%2B", 3*sizeof(WCHAR));
  312. pszEncode += 3;
  313. break;
  314. default:
  315. *pszEncode++ = c;
  316. break;
  317. }
  318. }
  319. *pszEncode++ = L'\0';
  320. memcpy(pszEEnd ,pszEStart, (size_t)(pszEncode - pszEStart));
  321. free(pszEStart);
  322. }
  323. }
  324. }
  325. //BUGBUG: Need to turn spaces into "+"
  326. void WINAPI URLAppendQueryPair
  327. (
  328. LPWSTR lpszQuery,
  329. LPWSTR lpszName,
  330. LPWSTR lpszValue OPTIONAL
  331. )
  332. {
  333. // Append the Name
  334. lstrcat(lpszQuery, lpszName);
  335. lstrcat(lpszQuery, cszEquals);
  336. // Append the Value
  337. if ( lpszValue ) {
  338. lstrcat(lpszQuery, lpszValue);
  339. }
  340. // Append an Ampersand if this is NOT the last pair
  341. lstrcat(lpszQuery, cszAmpersand);
  342. }
  343. void GetCmdLineToken(LPWSTR *ppszCmd, LPWSTR pszOut)
  344. {
  345. LPWSTR c;
  346. int i = 0;
  347. BOOL fInQuote = FALSE;
  348. c = *ppszCmd;
  349. pszOut[0] = *c;
  350. if (!*c)
  351. return;
  352. if (*c == L' ')
  353. {
  354. pszOut[1] = L'\0';
  355. *ppszCmd = c+1;
  356. return;
  357. }
  358. else if( L'"' == *c )
  359. {
  360. fInQuote = TRUE;
  361. }
  362. NextChar:
  363. i++;
  364. c++;
  365. if( !*c || (!fInQuote && (*c == L' ')) )
  366. {
  367. pszOut[i] = L'\0';
  368. *ppszCmd = c;
  369. return;
  370. }
  371. else if( fInQuote && (*c == L'"') )
  372. {
  373. fInQuote = FALSE;
  374. pszOut[i] = *c;
  375. i++;
  376. c++;
  377. pszOut[i] = L'\0';
  378. *ppszCmd = c;
  379. return;
  380. }
  381. else
  382. {
  383. pszOut[i] = *c;
  384. goto NextChar;
  385. }
  386. }
  387. BOOL IsOEMDebugMode()
  388. {
  389. HKEY hKey = NULL;
  390. DWORD dwIsDebug = 0;
  391. DWORD dwSize = sizeof(dwIsDebug);
  392. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  393. OOBE_MAIN_REG_KEY,
  394. 0,
  395. KEY_QUERY_VALUE,
  396. &hKey) == ERROR_SUCCESS)
  397. {
  398. RegQueryValueEx(hKey,
  399. OOBE_OEMDEBUG_REG_VAL,
  400. 0,
  401. NULL,
  402. (LPBYTE)&dwIsDebug,
  403. &dwSize);
  404. RegCloseKey(hKey);
  405. }
  406. #ifdef DEBUG
  407. return (BOOL)1;
  408. #else
  409. return (BOOL)dwIsDebug;
  410. #endif
  411. }
  412. VOID
  413. PumpMessageQueue(
  414. VOID
  415. )
  416. {
  417. MSG msg;
  418. while(PeekMessage(&msg, NULL, 0,0,PM_REMOVE)) {
  419. DispatchMessage(&msg);
  420. }
  421. }
  422. BOOL
  423. IsThreadActive(
  424. HANDLE hThread
  425. )
  426. {
  427. DWORD dwExitCode = 0;
  428. return (NULL != hThread
  429. && GetExitCodeThread(hThread, &dwExitCode)
  430. && STILL_ACTIVE == dwExitCode
  431. );
  432. }
  433. void GetDesktopDirectory(WCHAR* pszPath)
  434. {
  435. WCHAR pszFolder[MAX_PATH];
  436. *pszFolder = L'\0';
  437. HRESULT hRet = SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY,
  438. NULL, 0, pszFolder
  439. );
  440. if (S_OK != hRet)
  441. {
  442. hRet = SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY,
  443. NULL, 0, pszFolder
  444. );
  445. }
  446. if (S_OK == hRet)
  447. {
  448. lstrcpy(pszPath , pszFolder);
  449. }
  450. }
  451. void RemoveDesktopShortCut
  452. (
  453. LPWSTR lpszShortcutName
  454. )
  455. {
  456. WCHAR szShortcutPath[MAX_PATH] = L"\0";
  457. GetDesktopDirectory(szShortcutPath);
  458. if(szShortcutPath[0] != L'\0')
  459. {
  460. lstrcat(szShortcutPath, L"\\");
  461. lstrcat(szShortcutPath, lpszShortcutName);
  462. lstrcat(szShortcutPath, L".LNK");
  463. DeleteFile(szShortcutPath);
  464. }
  465. }
  466. BOOL
  467. InvokeExternalApplication(
  468. IN PCWSTR ApplicationName, OPTIONAL
  469. IN PCWSTR CommandLine,
  470. IN OUT PDWORD ExitCode OPTIONAL
  471. )
  472. /*++
  473. Routine Description:
  474. Invokes an external program, which is optionally detached.
  475. Arguments:
  476. ApplicationName - supplies app name. May be a partial or full path,
  477. or just a filename, in which case the standard win32 path search
  478. is performed. If not specified then the first element in
  479. CommandLine must specify the binary to execute.
  480. CommandLine - supplies the command line to be passed to the
  481. application.
  482. ExitCode - If specified, the execution is synchronous and this value
  483. receives the exit code of the application. If not specified,
  484. the execution is asynchronous.
  485. Return Value:
  486. Boolean value indicating whether the process was started successfully.
  487. --*/
  488. {
  489. PWSTR FullCommandLine;
  490. BOOL b;
  491. PROCESS_INFORMATION ProcessInfo;
  492. STARTUPINFO StartupInfo;
  493. DWORD d;
  494. b = FALSE;
  495. //
  496. // Form the command line to be passed to CreateProcess.
  497. //
  498. if(ApplicationName) {
  499. FullCommandLine =
  500. (PWSTR) malloc(BYTES_REQUIRED_BY_SZ(ApplicationName)+BYTES_REQUIRED_BY_SZ(CommandLine)+BYTES_REQUIRED_BY_CCH(2));
  501. if(!FullCommandLine) {
  502. goto err0;
  503. }
  504. lstrcpy(FullCommandLine, ApplicationName);
  505. lstrcat(FullCommandLine, L" ");
  506. lstrcat(FullCommandLine, CommandLine);
  507. } else {
  508. FullCommandLine =
  509. (PWSTR) malloc(BYTES_REQUIRED_BY_SZ(CommandLine));
  510. if(!FullCommandLine) {
  511. goto err0;
  512. }
  513. lstrcpy(FullCommandLine, CommandLine);
  514. }
  515. //
  516. // Initialize startup info.
  517. //
  518. ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
  519. StartupInfo.cb = sizeof(STARTUPINFO);
  520. //
  521. // Create the process.
  522. //
  523. b = CreateProcess(
  524. NULL,
  525. FullCommandLine,
  526. NULL,
  527. NULL,
  528. FALSE,
  529. ExitCode ? 0 : DETACHED_PROCESS,
  530. NULL,
  531. NULL,
  532. &StartupInfo,
  533. &ProcessInfo
  534. );
  535. if(!b) {
  536. goto err1;
  537. }
  538. //
  539. // If execution is asynchronus, we're done.
  540. //
  541. if(!ExitCode) {
  542. goto err2;
  543. }
  544. err2:
  545. CloseHandle(ProcessInfo.hThread);
  546. CloseHandle(ProcessInfo.hProcess);
  547. err1:
  548. free(FullCommandLine);
  549. err0:
  550. return(b);
  551. }
  552. //////////////////////////////////////////////////////////////////////////////
  553. //
  554. // InSafeMode
  555. //
  556. // Determine whether the system is running in safe mode or clean mode.
  557. //
  558. // parameters:
  559. // None.
  560. //
  561. // returns:
  562. // TRUE if the system was booted in safe mode
  563. // FALSE if the system was booted in clean mode
  564. //
  565. //////////////////////////////////////////////////////////////////////////////
  566. BOOL
  567. InSafeMode()
  568. {
  569. if (BOOT_CLEAN != GetSystemMetrics(SM_CLEANBOOT))
  570. {
  571. TRACE(L"Running in SAFEMODE...\n");
  572. return TRUE;
  573. }
  574. return FALSE;
  575. } // InSafeMode
  576. // Signal winlogon that the computer name has been changed. WinLogon waits to
  577. // start services that depend on the computer name until this event is
  578. // signalled.
  579. //
  580. BOOL
  581. SignalComputerNameChangeComplete()
  582. {
  583. BOOL fReturn = TRUE;
  584. // Open event with EVENT_ALL_ACCESS so that synchronization and state
  585. // change can be done.
  586. //
  587. HANDLE hevent = OpenEvent(EVENT_ALL_ACCESS,
  588. FALSE,
  589. SC_OOBE_MACHINE_NAME_DONE
  590. );
  591. // It is not fatal for OpenEvent to fail: this synchronization is only
  592. // required when OOBE will be run in OEM mode.
  593. //
  594. if (NULL != hevent)
  595. {
  596. if (! SetEvent(hevent))
  597. {
  598. // It is fatal to open but not set the event: services.exe will not
  599. // continue until this event is signalled.
  600. //
  601. TRACE2(L"Failed to signal SC_OOBE_MACHINE_NAME_DONE(%s): 0x%08X\n",
  602. SC_OOBE_MACHINE_NAME_DONE, GetLastError());
  603. fReturn = FALSE;
  604. }
  605. MYASSERT(fReturn); // Why did we fail to set an open event??
  606. }
  607. return fReturn;
  608. }
  609. BOOL
  610. IsUserAdmin(
  611. VOID
  612. )
  613. /*++
  614. Routine Description:
  615. This routine returns TRUE if the caller's process is a
  616. member of the Administrators local group.
  617. Caller is NOT expected to be impersonating anyone and IS
  618. expected to be able to open their own process and process
  619. token.
  620. Arguments:
  621. None.
  622. Return Value:
  623. TRUE - Caller has Administrators local group.
  624. FALSE - Caller does not have Administrators local group.
  625. --*/
  626. {
  627. HANDLE Token;
  628. DWORD BytesRequired;
  629. PTOKEN_GROUPS Groups;
  630. BOOL b;
  631. DWORD i;
  632. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  633. PSID AdministratorsGroup;
  634. //
  635. // Open the process token.
  636. //
  637. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  638. return(FALSE);
  639. }
  640. b = FALSE;
  641. Groups = NULL;
  642. //
  643. // Get group information.
  644. //
  645. if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
  646. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  647. && (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired))
  648. && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
  649. b = AllocateAndInitializeSid(
  650. &NtAuthority,
  651. 2,
  652. SECURITY_BUILTIN_DOMAIN_RID,
  653. DOMAIN_ALIAS_RID_ADMINS,
  654. 0, 0, 0, 0, 0, 0,
  655. &AdministratorsGroup
  656. );
  657. if(b) {
  658. //
  659. // See if the user has the administrator group.
  660. //
  661. b = FALSE;
  662. for(i=0; i<Groups->GroupCount; i++) {
  663. if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
  664. b = TRUE;
  665. break;
  666. }
  667. }
  668. FreeSid(AdministratorsGroup);
  669. }
  670. }
  671. //
  672. // Clean up and return.
  673. //
  674. if(Groups) {
  675. LocalFree((HLOCAL)Groups);
  676. }
  677. CloseHandle(Token);
  678. return(b);
  679. }
  680. #define MyMalloc(s) GlobalAlloc(GPTR, s)
  681. #define MyFree(p) GlobalFree(p)
  682. static LPTSTR
  683. pDuplicateString(
  684. LPCTSTR szText
  685. )
  686. {
  687. int cchText;
  688. LPTSTR szOutText;
  689. if (szText == NULL)
  690. {
  691. return NULL;
  692. }
  693. cchText = lstrlen(szText);
  694. szOutText = (LPTSTR) MyMalloc(sizeof(TCHAR) * (cchText + 1));
  695. if (szOutText)
  696. {
  697. lstrcpyn(szOutText, szText, cchText + 1);
  698. }
  699. return szOutText;
  700. }
  701. PSTRINGLIST
  702. CreateStringCell (
  703. IN PCTSTR String
  704. )
  705. {
  706. PSTRINGLIST p = (PSTRINGLIST) MyMalloc (sizeof (STRINGLIST));
  707. if (p) {
  708. ZeroMemory (p, sizeof (STRINGLIST));
  709. if (String) {
  710. p->String = pDuplicateString (String);
  711. if (!p->String) {
  712. MyFree (p);
  713. p = NULL;
  714. }
  715. } else {
  716. p->String = NULL;
  717. }
  718. }
  719. return p;
  720. }
  721. VOID
  722. DeleteStringCell (
  723. IN PSTRINGLIST Cell
  724. )
  725. {
  726. if (Cell) {
  727. MyFree (Cell->String);
  728. MyFree (Cell);
  729. }
  730. }
  731. BOOL
  732. InsertList (
  733. IN OUT PSTRINGLIST* List,
  734. IN PSTRINGLIST NewList
  735. )
  736. {
  737. PSTRINGLIST p;
  738. if (!NewList) {
  739. return FALSE;
  740. }
  741. if (*List) {
  742. for (p = *List; p->Next; p = p->Next) ;
  743. p->Next = NewList;
  744. } else {
  745. *List = NewList;
  746. }
  747. return TRUE;
  748. }
  749. VOID
  750. DestroyList (
  751. IN PSTRINGLIST List
  752. )
  753. {
  754. PSTRINGLIST p, q;
  755. for (p = List; p; p = q) {
  756. q = p->Next;
  757. DeleteStringCell (p);
  758. }
  759. }
  760. BOOL
  761. RemoveListI(
  762. IN OUT PSTRINGLIST* List,
  763. IN PCTSTR String
  764. )
  765. {
  766. PSTRINGLIST p = *List;
  767. BOOL b = FALSE;
  768. if (p)
  769. {
  770. if (!lstrcmpi(p->String, String))
  771. {
  772. *List = p->Next;
  773. DeleteStringCell(p);
  774. b = TRUE;
  775. }
  776. else
  777. {
  778. PSTRINGLIST q;
  779. for (q = p->Next; q; p = q, q = q->Next)
  780. {
  781. if (!lstrcmpi(q->String, String))
  782. {
  783. p->Next = q->Next;
  784. DeleteStringCell(q);
  785. b = TRUE;
  786. break;
  787. }
  788. }
  789. }
  790. }
  791. return b;
  792. }
  793. BOOL
  794. ExistInListI(
  795. IN PSTRINGLIST List,
  796. IN PCTSTR String
  797. )
  798. {
  799. PSTRINGLIST p;
  800. for (p = List; p; p = p->Next)
  801. {
  802. if (!lstrcmpi(p->String, String))
  803. {
  804. break;
  805. }
  806. }
  807. return (p != NULL);
  808. }
  809. BOOL IsDriveNTFS(IN TCHAR Drive)
  810. {
  811. TCHAR DriveName[4];
  812. TCHAR Filesystem[256];
  813. TCHAR VolumeName[MAX_PATH];
  814. DWORD SerialNumber;
  815. DWORD MaxComponent;
  816. DWORD Flags;
  817. BOOL bIsNTFS = FALSE;
  818. DriveName[0] = Drive;
  819. DriveName[1] = TEXT(':');
  820. DriveName[2] = TEXT('\\');
  821. DriveName[3] = 0;
  822. if (GetVolumeInformation(
  823. DriveName,
  824. VolumeName,MAX_PATH,
  825. &SerialNumber,
  826. &MaxComponent,
  827. &Flags,
  828. Filesystem,
  829. sizeof(Filesystem)/sizeof(TCHAR)
  830. ))
  831. {
  832. bIsNTFS = (lstrcmpi(Filesystem,TEXT("NTFS")) == 0);
  833. }
  834. return bIsNTFS;
  835. }
  836. BOOL
  837. HasTablet()
  838. {
  839. TCHAR szPath[MAX_PATH+1];
  840. ZeroMemory(szPath, sizeof(szPath));
  841. if (FAILED(SHGetFolderPath(
  842. NULL,
  843. CSIDL_PROGRAM_FILES_COMMON,
  844. NULL,
  845. SHGFP_TYPE_DEFAULT,
  846. szPath)))
  847. {
  848. return FALSE;
  849. }
  850. StrCatBuff(szPath, TEXT("\\Microsoft Shared\\Ink\\tabtip.exe"), MAX_PATH+1);
  851. return PathFileExists(szPath);
  852. }