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.

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