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.

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