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.

1315 lines
33 KiB

  1. /////////////////////////////////////////////////////////////////////
  2. //
  3. // Utils.cpp
  4. //
  5. // General-purpose routines that are project independent.
  6. //
  7. // HISTORY
  8. // t-danmo 96.09.22 Creation.
  9. //
  10. /////////////////////////////////////////////////////////////////////
  11. #include "stdafx.h"
  12. #include "progress.h" // CServiceControlProgress
  13. #include "macros.h" // MFC_TRY/MFC_CATCH
  14. USE_HANDLE_MACROS("FILEMGMT(utils.cpp)")
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. //
  21. // Fusion MFC-based property page
  22. //
  23. HPROPSHEETPAGE MyCreatePropertySheetPage(AFX_OLDPROPSHEETPAGE* psp)
  24. {
  25. PROPSHEETPAGE_V3 sp_v3 = {0};
  26. CopyMemory (&sp_v3, psp, psp->dwSize);
  27. sp_v3.dwSize = sizeof(sp_v3);
  28. return (::CreatePropertySheetPage (&sp_v3));
  29. }
  30. /////////////////////////////////////////////////////////////////////
  31. void
  32. ComboBox_FlushContent(HWND hwndCombo)
  33. {
  34. Assert(IsWindow(hwndCombo));
  35. SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
  36. }
  37. /////////////////////////////////////////////////////////////////////
  38. // ComboBox_FFill()
  39. //
  40. // Fill a combo box with the array of string Ids.
  41. //
  42. // Return FALSE if an error occurs (such as stringId not found).
  43. //
  44. BOOL
  45. ComboBox_FFill(
  46. const HWND hwndCombo, // IN: Handle of the combobox
  47. const TStringParamEntry rgzSPE[], // IN: SPE aray zero terminated
  48. const LPARAM lItemDataSelect) // IN: Which item to select
  49. {
  50. CString str;
  51. TCHAR szBuffer[1024];
  52. LRESULT lResult;
  53. Assert(IsWindow(hwndCombo));
  54. Assert(rgzSPE != NULL);
  55. for (int i = 0; rgzSPE[i].uStringId != 0; i++)
  56. {
  57. if (!::LoadString(g_hInstanceSave, rgzSPE[i].uStringId,
  58. OUT szBuffer, LENGTH(szBuffer)))
  59. {
  60. TRACE1("Unable to load string Id=%d.\n", rgzSPE[i].uStringId);
  61. Assert(FALSE && "Unable to load string");
  62. return FALSE;
  63. }
  64. lResult = SendMessage(hwndCombo, CB_ADDSTRING, 0,
  65. reinterpret_cast<LPARAM>(szBuffer));
  66. Report(lResult >= 0);
  67. const WPARAM iIndex = lResult;
  68. lResult = SendMessage(hwndCombo, CB_SETITEMDATA, iIndex,
  69. rgzSPE[i].lItemData);
  70. Report(lResult != CB_ERR);
  71. if (rgzSPE[i].lItemData == lItemDataSelect)
  72. {
  73. SendMessage(hwndCombo, CB_SETCURSEL, iIndex, 0);
  74. }
  75. } // for
  76. return TRUE;
  77. } // ComboBox_FFill()
  78. /////////////////////////////////////////////////////////////////////
  79. // ComboBox_FGetSelectedItemData()
  80. //
  81. // Get the value of the lParam field of the current selected item.
  82. //
  83. // If an error occurs return -1 (CB_ERR).
  84. // Otherwise the value of the selected item.
  85. //
  86. LPARAM
  87. ComboBox_GetSelectedItemData(HWND hwndComboBox)
  88. {
  89. LPARAM l;
  90. Assert(IsWindow(hwndComboBox));
  91. l = SendMessage(hwndComboBox, CB_GETCURSEL, 0, 0);
  92. Report(l != CB_ERR && "Combobox has no item selected");
  93. l = SendMessage(hwndComboBox, CB_GETITEMDATA, l, 0);
  94. Assert(l != CB_ERR && "Cannot extract item data from combobox");
  95. if (l == CB_ERR)
  96. {
  97. Assert(CB_ERR == -1);
  98. return -1;
  99. }
  100. return l;
  101. } // ComboBox_GetSelectedItemData()
  102. /////////////////////////////////////////////////////////////////////
  103. HWND
  104. HGetDlgItem(HWND hdlg, INT nIdDlgItem)
  105. {
  106. Assert(IsWindow(hdlg));
  107. Assert(IsWindow(GetDlgItem(hdlg, nIdDlgItem)));
  108. return GetDlgItem(hdlg, nIdDlgItem);
  109. } // HGetDlgItem()
  110. /////////////////////////////////////////////////////////////////////
  111. void
  112. SetDlgItemFocus(HWND hdlg, INT nIdDlgItem)
  113. {
  114. Assert(IsWindow(hdlg));
  115. Assert(IsWindow(GetDlgItem(hdlg, nIdDlgItem)));
  116. SetFocus(GetDlgItem(hdlg, nIdDlgItem));
  117. }
  118. /////////////////////////////////////////////////////////////////////
  119. void
  120. EnableDlgItem(HWND hdlg, INT nIdDlgItem, BOOL fEnable)
  121. {
  122. Assert(IsWindow(hdlg));
  123. Assert(IsWindow(GetDlgItem(hdlg, nIdDlgItem)));
  124. EnableWindow(GetDlgItem(hdlg, nIdDlgItem), fEnable);
  125. }
  126. /////////////////////////////////////////////////////////////////////
  127. // Enable/disable one or more controls in a dialog.
  128. void
  129. EnableDlgItemGroup(
  130. HWND hdlg, // IN: Parent dialog of the controls
  131. const UINT rgzidCtl[], // IN: Group (array) of control Ids to be enabled (or disabled)
  132. BOOL fEnableAll) // IN: TRUE => We want to enable the controls; FALSE => We want to disable the controls
  133. {
  134. Assert(IsWindow(hdlg));
  135. Assert(rgzidCtl != NULL);
  136. for (const UINT * pidCtl = rgzidCtl; *pidCtl != 0; pidCtl++)
  137. {
  138. EnableWindow(HGetDlgItem(hdlg, *pidCtl), fEnableAll);
  139. }
  140. } // EnableDlgItemGroup()
  141. /////////////////////////////////////////////////////////////////////
  142. // Show/hide one or more controls in a dialog.
  143. void
  144. ShowDlgItemGroup(
  145. HWND hdlg, // IN: Parent dialog of the controls
  146. const UINT rgzidCtl[], // IN: Group (array) of control Ids to be shown (or hidden)
  147. BOOL fShowAll) // IN: TRUE => We want to show the controls; FALSE => We want to hide the controls
  148. {
  149. Assert(IsWindow(hdlg));
  150. Assert(rgzidCtl != NULL);
  151. INT nCmdShow = fShowAll ? SW_SHOW : SW_HIDE;
  152. for (const UINT * pidCtl = rgzidCtl; *pidCtl != 0; pidCtl++)
  153. {
  154. ShowWindow(HGetDlgItem(hdlg, *pidCtl), nCmdShow);
  155. }
  156. } // ShowDlgItemGroup()
  157. /////////////////////////////////////////////////////////////////////
  158. // Str_PchCopyChN()
  159. //
  160. // Copy a string until reaching character chStop or destination buffer full.
  161. //
  162. // RETURNS
  163. // Pointer to the last character of source buffer not copied into destination buffer.
  164. // This may be useful to parse the rest of the source string.
  165. //
  166. // INTERFACE NOTES
  167. // Character chStop is not copied into the destination buffer.
  168. // If cchDstMax==0, the number of characters will not be limited.
  169. //
  170. TCHAR *
  171. Str_PchCopyChN(
  172. TCHAR * szDst, // OUT: Destination buffer
  173. CONST TCHAR * szSrc, // IN: Source buffer
  174. TCHAR chStop, // IN: Character to stop the copying
  175. INT cchDstMax) // IN: Length of the output buffer
  176. {
  177. Assert(szDst != NULL);
  178. Assert(szSrc != NULL);
  179. Assert(cchDstMax >= 0);
  180. while (*szSrc != '\0' && *szSrc != chStop && --cchDstMax != 0)
  181. {
  182. *szDst++ = *szSrc++;
  183. }
  184. *szDst = '\0';
  185. return const_cast<TCHAR *>(szSrc);
  186. } // Str_PchCopyChN()
  187. /////////////////////////////////////////////////////////////////////
  188. // Str_SubstituteStrStr()
  189. //
  190. // Scan the source string and replace every occurrence of a
  191. // sub-string by another sub-string. This routine may
  192. // be used to count the number of sub-strings in the
  193. // source string.
  194. //
  195. // RETURNS
  196. // Return the number of subsitutions performed.
  197. //
  198. // INTERFACE NOTES
  199. // The source and destination buffer may overlap as long
  200. // as the length of the token to replace is shorter than
  201. // the token to search.
  202. //
  203. INT
  204. Str_SubstituteStrStr(
  205. TCHAR * szDst, // OUT: Destination buffer
  206. CONST TCHAR * szSrc, // IN: Source buffer
  207. CONST TCHAR * szToken, // IN: Token to find
  208. CONST TCHAR * szReplace) // IN: Token to replace
  209. {
  210. INT cSubtitutions = 0;
  211. Assert(szDst != NULL);
  212. Assert(szSrc != NULL);
  213. Assert(szToken != NULL);
  214. Assert(szReplace != NULL);
  215. Endorse(szDst == szSrc);
  216. while (*szSrc != '\0')
  217. {
  218. if (*szSrc == *szToken)
  219. {
  220. // Check if we match the token
  221. CONST TCHAR * pchSrc = szSrc;
  222. CONST TCHAR * pchToken = szToken;
  223. while (*pchToken != '\0')
  224. {
  225. if (*pchSrc++ != *pchToken++)
  226. goto TokenNotMatch;
  227. }
  228. cSubtitutions++;
  229. szSrc = pchSrc;
  230. pchSrc = szReplace;
  231. while (*pchSrc != '\0')
  232. *szDst++ = *pchSrc++;
  233. continue;
  234. TokenNotMatch:
  235. ;
  236. } // if
  237. *szDst++ = *szSrc++;
  238. } // while
  239. *szDst = '\0';
  240. return cSubtitutions;
  241. } // Str_SubstituteStrStr()
  242. /////////////////////////////////////////////////////////////////////
  243. // PchParseCommandLine()
  244. //
  245. // Split a command line into its path to its executable binary and
  246. // its command line arguments. The path to the executable is
  247. // copied into the output buffer.
  248. //
  249. // RETURNS
  250. // Pointer to the next character after path to the executable (Pointer
  251. // may point to an empty string). If an error occurs, return NULL.
  252. //
  253. // FORMATS SUPPORTED
  254. // 1. "c:\\winnt\\foo.exe /bar"
  255. // 2. ""c:\\winnt\\foo.exe" /bar"
  256. // The double quotes around the binary path allow
  257. // the binary path to have spaces.
  258. //
  259. TCHAR *
  260. PchParseCommandLine(
  261. CONST TCHAR szFullCommand[], // IN: Full command line
  262. TCHAR szBinPath[], // OUT: Path of the executable binary
  263. INT cchBinPathBuf) // IN: Size of the buffer
  264. {
  265. UNREFERENCED_PARAMETER (cchBinPathBuf);
  266. CONST TCHAR * pchSrc = szFullCommand;
  267. TCHAR * pchDst = szBinPath;
  268. BOOL fQuotesFound = FALSE; // TRUE => The binary path is surrounded by quotes (")
  269. Assert(szFullCommand != NULL);
  270. Assert(szBinPath != NULL);
  271. // Skip leading spaces
  272. while (*pchSrc == _T(' '))
  273. pchSrc++;
  274. if (*pchSrc == _T('\"'))
  275. {
  276. fQuotesFound = TRUE;
  277. pchSrc++;
  278. }
  279. while (TRUE)
  280. {
  281. *pchDst = *pchSrc;
  282. if (*pchSrc == _T('\0'))
  283. break;
  284. if (*pchSrc == _T('\"') && fQuotesFound)
  285. {
  286. pchSrc++;
  287. break;
  288. }
  289. if (*pchSrc == _T(' ') && !fQuotesFound)
  290. {
  291. pchSrc++;
  292. break;
  293. }
  294. pchSrc++;
  295. pchDst++;
  296. }
  297. Assert(pchDst - szBinPath < cchBinPathBuf);
  298. *pchDst = _T('\0');
  299. return const_cast<TCHAR *>(pchSrc); // Return character where arguments starts
  300. } // PchParseCommandLine()
  301. /////////////////////////////////////////////////////////////////////
  302. void TrimString(CString& rString)
  303. {
  304. rString.TrimLeft();
  305. rString.TrimRight();
  306. }
  307. /////////////////////////////////////////////////////////////////////
  308. // PargzpszFromPgrsz()
  309. //
  310. // Parse a group of strings into an array of pointers to strings.
  311. // This routine is somewhat similar to CommandLineToArgvW() but
  312. // uses a group of strings instead of a normal string.
  313. //
  314. // RETURN
  315. // Return a pointer to an allocated array of pointers to strings.
  316. // The array of pointers allocated with the new() operator,
  317. // therefore the caller must call ONCE delete() to free memory.
  318. //
  319. // BACKGROUND
  320. // You need to 'understand' hungarian prefixes to appreciate the
  321. // name of the function.
  322. //
  323. // p Pointer to something
  324. // psz Pointer to string terminated.
  325. // pa Pointer dynamically allocated. For instance, pasz is
  326. // a pointer to an allocated string. The allocation is
  327. // to remind the developper he/she have to free the memory
  328. // when done with the variable.
  329. // rg Array (range). Array (rg) is similar to pointer (p)
  330. // but may point to more than one element.
  331. // rgch is an array of characters while pch points to
  332. // a single character.
  333. // rgz Array of which the last element is zero. The 'last element'
  334. // may be a character, an integer, a pointer or any other
  335. // data type found in the array.
  336. // For instance rgzch would be an array of characters having
  337. // its last character zero -- a string (sz).
  338. // gr Group. This is different than array because indexing
  339. // cannot be used. For instance, a group of strings is
  340. // not the same as an array of strings.
  341. // char grsz[] = "DOS\0WfW\0Win95\0WinNT\0";
  342. // char * rgpsz[] = { "DOS", "WfW", "Win95", "WinNT" };
  343. // char * rgzpsz[] = { "DOS", "WfW", "Win95", "WinNT", NULL };
  344. //
  345. // Now it is time to put all the pieces together.
  346. // pargzpsz = "pa" + "rgz" + "psz"
  347. // pgrsz = "p" + "gr" + "sz"
  348. //
  349. // USAGE
  350. // LPTSTR * pargzpsz;
  351. // pargzpsz = PargzpszFromPgrsz("DOS\0WfW\0Win95\0WinNT\0", OUT &cStringCount);
  352. // delete pargzpsz; // Single delete to free memory
  353. //
  354. LPTSTR *
  355. PargzpszFromPgrsz(
  356. CONST LPCTSTR pgrsz, // IN: Pointer to group of strings
  357. INT * pcStringCount) // OUT: OPTIONAL: Count of strings in the stored into returned value
  358. {
  359. Assert(pgrsz != NULL);
  360. Endorse(pcStringCount == NULL);
  361. // Compute how much memory is needed for allocation
  362. CONST TCHAR * pchSrc = pgrsz;
  363. INT cStringCount = 0;
  364. INT cch = sizeof(TCHAR *);
  365. while (*pchSrc != _T('\0'))
  366. {
  367. cStringCount++;
  368. for ( ; *pchSrc != _T('\0'); pchSrc++)
  369. cch++;
  370. cch = sizeof(TCHAR *) + ((cch + 4) & ~3); // Align to next DWORD
  371. pchSrc++;
  372. } // while
  373. // Allocate a single block of memory for all the data
  374. LPTSTR * pargzpsz = (LPTSTR *)new TCHAR[cch];
  375. Assert(pargzpsz != NULL);
  376. TCHAR * pchDst = (TCHAR *)&pargzpsz[cStringCount+1];
  377. pchSrc = pgrsz;
  378. for (INT iString = 0; iString < cStringCount; iString++)
  379. {
  380. pargzpsz[iString] = pchDst;
  381. // Copy string
  382. while (*pchSrc != '\0')
  383. {
  384. *pchDst++ = *pchSrc++;
  385. }
  386. *pchDst++ = *pchSrc++; // Copy null-terminator
  387. pchDst = (TCHAR *)(((INT_PTR)pchDst + 3) & ~3); // Align pointer to next DWORD
  388. } // for
  389. pargzpsz[cStringCount] = NULL;
  390. if (pcStringCount != NULL)
  391. *pcStringCount = cStringCount;
  392. return pargzpsz;
  393. } // PargzpszFromPgrsz()
  394. /////////////////////////////////////////////////////////////////////
  395. void
  396. ListView_AddColumnHeaders(
  397. HWND hwndListview, // IN: Handle of the listview we want to add columns
  398. const TColumnHeaderItem rgzColumnHeader[]) // IN: Array of column header items
  399. {
  400. RECT rcClient;
  401. INT cxTotalWidth; // Total width of the listview control
  402. LV_COLUMN lvColumn;
  403. INT cxColumn; // Width of the individual column
  404. TCHAR szBuffer[1024];
  405. Assert(IsWindow(hwndListview));
  406. Assert(rgzColumnHeader != NULL);
  407. GetClientRect(hwndListview, OUT &rcClient);
  408. cxTotalWidth = rcClient.right;
  409. lvColumn.pszText = szBuffer;
  410. for (INT i = 0; rgzColumnHeader[i].uStringId != 0; i++)
  411. {
  412. if (!::LoadString(g_hInstanceSave, rgzColumnHeader[i].uStringId,
  413. OUT szBuffer, LENGTH(szBuffer)))
  414. {
  415. TRACE1("Unable to load string Id=%d\n", rgzColumnHeader[i].uStringId);
  416. Assert(FALSE);
  417. continue;
  418. }
  419. lvColumn.mask = LVCF_TEXT;
  420. cxColumn = rgzColumnHeader[i].nColWidth;
  421. if (cxColumn > 0)
  422. {
  423. Assert(cxColumn <= 100);
  424. cxColumn = (cxTotalWidth * cxColumn) / 100;
  425. lvColumn.mask |= LVCF_WIDTH;
  426. lvColumn.cx = cxColumn;
  427. }
  428. INT iColRet = ListView_InsertColumn(hwndListview, i, IN &lvColumn);
  429. Report(iColRet == i);
  430. } // for
  431. } // ListView_AddColumnHeaders()
  432. /////////////////////////////////////////////////////////////////////
  433. int
  434. ListView_InsertItemEx(
  435. HWND hwndListview, // IN: Handle of the listview we want to add item
  436. CONST LV_ITEM * pLvItem) // IN: Pointer to listview item
  437. {
  438. LV_ITEM lvItemT; // Temporary variable
  439. TCHAR szT[1024]; // Temporary buffer
  440. TCHAR * pch;
  441. INT iItem; // Index of the item
  442. Assert(IsWindow(hwndListview));
  443. Assert(pLvItem != NULL);
  444. lvItemT = *pLvItem; // Copy the whole structure
  445. lvItemT.iSubItem = 0;
  446. lvItemT.pszText = szT;
  447. // Copy until the next
  448. pch = Str_PchCopyChN(OUT szT, pLvItem->pszText, '\t', LENGTH(szT));
  449. Assert(pch != NULL);
  450. iItem = ListView_InsertItem(hwndListview, IN &lvItemT);
  451. Report(iItem >= 0);
  452. if (*pch == '\0')
  453. return iItem;
  454. Assert(*pch == '\t');
  455. lvItemT.mask = LVIF_TEXT;
  456. lvItemT.iItem = iItem;
  457. lvItemT.iSubItem = 1;
  458. while (*pch != '\0')
  459. {
  460. pch = Str_PchCopyChN(OUT szT, pch + 1, '\t', LENGTH(szT));
  461. BOOL fRet = ListView_SetItem(hwndListview, IN &lvItemT);
  462. Report(fRet != FALSE);
  463. lvItemT.iSubItem++;
  464. break;
  465. }
  466. return iItem;
  467. } // ListView_InsertItemEx()
  468. /////////////////////////////////////////////////////////////////////
  469. // Display the common dialog to get a filename.
  470. BOOL
  471. UiGetFileName(
  472. HWND hwnd,
  473. TCHAR szFileName[], // OUT: Filename we want to get
  474. INT cchBufferLength) // IN: Length of szFileName buffer
  475. {
  476. OPENFILENAME ofn;
  477. Assert(szFileName != NULL);
  478. Assert(cchBufferLength > 10); // At least 10 characters
  479. TCHAR szBufferT[2048];
  480. ::ZeroMemory( szBufferT, sizeof(szBufferT) );
  481. VERIFY(::LoadString(g_hInstanceSave, IDS_OPENFILE_FILTER, szBufferT, LENGTH(szBufferT)));
  482. ::ZeroMemory(OUT &ofn, sizeof(ofn));
  483. ofn.lStructSize = sizeof(OPENFILENAME);
  484. ofn.hwndOwner = hwnd;
  485. ofn.hInstance = g_hInstanceSave;
  486. ofn.lpstrFilter = szBufferT;
  487. ofn.nFilterIndex = 1;
  488. ofn.lpstrFile = szFileName;
  489. ofn.nMaxFile = cchBufferLength;
  490. ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
  491. return GetOpenFileName(&ofn);
  492. } // UiGetFileName()
  493. /////////////////////////////////////////////////////////////////////
  494. // PaszLoadStringPrintf()
  495. //
  496. // Load a string from the resource, and format it and return
  497. // pointer allocated string.
  498. //
  499. // RETURNS
  500. // Pointer to allocated string. Must call LocalFree() when
  501. // done with string.
  502. //
  503. // INTERFACE NOTES
  504. // The format of the resource string uses %1 throuth %99 and
  505. // assumes the arguments are pointers to strings.
  506. //
  507. // If you have an argument other than a string, you can append a
  508. // printf-type within two exclamation marks.
  509. // !s! Insert a string (default)
  510. // !d! Insert a decimal integer
  511. // !u! Insert an unsigned integer
  512. // !x! Insert an hexadecimal integer
  513. //
  514. // HOW TO AVOID BUGS
  515. // To avoid bugs using this routine, I strongly suggest to include
  516. // the format of the string as part of the name of the string Id.
  517. // If you change the format of the string, you should rename
  518. // the string Id to reflect the new format. This will guarantee
  519. // the correct type and number of arguments are used.
  520. //
  521. // EXAMPLES
  522. // IDS_s_PROPERTIES = "%1 Properties"
  523. // IDS_ss_PROPERTIES = "%1 Properties on %2"
  524. // IDS_sus_SERVICE_ERROR = "Service %1 encountered error %2!u! while connecting to %3"
  525. //
  526. // HISTORY
  527. // 96.10.30 t-danmo Creation
  528. //
  529. TCHAR *
  530. PaszLoadStringPrintf(
  531. UINT wIdString, // IN: String Id
  532. va_list arglist) // IN: Arguments (if any)
  533. {
  534. Assert(wIdString != 0);
  535. TCHAR szBufferT[2048];
  536. LPTSTR paszBuffer = NULL; // Pointer to allocated buffer. Caller must call LocalFree() to free it
  537. // Load the string from the resource
  538. VERIFY(::LoadString(g_hInstanceSave, wIdString, szBufferT, LENGTH(szBufferT)));
  539. // Format the string
  540. ::FormatMessage(
  541. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  542. szBufferT,
  543. 0,
  544. 0,
  545. OUT (LPTSTR)&paszBuffer, // Buffer will be allocated by FormatMessage()
  546. 0,
  547. &arglist);
  548. #ifdef DEBUG
  549. if (paszBuffer == NULL)
  550. {
  551. DWORD dw = GetLastError();
  552. Report(FALSE && "FormatMessage() failed.");
  553. }
  554. #endif
  555. return paszBuffer;
  556. } // PaszLoadStringPrintf()
  557. /////////////////////////////////////////////////////////////////////
  558. // LoadStringPrintf()
  559. //
  560. // Load a string from the resources, format it and copy the result string
  561. // into the CString object.
  562. //
  563. // Can also use LoadStringWithInsertions()
  564. // AFX_MANAGE_STATE(AfxGetStaticModuleState())
  565. //
  566. // EXAMPLES
  567. // LoadStrigPrintf(IDS_s_PROPERTIES, OUT &strCaption, szServiceName);
  568. // LoadStrigPrintf(IDS_ss_PROPERTIES, OUT &strCaption, szServiceName, szMachineName);
  569. // LoadStrigPrintf(IDS_sus_SERVICE_ERROR, OUT &strMessage, szServiceName, ::GetLastError(), szMachineName);
  570. //
  571. void
  572. LoadStringPrintf(
  573. UINT wIdString, // IN: String Id
  574. CString * pString, // OUT: String to receive the characters
  575. ...) // IN: Optional arguments
  576. {
  577. Assert(wIdString != NULL);
  578. Assert(pString != NULL);
  579. va_list arglist;
  580. va_start(arglist, pString);
  581. TCHAR * paszBuffer = PaszLoadStringPrintf(wIdString, arglist);
  582. *pString = paszBuffer; // Copy the string into the CString object
  583. LocalFree(paszBuffer);
  584. }
  585. /////////////////////////////////////////////////////////////////////
  586. // SetWindowTextPrintf()
  587. //
  588. // Load a string from the resource, format it and set the window text.
  589. //
  590. // EXAMPLE
  591. // SetWindowText(hwndStatic, IDS_s_PROPERTIES, szObjectName);
  592. //
  593. // HISTORY
  594. // 96.10.30 t-danmo Creation. Core copied from LoadStringPrintf()
  595. //
  596. void
  597. SetWindowTextPrintf(HWND hwnd, UINT wIdString, ...)
  598. {
  599. ASSERT(IsWindow(hwnd));
  600. ASSERT(wIdString != 0);
  601. va_list arglist;
  602. va_start(arglist, wIdString);
  603. TCHAR * paszBuffer = PaszLoadStringPrintf(wIdString, arglist);
  604. if (NULL != paszBuffer) // JonN 5/30/00 PREFIX 110941
  605. SetWindowText(hwnd, paszBuffer); // Set the text of the window
  606. LocalFree(paszBuffer);
  607. } // SetWindowTextPrintf()
  608. #ifdef SNAPIN_PROTOTYPER
  609. const TCHAR rgchHexDigits[] = _T("00112233445566778899aAbBcCdDeEfF");
  610. const TCHAR szSpcTab[] = _T(" \t");
  611. const TCHAR szWhiteSpaces[] = _T(" \t\n\r\f\v");
  612. const TCHAR szDecimalDigits[] = _T("0123456789");
  613. #ifdef UNICODE
  614. #define strchrT wcschr
  615. #else
  616. #define strchrT strchr
  617. #endif
  618. /////////////////////////////////////////////////////////////////////
  619. // FParseInteger()
  620. //
  621. // Parse the source string pchSrc and extract
  622. // its integer value.
  623. //
  624. // RETURNS
  625. // Return TRUE if successful and set uData to integer value
  626. // of the parsed string.
  627. // If not successful (ie, illegal digit or overflow), return FALSE,
  628. // set uData to zero and set nErrCode to error found.
  629. // Field pi.pchStop is always set to the last valid character
  630. // parsed.
  631. //
  632. // INTERFACE NOTES
  633. // Fields pPI->pchSrc and pPI->nFlags are preserved during
  634. // the execution of FParseInteger().
  635. //
  636. BOOL
  637. FParseInteger(INOUT TParseIntegerInfo * pPI)
  638. {
  639. UINT uDataT;
  640. UINT uBase;
  641. UINT iDigit;
  642. UINT cDigitParsed; // Number of digits parsed
  643. BOOL fIsNegative = FALSE;
  644. const TCHAR * pchDigit;
  645. Assert(pPI != NULL);
  646. Assert(pPI->pchSrc != NULL);
  647. pPI->pchStop = pPI->pchSrc;
  648. pPI->nErrCode = PI_errOK; // No error yet
  649. pPI->uData = 0;
  650. uBase = (pPI->nFlags & PI_mskfHexBaseOnly) ? 16 : 10;
  651. cDigitParsed = 0;
  652. // Skip leading blanks
  653. while (*pPI->pchStop ==_T(' '))
  654. pPI->pchStop++;
  655. // Check for a minus sign
  656. if (*pPI->pchStop == _T('-'))
  657. {
  658. if (pPI->nFlags & PI_mskfNoMinusSign)
  659. {
  660. pPI->nErrCode = PI_errMinusSignFound;
  661. return FALSE;
  662. }
  663. fIsNegative = TRUE;
  664. pPI->pchStop++;
  665. }
  666. // Skip leading zeroes
  667. while (*pPI->pchStop == _T('0'))
  668. {
  669. pPI->pchStop++;
  670. cDigitParsed++;
  671. }
  672. // Look for the hexadecimal prefix (0x or 0X)
  673. if (*pPI->pchStop == _T('x') || *pPI->pchStop == _T('X'))
  674. {
  675. if ((pPI->nFlags & PI_mskfAllowHexBase) == 0)
  676. {
  677. pPI->nErrCode = PI_errInvalidInteger;
  678. return FALSE;
  679. }
  680. pPI->pchStop++;
  681. cDigitParsed = 0;
  682. uBase = 16;
  683. } // if
  684. while (*pPI->pchStop != _T('\0'))
  685. {
  686. pchDigit = wcschr(rgchHexDigits, *pPI->pchStop);
  687. if (pchDigit == NULL)
  688. {
  689. if (pPI->nFlags & PI_mskfAllowRandomTail)
  690. break;
  691. // Digit not found while random tail not allowed
  692. pPI->nErrCode = PI_errInvalidInteger;
  693. return FALSE;
  694. } // if
  695. Assert(pchDigit >= rgchHexDigits);
  696. iDigit = (pchDigit - rgchHexDigits) >> 1;
  697. Assert(iDigit <= 0x0F);
  698. if (iDigit >= uBase)
  699. {
  700. // Hex digit found while parsing a decimal string
  701. pPI->nErrCode = PI_errInvalidInteger;
  702. return FALSE;
  703. }
  704. cDigitParsed++;
  705. uDataT = pPI->uData * uBase + iDigit;
  706. if (pPI->uData > ((UINT)-1)/10 || uDataT < pPI->uData)
  707. {
  708. pPI->nErrCode = PI_errIntegerOverflow;
  709. return FALSE;
  710. }
  711. pPI->uData = uDataT;
  712. pPI->pchStop++;
  713. } // while
  714. if ((cDigitParsed == 0) && (pPI->nFlags & PI_mskfNoEmptyString))
  715. {
  716. // Empty String found while not allowed
  717. Assert(pPI->uData == 0);
  718. pPI->nErrCode = PI_errEmptyString;
  719. return FALSE;
  720. }
  721. if (fIsNegative)
  722. {
  723. pPI->uData = -(int)pPI->uData;
  724. }
  725. if (pPI->nFlags & PI_mskfSingleEntry)
  726. {
  727. // Check if there are no more digits at the end of the string
  728. // Only spaces are allowed
  729. while (*pPI->pchStop == _T(' '))
  730. pPI->pchStop++;
  731. if (*pPI->pchStop != _T('\0'))
  732. {
  733. pPI->nErrCode = PI_errInvalidInteger;
  734. return FALSE;
  735. }
  736. }
  737. return TRUE;
  738. } // FParseInteger()
  739. /////////////////////////////////////////////////////////////////////
  740. // FScanf()
  741. //
  742. // Parse a formatted string and extract the values.
  743. // FScanf() behaves like the well known scanf() function but
  744. // has range checking and pattern matching. The wildcard (*)
  745. // may be substituded by "%s" with a NULL pointer.
  746. //
  747. // Return TRUE if successful, otherwise return FALSE
  748. // and set nErrCode to the error found.
  749. //
  750. // Formats supported:
  751. // %d Extract a decimal integer
  752. // %i Extract a generic integer (decimal or hexadecimal)
  753. // %u Extract an unsigned decimal integer (return error if minus sign found)
  754. // %x Force extraction of an hexadecimal integer
  755. // %s Extract a string
  756. // %v Void the spaces and tabs characters
  757. //
  758. // Note:
  759. // Fields sfi.pchSrc and sfi.nFlags are preserved during
  760. // the execution of FScanf().
  761. //
  762. // Example:
  763. // FScanf(&sfi, "%v%s.%s", " \t foobar.txt",
  764. // OUT szName, LENGTH(szName), OUT szExt, LENGTH(szExt));
  765. //
  766. BOOL FScanf(
  767. SCANF_INFO * pSFI, // INOUT: Control structure
  768. const TCHAR * pchFmt, // IN: Format template string
  769. ...) // OUT: scanf() arguments
  770. {
  771. va_list arglist;
  772. TParseIntegerInfo pi;
  773. Assert(pSFI != 0);
  774. Assert(pchFmt != NULL);
  775. Assert(pSFI->pchSrc != NULL);
  776. va_start(INOUT arglist, pchFmt);
  777. pSFI->pchSrcStop = pSFI->pchSrc;
  778. pSFI->nErrCode = SF_errOK;
  779. pSFI->cArgParsed = 0;
  780. while (TRUE)
  781. {
  782. switch (*pchFmt++)
  783. {
  784. case 0: // End of string
  785. return TRUE;
  786. case '%':
  787. switch (*pchFmt++)
  788. {
  789. case '%': // "%%"
  790. if (*pSFI->pchSrcStop++ != '%')
  791. {
  792. pSFI->pchSrcStop--;
  793. pSFI->nErrCode = SF_errTemplateMismatch;
  794. return FALSE;
  795. }
  796. break;
  797. case 'v':
  798. while (*pSFI->pchSrcStop == ' ' || *pSFI->pchSrcStop == '\t')
  799. pSFI->pchSrcStop++;
  800. break;
  801. case 'V':
  802. while ((*pSFI->pchSrcStop != '\0') &&
  803. (strchrT(szWhiteSpaces, *pSFI->pchSrcStop) != NULL))
  804. pSFI->pchSrcStop++;
  805. break;
  806. case 'd': // "%d" Decimal integer (signed | unsigned)
  807. case 'u': // "%u" Decimal unsigned integer
  808. case 'i': // "%i" Generic integer (decimal | hexadecimal / signed | unsigned)
  809. case 'x': // "%x" Hexadecimal integer
  810. {
  811. int * p;
  812. pi.nFlags = PI_mskfNoEmptyString | PI_mskfAllowRandomTail;
  813. switch (*(pchFmt-1))
  814. {
  815. case 'u':
  816. pi.nFlags |= PI_mskfNoMinusSign;
  817. break;
  818. case 'i':
  819. pi.nFlags |= PI_mskfAllowHexBase;
  820. break;
  821. case 'x':
  822. pi.nFlags |= PI_mskfHexBaseOnly | PI_mskfNoMinusSign;
  823. } // switch
  824. pi.pchSrc = pSFI->pchSrcStop;
  825. if (!FParseInteger(INOUT &pi))
  826. {
  827. pSFI->pchSrcStop = pi.pchStop;
  828. return FALSE;
  829. } // if
  830. pSFI->pchSrcStop = pi.pchStop;
  831. pSFI->cArgParsed++;
  832. p = (int *)va_arg(arglist, int *);
  833. Assert(p != NULL);
  834. *p = pi.uData;
  835. }
  836. break; // Integer
  837. case 's': // "%s" String
  838. {
  839. // To get a clean string, use the format "%v%s%v"
  840. // which will strip all the spaces and tabs around
  841. // the string.
  842. TCHAR * pchDest; // Destination buffer
  843. int cchDestMax; // Size of destination buffer
  844. TCHAR chEndScan;
  845. const TCHAR * pchEndScan = NULL;
  846. // Find out the ending character(s)
  847. if (*pchFmt == '%')
  848. {
  849. switch (*(pchFmt+1))
  850. {
  851. case 'd':
  852. case 'u':
  853. case 'i':
  854. pchEndScan = szDecimalDigits;
  855. chEndScan = '\0';
  856. break;
  857. case 'v': // %v
  858. pchEndScan = szSpcTab;
  859. chEndScan = *(pchFmt+2);
  860. break;
  861. case 'V': // %V
  862. pchEndScan = szWhiteSpaces;
  863. chEndScan = *(pchFmt+2);
  864. break;
  865. case '%': // %%
  866. chEndScan = '%';
  867. default:
  868. Assert(FALSE); // Ambiguous compound format (not supported anyway!)
  869. } // switch
  870. }
  871. else
  872. {
  873. chEndScan = *pchFmt;
  874. } // if...else
  875. pSFI->cArgParsed++;
  876. pchDest = (TCHAR *)va_arg(arglist, TCHAR *);
  877. if (pchDest != NULL)
  878. {
  879. cchDestMax = va_arg(arglist, int) - 1;
  880. // Verify if the size of destination buffer
  881. // is a valid size.
  882. // Otherwise, this may be the address of the
  883. // next argument
  884. Assert(cchDestMax > 0 && cchDestMax < 5000);
  885. while (cchDestMax-- > 0)
  886. {
  887. if (*pSFI->pchSrcStop == chEndScan)
  888. break;
  889. else if (*pSFI->pchSrcStop == '\0')
  890. break;
  891. else if (pchEndScan != NULL)
  892. {
  893. if (strchrT(pchEndScan, *pSFI->pchSrcStop))
  894. break;
  895. } // if...else
  896. // Copy the character into destination buffer
  897. *pchDest++ = *pSFI->pchSrcStop++;
  898. }
  899. *pchDest = '\0';
  900. } // if
  901. // Skip the characters until reaching either end character
  902. while (TRUE)
  903. {
  904. if (*pSFI->pchSrcStop == chEndScan)
  905. break;
  906. else if (*pSFI->pchSrcStop == '\0')
  907. break;
  908. else if (pchEndScan != NULL)
  909. {
  910. if (strchrT(pchEndScan, *pSFI->pchSrcStop))
  911. break;
  912. } // if...else
  913. pSFI->pchSrcStop++;
  914. } // while
  915. }
  916. break; // "%s"
  917. default:
  918. // Unknown "%?" format
  919. Assert(FALSE);
  920. pSFI->pchSrcStop--;
  921. } // switch
  922. break; // case '%'
  923. default:
  924. if (*(pchFmt-1) != *pSFI->pchSrcStop++)
  925. {
  926. pSFI->pchSrcStop--;
  927. pSFI->nErrCode = SF_errTemplateMismatch;
  928. return FALSE;
  929. }
  930. } // switch
  931. } // while
  932. return TRUE;
  933. } // FScanf()
  934. /////////////////////////////////////////////////////////////////////
  935. // Query the a registry key of type REG_SZ without trowing an exception.
  936. //
  937. BOOL
  938. RegKey_FQueryString(
  939. HKEY hKey,
  940. LPCTSTR pszValueName, // IN: Name of the key
  941. CString& rstrKeyData) // OUT: Value (data) of registry key
  942. {
  943. Assert(hKey != NULL);
  944. Assert(pszValueName != NULL);
  945. TCHAR szBufferT[4096];
  946. DWORD cbBufferLength = sizeof(szBufferT);
  947. DWORD dwType;
  948. DWORD dwErr;
  949. dwErr = ::RegQueryValueEx(
  950. hKey,
  951. pszValueName,
  952. 0,
  953. OUT &dwType,
  954. OUT (BYTE *)szBufferT,
  955. INOUT &cbBufferLength);
  956. if ((dwErr == ERROR_SUCCESS) && (dwType == REG_SZ))
  957. {
  958. rstrKeyData = szBufferT; // Copy the string
  959. return TRUE;
  960. }
  961. else
  962. {
  963. rstrKeyData.Empty();
  964. return FALSE;
  965. }
  966. } // RegKey_FQueryString()
  967. #endif // SNAPIN_PROTOTYPER
  968. DWORD DisplayNameHelper(
  969. HWND hwndParent,
  970. BSTR pszMachineName,
  971. BSTR pszServiceName,
  972. DWORD dwDesiredAccess,
  973. SC_HANDLE* phSC,
  974. BSTR* pbstrServiceDisplayName)
  975. {
  976. *phSC = ::OpenSCManager(
  977. pszMachineName,
  978. NULL,
  979. SC_MANAGER_CONNECT);
  980. if (NULL == *phSC)
  981. {
  982. DWORD dwErr = ::GetLastError();
  983. ASSERT( NO_ERROR != dwErr );
  984. return dwErr;
  985. }
  986. SC_HANDLE hService = ::OpenService(
  987. *phSC,
  988. pszServiceName,
  989. dwDesiredAccess | SERVICE_QUERY_CONFIG);
  990. if (NULL == hService)
  991. {
  992. DWORD dwErr = ::GetLastError();
  993. ASSERT( NO_ERROR != dwErr );
  994. ::CloseServiceHandle(*phSC);
  995. *phSC = NULL;
  996. return dwErr;
  997. }
  998. union
  999. {
  1000. // Service config
  1001. QUERY_SERVICE_CONFIG qsc;
  1002. BYTE rgbBufferQsc[SERVICE_cbQueryServiceConfigMax];
  1003. };
  1004. ::ZeroMemory(&qsc, max(sizeof(qsc), sizeof(rgbBufferQsc)));
  1005. DWORD cbBytesNeeded = 0;
  1006. if (!::QueryServiceConfigW(
  1007. hService,
  1008. OUT &qsc,
  1009. max(sizeof(qsc), sizeof(rgbBufferQsc)),
  1010. OUT &cbBytesNeeded))
  1011. {
  1012. DWORD dwErr = ::GetLastError();
  1013. ASSERT( NO_ERROR != dwErr );
  1014. ::CloseServiceHandle(hService);
  1015. ::CloseServiceHandle(*phSC);
  1016. *phSC = NULL;
  1017. return dwErr;
  1018. }
  1019. *pbstrServiceDisplayName = ::SysAllocString(
  1020. (qsc.lpDisplayName && qsc.lpDisplayName[0])
  1021. ? qsc.lpDisplayName
  1022. : pszServiceName);
  1023. if (NULL == *pbstrServiceDisplayName)
  1024. {
  1025. ::CloseServiceHandle(hService);
  1026. ::CloseServiceHandle(*phSC);
  1027. *phSC = NULL;
  1028. return E_OUTOFMEMORY;
  1029. }
  1030. ::CloseServiceHandle(hService);
  1031. return NO_ERROR;
  1032. }
  1033. HRESULT CStartStopHelper::StartServiceHelper(
  1034. HWND hwndParent,
  1035. BSTR pszMachineName,
  1036. BSTR pszServiceName,
  1037. DWORD dwNumServiceArgs,
  1038. BSTR * lpServiceArgVectors)
  1039. {
  1040. MFC_TRY;
  1041. if ( ( (NULL != pszMachineName)
  1042. && ::IsBadStringPtr(pszMachineName,0x7FFFFFFF))
  1043. || ::IsBadStringPtr(pszServiceName,0x7FFFFFFF))
  1044. {
  1045. ASSERT(FALSE);
  1046. return E_POINTER;
  1047. }
  1048. if (0 < dwNumServiceArgs)
  1049. {
  1050. if (::IsBadReadPtr(lpServiceArgVectors,sizeof(lpServiceArgVectors)))
  1051. {
  1052. ASSERT(FALSE);
  1053. return E_POINTER;
  1054. }
  1055. for (DWORD i = 0; i < dwNumServiceArgs; i++)
  1056. {
  1057. if ( (NULL != lpServiceArgVectors[i])
  1058. && ::IsBadStringPtr(lpServiceArgVectors[i],0x7FFFFFFF))
  1059. {
  1060. ASSERT(FALSE);
  1061. return E_POINTER;
  1062. }
  1063. }
  1064. }
  1065. SC_HANDLE hScManager = NULL;
  1066. CComBSTR sbstrServiceDisplayName;
  1067. DWORD dwErr = DisplayNameHelper(
  1068. hwndParent,
  1069. pszMachineName,
  1070. pszServiceName,
  1071. SERVICE_START,
  1072. &hScManager,
  1073. &sbstrServiceDisplayName);
  1074. if (NO_ERROR != dwErr)
  1075. {
  1076. (void) DoServicesErrMsgBox(
  1077. hwndParent,
  1078. MB_OK | MB_ICONSTOP,
  1079. dwErr,
  1080. IDS_MSG_sss_UNABLE_TO_START_SERVICE,
  1081. pszServiceName,
  1082. (pszMachineName && pszMachineName[0])
  1083. ? pszMachineName : (LPCTSTR)g_strLocalMachine,
  1084. L"");
  1085. }
  1086. else
  1087. {
  1088. dwErr = CServiceControlProgress::S_EStartService(
  1089. hwndParent,
  1090. hScManager,
  1091. pszMachineName,
  1092. pszServiceName,
  1093. sbstrServiceDisplayName,
  1094. dwNumServiceArgs,
  1095. (LPCTSTR *)lpServiceArgVectors);
  1096. }
  1097. if (NULL != hScManager)
  1098. (void) ::CloseServiceHandle( hScManager );
  1099. switch (dwErr)
  1100. {
  1101. case CServiceControlProgress::errUserCancelStopDependentServices:
  1102. case CServiceControlProgress::errCannotInitialize:
  1103. case CServiceControlProgress::errUserAbort:
  1104. return S_FALSE;
  1105. default:
  1106. break;
  1107. }
  1108. return HRESULT_FROM_WIN32(dwErr);
  1109. MFC_CATCH;
  1110. }
  1111. HRESULT CStartStopHelper::ControlServiceHelper(
  1112. HWND hwndParent,
  1113. BSTR pszMachineName,
  1114. BSTR pszServiceName,
  1115. DWORD dwControlCode)
  1116. {
  1117. MFC_TRY;
  1118. if ( ( (NULL != pszMachineName)
  1119. && ::IsBadStringPtr(pszMachineName,0x7FFFFFFF))
  1120. || ::IsBadStringPtr(pszServiceName,0x7FFFFFFF))
  1121. {
  1122. ASSERT(FALSE);
  1123. return E_POINTER;
  1124. }
  1125. SC_HANDLE hScManager = NULL;
  1126. CComBSTR sbstrServiceDisplayName;
  1127. DWORD dwDesiredAccess = SERVICE_USER_DEFINED_CONTROL;
  1128. UINT idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_STOP_SERVICE; // CODEWORK
  1129. switch (dwControlCode)
  1130. {
  1131. case SERVICE_CONTROL_STOP:
  1132. idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_STOP_SERVICE;
  1133. dwDesiredAccess = SERVICE_STOP;
  1134. break;
  1135. case SERVICE_CONTROL_PAUSE:
  1136. idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_PAUSE_SERVICE;
  1137. dwDesiredAccess = SERVICE_PAUSE_CONTINUE;
  1138. break;
  1139. case SERVICE_CONTROL_CONTINUE:
  1140. idErrorMessageTemplate = IDS_MSG_sss_UNABLE_TO_RESUME_SERVICE;
  1141. dwDesiredAccess = SERVICE_PAUSE_CONTINUE;
  1142. break;
  1143. default:
  1144. break;
  1145. }
  1146. DWORD dwErr = DisplayNameHelper(
  1147. hwndParent,
  1148. pszMachineName,
  1149. pszServiceName,
  1150. dwDesiredAccess,
  1151. &hScManager,
  1152. &sbstrServiceDisplayName);
  1153. if (NO_ERROR != dwErr)
  1154. {
  1155. (void) DoServicesErrMsgBox(
  1156. hwndParent,
  1157. MB_OK | MB_ICONSTOP,
  1158. dwErr,
  1159. idErrorMessageTemplate,
  1160. pszServiceName,
  1161. (pszMachineName && pszMachineName[0])
  1162. ? pszMachineName : (LPCTSTR)g_strLocalMachine,
  1163. L"");
  1164. }
  1165. else
  1166. {
  1167. dwErr = CServiceControlProgress::S_EControlService(
  1168. hwndParent,
  1169. hScManager,
  1170. pszMachineName,
  1171. pszServiceName,
  1172. sbstrServiceDisplayName,
  1173. dwControlCode);
  1174. }
  1175. if (NULL != hScManager)
  1176. (void) ::CloseServiceHandle( hScManager );
  1177. switch (dwErr)
  1178. {
  1179. case CServiceControlProgress::errUserCancelStopDependentServices:
  1180. case CServiceControlProgress::errCannotInitialize:
  1181. case CServiceControlProgress::errUserAbort:
  1182. return S_FALSE;
  1183. default:
  1184. break;
  1185. }
  1186. return HRESULT_FROM_WIN32(dwErr);
  1187. MFC_CATCH;
  1188. }