Leaked source code of windows server 2003
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.

1533 lines
44 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: misc.cpp
  4. //
  5. // Module: CMUTIL.DLL
  6. //
  7. // Synopsis: Misc. utility routines provided by CMUTIL
  8. //
  9. // Copyright (c) 1997-1999 Microsoft Corporation
  10. //
  11. // Author: henryt Created 03/01/98
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmmaster.h"
  15. #include "ver.cpp"
  16. //+----------------------------------------------------------------------------
  17. // defines
  18. //+----------------------------------------------------------------------------
  19. #define MAX_STR_LEN 512 // Maximum length for Format Message string
  20. //+----------------------------------------------------------------------------
  21. // code
  22. //+----------------------------------------------------------------------------
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Function: IsFarEastNonOSR2Win95()
  26. //
  27. // Synopsis: Checks to see if the OS is a far east version of Win95(golden
  28. // and OPK1, NOT OSR2).
  29. //
  30. // Arguments: NONE
  31. //
  32. // Returns: TRUE/FALSE
  33. //
  34. // History: henryt 07/09/97 Created
  35. // nickball 03/11/98 Moved to cmutil
  36. //----------------------------------------------------------------------------
  37. CMUTILAPI BOOL WINAPI IsFarEastNonOSR2Win95(void)
  38. {
  39. OSVERSIONINFO oviVersion;
  40. ZeroMemory(&oviVersion, sizeof(oviVersion));
  41. oviVersion.dwOSVersionInfoSize = sizeof(oviVersion);
  42. GetVersionEx(&oviVersion);
  43. //
  44. // Is it (Win95) and (not OSR2) and (DBCS enabled)?
  45. // Far east Win95 are DBCS enabled while other non-English versions
  46. // are SBCS-enabled.
  47. //
  48. MYDBGTST((oviVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
  49. LOWORD(oviVersion.dwBuildNumber) != WIN95_OSR2_BUILD_NUMBER &&
  50. GetSystemMetrics(SM_DBCSENABLED)), (TEXT("It's a Far East non-OSR2 machine!\n")));
  51. return (oviVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
  52. LOWORD(oviVersion.dwBuildNumber) != WIN95_OSR2_BUILD_NUMBER &&
  53. GetSystemMetrics(SM_DBCSENABLED));
  54. }
  55. //+---------------------------------------------------------------------------
  56. //
  57. // Function: CmLoadStringA
  58. //
  59. // Synopsis: Loads the ANSI version of the string resource specified by
  60. // the passed in module instance handle and resource ID. The
  61. // function returns the requested string in a CmMalloc-ed buffer
  62. // through the return value. This buffer must be freed by the
  63. // caller. Note that CmLoadString figures out the proper buffer
  64. // size by guessing and then calling loadstring again if the buffer
  65. // is too small.
  66. //
  67. // Arguments: HINSTANCE hInst - module to load the string resource from
  68. // UINT nId - resource ID of the string to load
  69. //
  70. // Returns: LPSTR - On success returns a pointer to the requested string
  71. // resource. On failure the function tries to return
  72. // a pointer to the Empty string ("") but if the memory
  73. // allocation fails it can return NULL.
  74. //
  75. // History: quintinb Created Header 01/14/2000
  76. //
  77. //----------------------------------------------------------------------------
  78. CMUTILAPI LPSTR CmLoadStringA(HINSTANCE hInst, UINT nId)
  79. {
  80. //
  81. // In some far east versions of non-OSR2 win95, LoadString() ignores the
  82. // nBufferMax paramater when loading DBCS strings. As a result, if the
  83. // DBCS string is bigger than the buffer, the API overwrites the memory.
  84. // We workaround the bug by using a larger buffer size.
  85. //
  86. static fFarEastNonOSR2Win95 = IsFarEastNonOSR2Win95();
  87. size_t nLen = fFarEastNonOSR2Win95?
  88. FAREAST_WIN95_LOADSTRING_BUFSIZE :
  89. LOADSTRING_BUFSIZE;
  90. LPSTR pszString;
  91. if (!nId)
  92. {
  93. return (CmStrCpyAllocA(""));
  94. }
  95. while (1)
  96. {
  97. size_t nNewLen;
  98. pszString = (LPSTR) CmMalloc(nLen*sizeof(CHAR));
  99. MYDBGASSERT(pszString);
  100. if (NULL == pszString)
  101. {
  102. return (CmStrCpyAllocA(""));
  103. }
  104. nNewLen = LoadStringA(hInst, nId, pszString, nLen-1);
  105. //
  106. // we use nNewLen+3 because a DBCS char len can be 2 and a UNICODE
  107. // char len is 2. Ideally, we can use nLen in the above LoadString()
  108. // call and use nNewLen+2 in the line below. But nLen+3 is a safer
  109. // fix now...
  110. //
  111. if ((nNewLen + 3) < nLen)
  112. {
  113. return (pszString);
  114. }
  115. //
  116. // shouldn't reach here for far east non osr2
  117. // this will allow us to catch DBCS string resources that are
  118. // longer than FAREAST_WIN95_LOADSTRING_BUFSIZE.
  119. //
  120. MYDBGASSERT(!fFarEastNonOSR2Win95);
  121. CmFree(pszString);
  122. nLen *= 2;
  123. }
  124. }
  125. //+---------------------------------------------------------------------------
  126. //
  127. // Function: CmLoadStringW
  128. //
  129. // Synopsis: Loads the Unicode version of the string resource specified by
  130. // the passed in module instance handle and resource ID. The
  131. // function returns the requested string in a CmMalloc-ed buffer
  132. // through the return value. This buffer must be freed by the
  133. // caller. Note that CmLoadString figures out the proper buffer
  134. // size by guessing and then calling loadstring again if the buffer
  135. // is too small.
  136. //
  137. // Arguments: HINSTANCE hInst - module to load the string resource from
  138. // UINT nId - resource ID of the string to load
  139. //
  140. // Returns: LPWSTR - On success returns a pointer to the requested string
  141. // resource. On failure the function tries to return
  142. // a pointer to the Empty string ("") but if the memory
  143. // allocation fails it can return NULL.
  144. //
  145. // History: quintinb Created Header 01/14/2000
  146. //
  147. //----------------------------------------------------------------------------
  148. CMUTILAPI LPWSTR CmLoadStringW(HINSTANCE hInst, UINT nId)
  149. {
  150. size_t nLen = LOADSTRING_BUFSIZE;
  151. LPWSTR pszString;
  152. if (!nId)
  153. {
  154. return (CmStrCpyAllocW(L""));
  155. }
  156. while (1)
  157. {
  158. size_t nNewLen;
  159. pszString = (LPWSTR) CmMalloc(nLen*sizeof(WCHAR));
  160. MYDBGASSERT(pszString);
  161. if (NULL == pszString)
  162. {
  163. return (CmStrCpyAllocW(L""));
  164. }
  165. nNewLen = LoadStringU(hInst, nId, pszString, nLen-1);
  166. //
  167. // we use nNewLen+3 because a DBCS char len can be 2 and a UNICODE
  168. // char len is 2. Ideally, we can use nLen in the above LoadString()
  169. // call and use nNewLen+2 in the line below. But nLen+3 is a safer
  170. // fix now...
  171. //
  172. if ((nNewLen + 3) < nLen)
  173. {
  174. return (pszString);
  175. }
  176. CmFree(pszString);
  177. nLen *= 2;
  178. }
  179. }
  180. //+---------------------------------------------------------------------------
  181. //
  182. // Function: CmFmtMsgW
  183. //
  184. // Synopsis: Simulation of FormatMessage using wvsprintf for cross-platform
  185. // compatibility.
  186. //
  187. // Arguments: hInst - Application instance handle
  188. // dwMsgId - ID of message to use for formatting final output
  189. // ... - Variable arguments to used in message fromatting
  190. //
  191. // Returns: Allocated to formatted string.
  192. //
  193. // History: nickball - Added function header - 5/12/97
  194. // nickball - Moved to cmutil - 03/30/98
  195. // quintinb - Added W and A versions - 03/09/99
  196. //
  197. //----------------------------------------------------------------------------
  198. CMUTILAPI LPWSTR CmFmtMsgW(HINSTANCE hInst, DWORD dwMsgId, ...)
  199. {
  200. LPWSTR pszTmp = NULL;
  201. LPWSTR lpszOutput = NULL;
  202. LPWSTR lpszFormat = NULL;
  203. if (!dwMsgId)
  204. {
  205. return (CmStrCpyAllocW(L""));
  206. }
  207. // Allocate a buffer to receive the RC string with specified msg ID
  208. lpszFormat = (LPWSTR) CmMalloc(MAX_STR_LEN*sizeof(WCHAR));
  209. if (!lpszFormat)
  210. {
  211. CMASSERTMSG(FALSE, "CmFmtMsgW -- CmMalloc returned a NULL pointer for lpszFormat");
  212. return (CmStrCpyAllocW(L""));
  213. }
  214. // Initialize argument list
  215. va_list valArgs;
  216. va_start(valArgs,dwMsgId);
  217. // Load the format string from the RC
  218. int nRes = LoadStringU(hInst, (UINT) dwMsgId, lpszFormat, MAX_STR_LEN - 1);
  219. #ifdef DEBUG
  220. if (0 == nRes)
  221. {
  222. CMTRACE3(TEXT("MyFmtMsg() LoadString(dwMsgId=0x%x) return %u, GLE=%u."), dwMsgId, nRes,
  223. nRes ? 0: GetLastError());
  224. }
  225. #endif
  226. // If nothing loaded, free format buffer and bail
  227. if (nRes == 0 || lpszFormat[0] == '\0')
  228. {
  229. CMASSERTMSG(FALSE, "CmFmtMsgW -- LoadStringU returned 0 or an empty buffer.");
  230. pszTmp = (CmStrCpyAllocW(L""));
  231. goto done;
  232. }
  233. // Allocate another buffer and for use by vsprintf
  234. lpszOutput = (LPWSTR) CmMalloc(MAX_STR_LEN*sizeof(WCHAR));
  235. if (!lpszOutput)
  236. {
  237. CMASSERTMSG(FALSE, "CmFmtMsgW -- CmMalloc returned a NULL pointer for lpszOutput");
  238. pszTmp = (CmStrCpyAllocW(L""));
  239. goto done;
  240. }
  241. // Format the final output using vsprintf
  242. nRes = wvsprintfU(lpszOutput, lpszFormat, valArgs);
  243. // If wvsprintfU failed, we're done
  244. if (nRes < 0 || lpszOutput[0] == L'\0')
  245. {
  246. CMASSERTMSG(FALSE, "CmFmtMsgW -- wvsprintfU returned 0 or an empty buffer");
  247. pszTmp = (CmStrCpyAllocW(L""));
  248. goto done;
  249. }
  250. // Remove trailing spaces
  251. pszTmp = lpszOutput + lstrlenU(lpszOutput) - 1;
  252. while (CmIsSpaceW(pszTmp) && (*pszTmp != L'\n'))
  253. {
  254. *pszTmp = 0;
  255. if (pszTmp == lpszOutput)
  256. {
  257. break;
  258. }
  259. pszTmp--;
  260. }
  261. pszTmp = CmStrCpyAllocW(lpszOutput); // allocates and copies
  262. CMASSERTMSG(pszTmp, "CmFmtMsgW -- CmStrCpyAllocW returned a NULL pointer.");
  263. done:
  264. // Cleanup buffers, etc.
  265. if (lpszFormat)
  266. {
  267. CmFree(lpszFormat);
  268. }
  269. if (lpszOutput)
  270. {
  271. CmFree(lpszOutput);
  272. }
  273. va_end(valArgs);
  274. return (pszTmp);
  275. }
  276. //+---------------------------------------------------------------------------
  277. //
  278. // Function: CmFmtMsgA
  279. //
  280. // Synopsis: Simulation of FormatMessage using wvsprintf for cross-platform
  281. // compatibility.
  282. //
  283. // Arguments: hInst - Application instance handle
  284. // dwMsgId - ID of message to use for formatting final output
  285. // ... - Variable arguments to used in message fromatting
  286. //
  287. // Returns: Allocated to formatted string.
  288. //
  289. // History: nickball - Added function header - 5/12/97
  290. // nickball - Moved to cmutil - 03/30/98
  291. // quintinb - Added W and A versions - 03/09/99
  292. //
  293. //----------------------------------------------------------------------------
  294. CMUTILAPI LPSTR CmFmtMsgA(HINSTANCE hInst, DWORD dwMsgId, ...)
  295. {
  296. LPSTR pszTmp = NULL;
  297. LPSTR lpszOutput = NULL;
  298. LPSTR lpszFormat = NULL;
  299. if (!dwMsgId)
  300. {
  301. return (CmStrCpyAllocA(""));
  302. }
  303. // Allocate a buffer to receive the RC string with specified msg ID
  304. lpszFormat = (LPSTR) CmMalloc(MAX_STR_LEN);
  305. if (!lpszFormat)
  306. {
  307. CMASSERTMSG(FALSE, "CmFmtMsgA -- CmMalloc returned a NULL pointer for lpszFormat");
  308. return (CmStrCpyAllocA(""));
  309. }
  310. // Initialize argument list
  311. va_list valArgs;
  312. va_start(valArgs,dwMsgId);
  313. // Load the format string from the RC
  314. int nRes = LoadStringA(hInst, (UINT) dwMsgId, lpszFormat, MAX_STR_LEN - 1);
  315. #ifdef DEBUG
  316. if (0 == nRes)
  317. {
  318. CMTRACE3(TEXT("MyFmtMsg() LoadString(dwMsgId=0x%x) return %u, GLE=%u."), dwMsgId, nRes,
  319. nRes ? 0: GetLastError());
  320. }
  321. #endif
  322. // If nothing loaded, free format buffer and bail
  323. if (nRes == 0 || lpszFormat[0] == '\0')
  324. {
  325. pszTmp = (CmStrCpyAllocA(""));
  326. CMASSERTMSG(FALSE, "CmFmtMsgA -- LoadStringA returned 0 or an empty buffer.");
  327. goto done;
  328. }
  329. // Allocate another buffer and for use by vsprintf
  330. lpszOutput = (LPSTR) CmMalloc(MAX_STR_LEN);
  331. if (!lpszOutput)
  332. {
  333. pszTmp = (CmStrCpyAllocA(""));
  334. CMASSERTMSG(FALSE, "CmFmtMsgA -- CmMalloc returned a NULL pointer for lpszOutput");
  335. goto done;
  336. }
  337. // Format the final output using vsprintf
  338. nRes = wvsprintfA(lpszOutput, lpszFormat, valArgs);
  339. // If wvsprintfA failed, we're done
  340. if (nRes < 0 || lpszOutput[0] == '\0')
  341. {
  342. pszTmp = (CmStrCpyAllocA(""));
  343. CMASSERTMSG(FALSE, "CmFmtMsgA -- wvsprintfA returned 0 or an empty buffer");
  344. goto done;
  345. }
  346. // Remove trailing spaces
  347. pszTmp = lpszOutput + lstrlenA(lpszOutput) - 1;
  348. while (CmIsSpaceA(pszTmp) && (*pszTmp != '\n'))
  349. {
  350. *pszTmp = 0;
  351. if (pszTmp == lpszOutput)
  352. {
  353. break;
  354. }
  355. pszTmp--;
  356. }
  357. pszTmp = CmStrCpyAllocA(lpszOutput); // allocates and copies
  358. CMASSERTMSG(pszTmp, "CmFmtMsgA -- CmStrCpyAllocA returned a NULL pointer.");
  359. done:
  360. // Cleanup buffers, etc.
  361. if (lpszFormat)
  362. {
  363. CmFree(lpszFormat);
  364. }
  365. if (lpszOutput)
  366. {
  367. CmFree(lpszOutput);
  368. }
  369. va_end(valArgs);
  370. return (pszTmp);
  371. #if 0
  372. /*
  373. // Replaced by the above code because we no longer use the platform specific .MC files
  374. // All strings resources are now managed via standard .RC files
  375. va_list valArgs;
  376. DWORD dwRes;
  377. LPTSTR pszBuffer = NULL;
  378. if (!dwMsgId)
  379. {
  380. return (CmStrCpy(TEXT("")));
  381. }
  382. va_start(valArgs,dwMsgId);
  383. dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_MAX_WIDTH_MASK,
  384. hInst,
  385. dwMsgId,
  386. LANG_USER_DEFAULT,
  387. (LPTSTR) &pszBuffer,
  388. 0,
  389. &valArgs);
  390. MYDBGTST(dwRes==0,("MyFmtMsg() FormatMessage(dwMsgId=0x%x) return %u, GLE=%u.",dwMsgId,dwRes,dwRes?0:GetLastError()));
  391. va_end(valArgs);
  392. if (dwRes == 0)
  393. {
  394. if (pszBuffer)
  395. {
  396. LocalFree(pszBuffer);
  397. }
  398. return (CmStrCpy(TEXT("")));
  399. }
  400. if (!CmStrLen(pszBuffer))
  401. {
  402. LocalFree(pszBuffer);
  403. return (CmStrCpy(TEXT("")));
  404. }
  405. pszTmp = pszBuffer + CmStrLen(pszBuffer) - 1;
  406. while (MyIsSpace(*pszTmp) && (*pszTmp != '\n'))
  407. {
  408. *pszTmp = 0;
  409. if (pszTmp == pszBuffer)
  410. {
  411. break;
  412. }
  413. pszTmp--;
  414. }
  415. pszTmp = CmStrCpy(pszBuffer);
  416. LocalFree(pszBuffer);
  417. return (pszTmp);
  418. */
  419. #endif
  420. }
  421. #if 0 // not used anywhere
  422. /*
  423. //+----------------------------------------------------------------------------
  424. //
  425. // Function: GetMaxStringNumber
  426. //
  427. // Synopsis: Given a buffer containing strings in INI section format, determines
  428. // which is the highest numbered string.
  429. //
  430. // Arguments: LPTSTR pszStr - The string containing an INI section
  431. // LPDWORD pdwMax - Ptr to a DOWRD to be filled with the result
  432. // *pdwMax gets the highest value of atol() of the strings.
  433. //
  434. // Returns: Nothing
  435. //
  436. // History: Anonymous Created 3/30/98
  437. //
  438. //+----------------------------------------------------------------------------
  439. CMUTILAPI void GetMaxStringNumber(LPTSTR pszStr, LPDWORD pdwMax)
  440. {
  441. LPTSTR pszTmp;
  442. DWORD dwMax = 0;
  443. if (pszStr)
  444. {
  445. pszTmp = pszStr;
  446. while (*pszTmp)
  447. {
  448. DWORD dwMaxTmp;
  449. if (pdwMax)
  450. {
  451. dwMaxTmp = (DWORD)CmAtol(pszTmp);
  452. if (dwMaxTmp > dwMax)
  453. {
  454. dwMax = dwMaxTmp;
  455. }
  456. }
  457. pszTmp += lstrlen(pszTmp) + 1;
  458. }
  459. }
  460. if (pdwMax)
  461. {
  462. *pdwMax = dwMax;
  463. }
  464. }
  465. */
  466. #endif
  467. //+---------------------------------------------------------------------------
  468. //
  469. // Function: CmParsePathW
  470. //
  471. // Synopsis: Converts a Cm command line and args path into its component
  472. // parts. If the command portion is a relative path, it is expanded
  473. // to a full path. A ptr to the top level service filename is required
  474. // to make the relative path determination.
  475. //
  476. // Arguments: pszCmdLine - Ptr to the full entry
  477. // pszServiceFile - Ptr to top-level service filename
  478. // ppszCommand - Ptr-ptr to be allocated and filled with command portion
  479. // ppszArguments - Ptr-ptr to be allocated and filled with args portion
  480. //
  481. // Returns: TRUE if ppszCmd and ppszArgs are allocated/filled. FALSE otherwise.
  482. //
  483. // History: 02/19/99 nickball Created
  484. // 02/21/99 nickball Moved to cmutil
  485. // 03/09/99 quintinb Created A and W versions
  486. //
  487. //----------------------------------------------------------------------------
  488. CMUTILAPI BOOL CmParsePathW(LPCWSTR pszCmdLine, LPCWSTR pszServiceFile, LPWSTR *ppszCommand, LPWSTR *ppszArguments)
  489. {
  490. LPWSTR pszArgs = NULL;
  491. LPWSTR pszCmd = NULL;
  492. LPWSTR pszTmp = NULL;
  493. BOOL bRet = FALSE;
  494. MYDBGASSERT(pszCmdLine);
  495. MYDBGASSERT(pszServiceFile);
  496. MYDBGASSERT(ppszCommand);
  497. MYDBGASSERT(ppszArguments);
  498. if (NULL == pszCmdLine ||
  499. NULL == pszServiceFile ||
  500. NULL == ppszCommand ||
  501. NULL == ppszArguments)
  502. {
  503. return FALSE;
  504. }
  505. CMTRACE1(TEXT("CmParsePathW() pszCmdLine is %s"), pszCmdLine);
  506. //
  507. // Determine where our string begins and what the delimiting char should
  508. // be then make a copy of the entire command line string to muck with.
  509. //
  510. WCHAR tchDelim = L'+';
  511. if (pszCmdLine == CmStrchrW(pszCmdLine, tchDelim))
  512. {
  513. pszCmd = CmStrCpyAllocW(CharNextU(pszCmdLine));
  514. }
  515. else
  516. {
  517. pszCmd = CmStrCpyAllocW(pszCmdLine);
  518. tchDelim = L' ';
  519. }
  520. MYDBGASSERT(pszCmd);
  521. CmStrTrimW(pszCmd);
  522. //
  523. // Assuming valid inputs, pszCmd is now one of the following:
  524. //
  525. // "C:\\Program Files\\Custom.Exe+"
  526. // "C:\\Program Files\\Custom.Exe+ Args"
  527. // "C:\\Progra~1\\Custom.Exe
  528. // "C:\\Progra~1\\Custom.Exe Args"
  529. // "service\custom.exe"
  530. // "service\custom.exe Args"
  531. //
  532. if (pszCmd && L'\0' != *pszCmd)
  533. {
  534. //
  535. // Locate the right command delimiter
  536. //
  537. pszArgs = CmStrchrW(pszCmd, tchDelim);
  538. if (pszArgs)
  539. {
  540. //
  541. // Content of pszTmp is now either "+ Args", "", or "+"
  542. // Get a pointer to the next char and truncate the pszCmd
  543. // that we have thus far.
  544. //
  545. pszTmp = CharNextU(pszArgs); // pszArgs is " Args" or ""
  546. *pszArgs = L'\0'; // The "+" becomes ""
  547. pszArgs = pszTmp; // pszTmp is " Args" or ""
  548. }
  549. //
  550. // Fill argument buffer from pszTmp and command buffer
  551. // from pszCmd with a complete path if necessary.
  552. //
  553. if (NULL == pszArgs)
  554. {
  555. *ppszArguments = (LPWSTR)CmMalloc(sizeof(WCHAR)); // one Zero-ed WCHAR
  556. }
  557. else
  558. {
  559. MYVERIFY(*ppszArguments = CmStrCpyAllocW(pszArgs));
  560. }
  561. MYVERIFY(*ppszCommand = CmConvertRelativePathW(pszServiceFile, pszCmd));
  562. //
  563. // Trim blanks as needed
  564. //
  565. if (*ppszCommand)
  566. {
  567. CmStrTrimW(*ppszCommand);
  568. }
  569. if (*ppszArguments)
  570. {
  571. CmStrTrimW(*ppszArguments);
  572. }
  573. bRet = TRUE;
  574. }
  575. //
  576. // Cleanup. Note: pszArgs is never allocated, so we don't have to free it.
  577. //
  578. CmFree(pszCmd);
  579. return bRet;
  580. }
  581. //+---------------------------------------------------------------------------
  582. //
  583. // Function: CmParsePathA
  584. //
  585. // Synopsis: Converts a Cm command line and args path into its component
  586. // parts. If the command portion is a relative path, it is expanded
  587. // to a full path. A ptr to the top level service filename is required
  588. // to make the relative path determination.
  589. //
  590. // Arguments: pszCmdLine - Ptr to the full entry
  591. // pszServiceFile - Ptr to top-level service filename
  592. // ppszCommand - Ptr-ptr to be allocated and filled with command portion
  593. // ppszArguments - Ptr-ptr to be allocated and filled with args portion
  594. //
  595. // Returns: TRUE if ppszCmd and ppszArgs are allocated/filled. FALSE otherwise.
  596. //
  597. // History: 02/19/99 nickball Created
  598. // 02/21/99 nickball Moved to cmutil
  599. // 03/09/99 quintinb Created A and W versions
  600. //
  601. //----------------------------------------------------------------------------
  602. CMUTILAPI BOOL CmParsePathA(LPCSTR pszCmdLine, LPCSTR pszServiceFile, LPSTR *ppszCommand, LPSTR *ppszArguments)
  603. {
  604. LPSTR pszArgs = NULL;
  605. LPSTR pszCmd = NULL;
  606. LPSTR pszTmp = NULL;
  607. BOOL bRet = FALSE;
  608. MYDBGASSERT(pszCmdLine);
  609. MYDBGASSERT(pszServiceFile);
  610. MYDBGASSERT(ppszCommand);
  611. MYDBGASSERT(ppszArguments);
  612. if (NULL == pszCmdLine ||
  613. NULL == pszServiceFile ||
  614. NULL == ppszCommand ||
  615. NULL == ppszArguments)
  616. {
  617. return FALSE;
  618. }
  619. CMTRACE1(TEXT("CmParsePathA() pszCmdLine is %s"), pszCmdLine);
  620. //
  621. // Determine where our string begins and what the delimiting char should
  622. // be then make a copy of the entire command line string to muck with.
  623. //
  624. CHAR tchDelim = '+';
  625. if (pszCmdLine == CmStrchrA(pszCmdLine, tchDelim))
  626. {
  627. pszCmd = CmStrCpyAllocA(CharNextA(pszCmdLine));
  628. }
  629. else
  630. {
  631. pszCmd = CmStrCpyAllocA(pszCmdLine);
  632. tchDelim = ' ';
  633. }
  634. MYDBGASSERT(pszCmd);
  635. CmStrTrimA(pszCmd);
  636. //
  637. // Assuming valid inputs, pszCmd is now one of the following:
  638. //
  639. // "C:\\Program Files\\Custom.Exe+"
  640. // "C:\\Program Files\\Custom.Exe+ Args"
  641. // "C:\\Progra~1\\Custom.Exe
  642. // "C:\\Progra~1\\Custom.Exe Args"
  643. // "service\custom.exe"
  644. // "service\custom.exe Args"
  645. //
  646. if (pszCmd && '\0' != *pszCmd)
  647. {
  648. //
  649. // Locate the right command delimiter
  650. //
  651. pszArgs = CmStrchrA(pszCmd, tchDelim);
  652. if (pszArgs)
  653. {
  654. //
  655. // Content of pszTmp is now either "+ Args", "", or "+"
  656. // Get a pointer to the next char and truncate the pszCmd
  657. // that we have thus far.
  658. //
  659. pszTmp = CharNextA(pszArgs); // pszArgs is " Args" or ""
  660. *pszArgs = '\0'; // The "+" becomes ""
  661. pszArgs = pszTmp; // pszTmp is " Args" or ""
  662. }
  663. //
  664. // Fill argument buffer from pszTmp and command buffer
  665. // from pszCmd with a complete path if necessary.
  666. //
  667. if (NULL == pszArgs)
  668. {
  669. MYVERIFY(*ppszArguments = (LPSTR)CmMalloc(sizeof(CHAR))); // one Zero-ed char
  670. }
  671. else
  672. {
  673. MYVERIFY(*ppszArguments = CmStrCpyAllocA(pszArgs));
  674. }
  675. MYVERIFY(*ppszCommand = CmConvertRelativePathA(pszServiceFile, pszCmd));
  676. //
  677. // Trim blanks as needed
  678. //
  679. if (*ppszCommand)
  680. {
  681. CmStrTrimA(*ppszCommand);
  682. }
  683. if (*ppszArguments)
  684. {
  685. CmStrTrimA(*ppszArguments);
  686. }
  687. bRet = TRUE;
  688. }
  689. //
  690. // Cleanup. Note: pszArgs is never allocated, so we don't have to free it.
  691. //
  692. CmFree(pszCmd);
  693. return bRet;
  694. }
  695. //+----------------------------------------------------------------------------
  696. //
  697. // Function: CmConvertRelativePathA
  698. //
  699. // Synopsis: Converts the specified relative path to a full path. If the
  700. // specified path is not a relative path specific to this profile,
  701. // it is ignored.
  702. //
  703. // Arguments: LPCSTR pszServiceFile - Full path to the .cms file
  704. // LPCSTR pszRelative - The relative path fragment
  705. //
  706. // Returns: LPSTR - NULL on failure
  707. //
  708. // Note: Do not pass referenced profile service objects to this routine.
  709. // It is designed to derive the short-service name from the top-level
  710. // service filename and path.
  711. //
  712. // History: 03/11/98 nickball Created
  713. // 02/03/99 nickball Added header Note
  714. // 02/21/99 nickball Moved to cmutil
  715. // 03/09/99 quintinb Added W and A versions
  716. //
  717. //+----------------------------------------------------------------------------
  718. CMUTILAPI LPSTR CmConvertRelativePathA(LPCSTR pszServiceFile,
  719. LPSTR pszRelative)
  720. {
  721. MYDBGASSERT(pszServiceFile);
  722. MYDBGASSERT(*pszServiceFile);
  723. MYDBGASSERT(pszRelative);
  724. MYDBGASSERT(*pszRelative);
  725. if (NULL == pszRelative || 0 == pszRelative[0] ||
  726. NULL == pszServiceFile || 0 == pszServiceFile[0])
  727. {
  728. return NULL;
  729. }
  730. //
  731. // Get the relative dir that we expect to find
  732. //
  733. LPSTR pszConverted = NULL;
  734. LPSTR pszRelDir = CmStripPathAndExtA(pszServiceFile);
  735. if (pszRelDir && *pszRelDir)
  736. {
  737. lstrcatA(pszRelDir, "\\");
  738. //
  739. // Compare against the specifed FRAGMENT. If it matches, convert.
  740. //
  741. CharUpperA(pszRelDir);
  742. CharUpperA(pszRelative);
  743. if (pszRelative == CmStrStrA(pszRelative, pszRelDir))
  744. {
  745. //
  746. // Combine CMS path and relative for complete
  747. //
  748. LPSTR pszTmp = CmStripFileNameA(pszServiceFile, FALSE);
  749. pszConverted = CmBuildFullPathFromRelativeA(pszTmp, pszRelative);
  750. CmFree(pszTmp);
  751. }
  752. else
  753. {
  754. //
  755. // Its not a relative path for this profile, just make a copy
  756. //
  757. pszConverted = CmStrCpyAllocA(pszRelative);
  758. }
  759. }
  760. CmFree(pszRelDir);
  761. return pszConverted;
  762. }
  763. //+----------------------------------------------------------------------------
  764. //
  765. // Function: CmConvertRelativePathW
  766. //
  767. // Synopsis: Converts the specified relative path to a full path. If the
  768. // specified path is not a relative path specific to this profile,
  769. // it is ignored.
  770. //
  771. // Arguments: LPCWSTR pszServiceFile - Full path to the .cms file
  772. // LPCWSTR pszRelative - The relative path fragment
  773. //
  774. // Returns: LPWSTR - NULL on failure
  775. //
  776. // Note: Do not pass referenced profile service objects to this routine.
  777. // It is designed to derive the short-service name from the top-level
  778. // service filename and path.
  779. //
  780. // History: 03/11/98 nickball Created
  781. // 02/03/99 nickball Added header Note
  782. // 02/21/99 nickball Moved to cmutil
  783. // 03/09/99 quintinb Added W and A versions
  784. //
  785. //+----------------------------------------------------------------------------
  786. CMUTILAPI LPWSTR CmConvertRelativePathW(LPCWSTR pszServiceFile,
  787. LPWSTR pszRelative)
  788. {
  789. MYDBGASSERT(pszServiceFile);
  790. MYDBGASSERT(*pszServiceFile);
  791. MYDBGASSERT(pszRelative);
  792. MYDBGASSERT(*pszRelative);
  793. if (NULL == pszRelative || 0 == pszRelative[0] ||
  794. NULL == pszServiceFile || 0 == pszServiceFile[0])
  795. {
  796. return NULL;
  797. }
  798. //
  799. // Get the relative dir that we expect to find
  800. //
  801. LPWSTR pszConverted = NULL;
  802. LPWSTR pszRelDir = CmStripPathAndExtW(pszServiceFile);
  803. if (pszRelDir && *pszRelDir)
  804. {
  805. lstrcatU(pszRelDir, L"\\");
  806. //
  807. // Compare against the specifed FRAGMENT. If it matches, convert.
  808. //
  809. CharUpperU(pszRelDir);
  810. CharUpperU(pszRelative);
  811. if (pszRelative == CmStrStrW(pszRelative, pszRelDir))
  812. {
  813. //
  814. // Combine CMS path and relative for complete
  815. //
  816. LPWSTR pszTmp = CmStripFileNameW(pszServiceFile, FALSE);
  817. pszConverted = CmBuildFullPathFromRelativeW(pszTmp, pszRelative);
  818. CmFree(pszTmp);
  819. }
  820. else
  821. {
  822. //
  823. // Its not a relative path for this profile, just make a copy
  824. //
  825. pszConverted = CmStrCpyAllocW(pszRelative);
  826. }
  827. }
  828. CmFree(pszRelDir);
  829. return pszConverted;
  830. }
  831. //+----------------------------------------------------------------------------
  832. //
  833. // Function: CmStripPathAndExtA
  834. //
  835. // Synopsis: Helper function, strips path and extension from a filename path
  836. //
  837. // Arguments: pszFileName - the filename path to be modified
  838. //
  839. // Returns: LPSTR - The base filename sub-string
  840. //
  841. // History: nickball Created header 8/12/98
  842. // nickball Moved to cmutil 02/21/99
  843. // quintinb Added W and A versions 03/09/99
  844. //
  845. //+----------------------------------------------------------------------------
  846. CMUTILAPI LPSTR CmStripPathAndExtA(LPCSTR pszFileName)
  847. {
  848. MYDBGASSERT(pszFileName);
  849. if (NULL == pszFileName)
  850. {
  851. return NULL;
  852. }
  853. MYDBGASSERT(*pszFileName);
  854. //
  855. // Make a copy of the string and validate format "\\." required.
  856. //
  857. LPSTR pszTmp = CmStrCpyAllocA(pszFileName);
  858. if (NULL == pszTmp)
  859. {
  860. MYDBGASSERT(pszTmp);
  861. return NULL;
  862. }
  863. LPSTR pszDot = CmStrrchrA(pszTmp, '.');
  864. LPSTR pszSlash = CmStrrchrA(pszTmp, '\\');
  865. if (NULL == pszDot || NULL == pszSlash || pszDot < pszSlash)
  866. {
  867. CmFree(pszTmp);
  868. MYDBGASSERT(FALSE);
  869. return NULL;
  870. }
  871. *pszDot = '\0';
  872. //
  873. // Increment past slash and copy remainder
  874. //
  875. pszSlash = CharNextA(pszSlash);
  876. lstrcpyA(pszTmp, pszSlash);
  877. return (pszTmp);
  878. }
  879. //+----------------------------------------------------------------------------
  880. //
  881. // Function: CmStripPathAndExtW
  882. //
  883. // Synopsis: Helper function, strips path and extension from a filename path
  884. //
  885. // Arguments: pszFileName - the filename path to be modified
  886. //
  887. // Returns: LPWSTR - The base filename sub-string
  888. //
  889. // History: nickball Created header 8/12/98
  890. // nickball Moved to cmutil 02/21/99
  891. // quintinb Added W and A versions 03/09/99
  892. //
  893. //+----------------------------------------------------------------------------
  894. CMUTILAPI LPWSTR CmStripPathAndExtW(LPCWSTR pszFileName)
  895. {
  896. MYDBGASSERT(pszFileName);
  897. if (NULL == pszFileName)
  898. {
  899. return NULL;
  900. }
  901. MYDBGASSERT(*pszFileName);
  902. //
  903. // Make a copy of the string and validate format "\\." required.
  904. //
  905. LPWSTR pszTmp = CmStrCpyAllocW(pszFileName);
  906. if (NULL == pszTmp)
  907. {
  908. MYDBGASSERT(FALSE);
  909. return NULL;
  910. }
  911. LPWSTR pszDot = CmStrrchrW(pszTmp, L'.');
  912. LPWSTR pszSlash = CmStrrchrW(pszTmp, L'\\');
  913. if (NULL == pszDot || NULL == pszSlash || pszDot < pszSlash)
  914. {
  915. CmFree(pszTmp);
  916. MYDBGASSERT(FALSE);
  917. return NULL;
  918. }
  919. *pszDot = L'\0';
  920. //
  921. // Increment past slash and copy remainder
  922. //
  923. pszSlash = CharNextU(pszSlash);
  924. lstrcpyU(pszTmp, pszSlash);
  925. return (pszTmp);
  926. }
  927. //+----------------------------------------------------------------------------
  928. //
  929. // Function: CmStripFileNameA
  930. //
  931. // Synopsis: Helper function to deal with the tedium of extracting the path
  932. // part of a complete filename.
  933. //
  934. // Arguments: LPCSTR pszFullNameAndPath - Ptr to the filename
  935. // BOOL fKeepSlash - Flag indicating that trailing directory '\' should be retained.
  936. //
  937. // Returns: LPSTR - Ptr to an allocated buffer containing the dir, or NULL on failure.
  938. //
  939. // Note: It is up to the caller to provide reasonable input, the only requirement
  940. // is that the input contain '\'.
  941. //
  942. // History: nickball Created 3/10/98
  943. // nickball Moved to cmutil 02/21/99
  944. // quintinb Added W and A versions 03/09/99
  945. //
  946. //+----------------------------------------------------------------------------
  947. CMUTILAPI LPSTR CmStripFileNameA(LPCSTR pszFullNameAndPath, BOOL fKeepSlash)
  948. {
  949. MYDBGASSERT(pszFullNameAndPath);
  950. if (NULL == pszFullNameAndPath)
  951. {
  952. return NULL;
  953. }
  954. //
  955. // Make a copy of the filename and locate the last '\'
  956. //
  957. LPSTR pszTmp = CmStrCpyAllocA(pszFullNameAndPath);
  958. if (NULL == pszTmp)
  959. {
  960. CMASSERTMSG(NULL, "CmStripFileNameA -- CmStrCpyAllocA returned a NULL pointer for pszTmp");
  961. return NULL;
  962. }
  963. LPSTR pszSlash = CmStrrchrA(pszTmp, '\\');
  964. if (NULL == pszSlash)
  965. {
  966. MYDBGASSERT(FALSE);
  967. CmFree(pszTmp);
  968. return NULL;
  969. }
  970. //
  971. // If slash is desired, move to next char before truncating
  972. //
  973. if (fKeepSlash)
  974. {
  975. pszSlash = CharNextA(pszSlash);
  976. }
  977. *pszSlash = '\0';
  978. return pszTmp;
  979. }
  980. //+----------------------------------------------------------------------------
  981. //
  982. // Function: CmStripFileNameW
  983. //
  984. // Synopsis: Helper function to deal with the tedium of extracting the path
  985. // part of a complete filename.
  986. //
  987. // Arguments: LPCWSTR pszFullNameAndPath - Ptr to the filename
  988. // BOOL fKeepSlash - Flag indicating that trailing directory '\' should be retained.
  989. //
  990. // Returns: LPWSTR - Ptr to an allocated buffer containing the dir, or NULL on failure.
  991. //
  992. // Note: It is up to the caller to provide reasonable input, the only requirement
  993. // is that the input contain '\'.
  994. //
  995. // History: nickball Created 3/10/98
  996. // nickball Moved to cmutil 02/21/99
  997. // quintinb Added W and A versions 03/09/99
  998. //
  999. //+----------------------------------------------------------------------------
  1000. CMUTILAPI LPWSTR CmStripFileNameW(LPCWSTR pszFullNameAndPath, BOOL fKeepSlash)
  1001. {
  1002. MYDBGASSERT(pszFullNameAndPath);
  1003. if (NULL == pszFullNameAndPath)
  1004. {
  1005. return NULL;
  1006. }
  1007. //
  1008. // Make a copy of the filename and locate the last '\'
  1009. //
  1010. LPWSTR pszTmp = CmStrCpyAllocW(pszFullNameAndPath);
  1011. if (NULL == pszTmp)
  1012. {
  1013. CMASSERTMSG(NULL, "CmStripFileNameW -- CmStrCpyAllocW returned a NULL pointer for pszTmp");
  1014. return NULL;
  1015. }
  1016. LPWSTR pszSlash = CmStrrchrW(pszTmp, L'\\');
  1017. if (NULL == pszSlash)
  1018. {
  1019. MYDBGASSERT(FALSE);
  1020. CmFree(pszTmp);
  1021. return NULL;
  1022. }
  1023. //
  1024. // If slash is desired, move to next char before truncating
  1025. //
  1026. if (fKeepSlash)
  1027. {
  1028. pszSlash = CharNextU(pszSlash);
  1029. }
  1030. *pszSlash = L'\0';
  1031. return pszTmp;
  1032. }
  1033. //+----------------------------------------------------------------------------
  1034. //
  1035. // Function: CmBuildFullPathFromRelativeA
  1036. //
  1037. // Synopsis: Builds a full path by stripping the filename from pszFullFileName
  1038. // and appending pszRelative.
  1039. //
  1040. // Arguments: LPCSTR pszFullFileName - A full path and filename
  1041. // LPCSTR pszRelative - Relative path fragment.
  1042. //
  1043. // Typically used to construct a full path to a file in the profile directory
  1044. // based upon the path to the .CMP file.
  1045. //
  1046. // Returns: LPSTR - Ptr to the completed path which must be freed by the caller.
  1047. //
  1048. // Note: pszRelative must NOT contain a leading "\"
  1049. //
  1050. // History: nickball Created 03/08/98
  1051. // nickball Moved to cmutil 02/21/99
  1052. //
  1053. //+----------------------------------------------------------------------------
  1054. CMUTILAPI LPSTR CmBuildFullPathFromRelativeA(LPCSTR pszFullFileName,
  1055. LPCSTR pszRelative)
  1056. {
  1057. MYDBGASSERT(pszFullFileName);
  1058. MYDBGASSERT(pszRelative);
  1059. //
  1060. // Check assumptions
  1061. //
  1062. if (NULL == pszFullFileName || NULL == pszRelative)
  1063. {
  1064. return NULL;
  1065. }
  1066. //
  1067. // No empty strings please
  1068. //
  1069. MYDBGASSERT(*pszFullFileName);
  1070. MYDBGASSERT(*pszRelative);
  1071. MYDBGASSERT(pszRelative[0] != '\\');
  1072. //
  1073. // Get the directory name including trailing '\'
  1074. //
  1075. LPSTR pszFull = NULL;
  1076. LPSTR pszProfile = CmStripFileNameA(pszFullFileName, TRUE);
  1077. if (pszProfile && *pszProfile)
  1078. {
  1079. pszFull = (LPSTR) CmMalloc(lstrlenA(pszProfile) + lstrlenA(pszRelative) + sizeof(CHAR));
  1080. MYDBGASSERT(pszFull);
  1081. if (pszFull)
  1082. {
  1083. //
  1084. // Build the complete path with new relative extension
  1085. //
  1086. lstrcpyA(pszFull, pszProfile);
  1087. lstrcatA(pszFull, pszRelative);
  1088. }
  1089. }
  1090. CmFree(pszProfile);
  1091. return pszFull;
  1092. }
  1093. //+----------------------------------------------------------------------------
  1094. //
  1095. // Function: CmBuildFullPathFromRelativeW
  1096. //
  1097. // Synopsis: Builds a full path by stripping the filename from pszFullFileName
  1098. // and appending pszRelative.
  1099. //
  1100. // Arguments: LPWTSTR pszFullFileName - A full path and filename
  1101. // LPWTSTR pszRelative - Relative path fragment.
  1102. //
  1103. // Typically used to construct a full path to a file in the profile directory
  1104. // based upon the path to the .CMP file.
  1105. //
  1106. // Returns: LPWSTR - Ptr to the completed path which must be freed by the caller.
  1107. //
  1108. // Note: pszRelative must NOT contain a leading "\"
  1109. //
  1110. // History: nickball Created 3/8/98
  1111. // nickball Moved to cmutil 02/21/99
  1112. //
  1113. //+----------------------------------------------------------------------------
  1114. CMUTILAPI LPWSTR CmBuildFullPathFromRelativeW(LPCWSTR pszFullFileName,
  1115. LPCWSTR pszRelative)
  1116. {
  1117. MYDBGASSERT(pszFullFileName);
  1118. MYDBGASSERT(pszRelative);
  1119. //
  1120. // Check assumptions
  1121. //
  1122. if (NULL == pszFullFileName || NULL == pszRelative)
  1123. {
  1124. return NULL;
  1125. }
  1126. //
  1127. // No empty strings please
  1128. //
  1129. MYDBGASSERT(*pszFullFileName);
  1130. MYDBGASSERT(*pszRelative);
  1131. MYDBGASSERT(pszRelative[0] != L'\\');
  1132. //
  1133. // Get the directory name including trailing '\'
  1134. //
  1135. LPWSTR pszFull = NULL;
  1136. LPWSTR pszProfile = CmStripFileNameW(pszFullFileName, TRUE);
  1137. if (pszProfile && *pszProfile)
  1138. {
  1139. pszFull = (LPWSTR) CmMalloc((lstrlenU(pszProfile) + lstrlenU(pszRelative) + 1)*sizeof(WCHAR));
  1140. MYDBGASSERT(pszFull);
  1141. if (pszFull)
  1142. {
  1143. //
  1144. // Build the complete path with new relative extension
  1145. //
  1146. lstrcpyU(pszFull, pszProfile);
  1147. lstrcatU(pszFull, pszRelative);
  1148. }
  1149. }
  1150. CmFree(pszProfile);
  1151. return pszFull;
  1152. }
  1153. //+-----------------------------------------------------------------------------------------
  1154. // Function: CmWinHelp
  1155. //
  1156. // Synopsis: Calls Winhelp using the command line parameters
  1157. //
  1158. // Arguments: See winhelp documentation
  1159. // hWndItem - This is a additional parameter we use to designate the window/control for
  1160. // which help(context) is needed.
  1161. // Returns: TRUE if help was launched successfully otherwise FALSE
  1162. //
  1163. // Notes:
  1164. //
  1165. // History: v-vijayb 7/10/99
  1166. //
  1167. //+-----------------------------------------------------------------------------------------
  1168. CMUTILAPI BOOL CmWinHelp(HWND hWndMain, HWND hWndItem, CONST WCHAR *lpszHelp, UINT uCommand, ULONG_PTR dwData)
  1169. {
  1170. DWORD cb;
  1171. TCHAR szName[MAX_PATH];
  1172. BOOL fRun = FALSE;
  1173. DWORD *prgWinIdHelpId = (DWORD *) dwData;
  1174. //
  1175. // Get the name of the desktop. Normally returns default or Winlogon or system or WinNT
  1176. // On Win95/98 GetUserObjectInformation is not supported and thus the desktop name
  1177. // will be empty so we will use the good old help API
  1178. //
  1179. szName[0] = 0;
  1180. HDESK hDesk = GetThreadDesktop(GetCurrentThreadId());
  1181. if (hDesk)
  1182. {
  1183. GetUserObjectInformation(hDesk, UOI_NAME, szName, sizeof(szName), &cb);
  1184. CMTRACE1(TEXT("Desktop = %s"), szName);
  1185. if (CmCompareString(TEXT("Winlogon"), szName) == 0)
  1186. {
  1187. return FALSE;
  1188. }
  1189. else
  1190. {
  1191. fRun = WinHelpU(hWndMain, lpszHelp, uCommand, (ULONG_PTR) prgWinIdHelpId);
  1192. }
  1193. }
  1194. return (fRun);
  1195. }
  1196. //+----------------------------------------------------------------------------
  1197. //
  1198. // Function: IsLogonAsSystem
  1199. //
  1200. // Synopsis: Whether the current process is running in the system account
  1201. //
  1202. // Arguments: None
  1203. //
  1204. // Returns: BOOL - TRUE if running in system account
  1205. //
  1206. // History: fengsun Created Header 7/13/98
  1207. // v-vijayb Modified to use SIDs instead of username
  1208. //
  1209. //+----------------------------------------------------------------------------
  1210. CMUTILAPI BOOL IsLogonAsSystem()
  1211. {
  1212. static BOOL fLogonAsSystem = -1;
  1213. //
  1214. // If this function has been called before, return the saved value.
  1215. //
  1216. if (fLogonAsSystem != -1)
  1217. {
  1218. return fLogonAsSystem;
  1219. }
  1220. //
  1221. // Runs only under NT
  1222. //
  1223. if (OS_NT)
  1224. {
  1225. HANDLE hProcess, hAccess;
  1226. DWORD cbTokenInfo, cbRetInfo;
  1227. PTOKEN_USER pTokenInfo;
  1228. SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
  1229. PSID pSystemSID = NULL;
  1230. //
  1231. // On NT, we pick the more stringent value for the default.
  1232. //
  1233. fLogonAsSystem = TRUE;
  1234. if (AllocateAndInitializeSid(&SIDAuthNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSID))
  1235. {
  1236. hProcess = GetCurrentProcess(); // Pseudo handle, no need to close
  1237. if (OpenProcessToken(hProcess, TOKEN_READ, &hAccess))
  1238. {
  1239. BOOL bRet = GetTokenInformation(hAccess, TokenUser, NULL, 0, &cbRetInfo);
  1240. MYDBGASSERT((FALSE == bRet) && (0 != cbRetInfo));
  1241. if (cbRetInfo)
  1242. {
  1243. cbTokenInfo = cbRetInfo;
  1244. pTokenInfo = (PTOKEN_USER) CmMalloc( cbTokenInfo * sizeof(BYTE) );
  1245. if (pTokenInfo)
  1246. {
  1247. if (GetTokenInformation(hAccess, TokenUser, (PVOID) pTokenInfo, cbTokenInfo, &cbRetInfo))
  1248. {
  1249. if (EqualSid(pTokenInfo->User.Sid, pSystemSID))
  1250. {
  1251. CMTRACE(TEXT("Running under LOCALSYSTEM account"));
  1252. fLogonAsSystem = TRUE;
  1253. }
  1254. else
  1255. {
  1256. fLogonAsSystem = FALSE;
  1257. }
  1258. }
  1259. CmFree(pTokenInfo);
  1260. }
  1261. }
  1262. CloseHandle(hAccess);
  1263. }
  1264. FreeSid(pSystemSID);
  1265. }
  1266. }
  1267. else
  1268. {
  1269. fLogonAsSystem = FALSE;
  1270. }
  1271. return fLogonAsSystem;
  1272. }