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.

1087 lines
35 KiB

  1. /////////////////////////////////////////////////////////////////////
  2. //
  3. // SvcUtils.cpp
  4. //
  5. // Utilities routines specific for system services.
  6. // Mostly used to display services properties.
  7. //
  8. // HISTORY
  9. // t-danmo 96.10.10 Creation.
  10. //
  11. /////////////////////////////////////////////////////////////////////
  12. #include "stdafx.h"
  13. #include <iads.h>
  14. #include <iadsp.h> // IADsPathname
  15. #include <atlcom.h> // CComPtr and CComBSTR
  16. extern "C"
  17. {
  18. #include <objsel.h> // IDsObjectPicker
  19. }
  20. //
  21. // Service current state
  22. //
  23. CString g_strSvcStateStarted; // Service is started
  24. CString g_strSvcStateStarting; // Service is starting
  25. CString g_strSvcStateStopped; // Service is stopped
  26. CString g_strSvcStateStopping; // Service is stopping
  27. CString g_strSvcStatePaused; // Service is paused
  28. CString g_strSvcStatePausing; // Service is pausing
  29. CString g_strSvcStateResuming; // Service is resuming
  30. //
  31. // Service startup type
  32. //
  33. CString g_strSvcStartupBoot;
  34. CString g_strSvcStartupSystem;
  35. CString g_strSvcStartupAutomatic;
  36. CString g_strSvcStartupManual;
  37. CString g_strSvcStartupDisabled;
  38. //
  39. // Service startup account
  40. // JonN 188203 11/13/00
  41. //
  42. CString g_strLocalSystem;
  43. CString g_strLocalService;
  44. CString g_strNetworkService;
  45. CString g_strUnknown;
  46. CString g_strLocalMachine; // "Local Machine"
  47. BOOL g_fStringsLoaded = FALSE;
  48. /////////////////////////////////////////////////////////////////////
  49. void
  50. Service_LoadResourceStrings()
  51. {
  52. if (g_fStringsLoaded)
  53. return;
  54. g_fStringsLoaded = TRUE;
  55. VERIFY(g_strSvcStateStarted.LoadString(IDS_SVC_STATUS_STARTED));
  56. VERIFY(g_strSvcStateStarting.LoadString(IDS_SVC_STATUS_STARTING));
  57. VERIFY(g_strSvcStateStopped.LoadString(IDS_SVC_STATUS_STOPPED));
  58. VERIFY(g_strSvcStateStopping.LoadString(IDS_SVC_STATUS_STOPPING));
  59. VERIFY(g_strSvcStatePaused.LoadString(IDS_SVC_STATUS_PAUSED));
  60. VERIFY(g_strSvcStatePausing.LoadString(IDS_SVC_STATUS_PAUSING));
  61. VERIFY(g_strSvcStateResuming.LoadString(IDS_SVC_STATUS_RESUMING));
  62. VERIFY(g_strSvcStartupBoot.LoadString(IDS_SVC_STARTUP_BOOT));
  63. VERIFY(g_strSvcStartupSystem.LoadString(IDS_SVC_STARTUP_SYSTEM));
  64. VERIFY(g_strSvcStartupAutomatic.LoadString(IDS_SVC_STARTUP_AUTOMATIC));
  65. VERIFY(g_strSvcStartupManual.LoadString(IDS_SVC_STARTUP_MANUAL));
  66. VERIFY(g_strSvcStartupDisabled.LoadString(IDS_SVC_STARTUP_DISABLED));
  67. // JonN 11/13/00 188203 support LocalService/NetworkService
  68. VERIFY(g_strLocalSystem.LoadString(IDS_SVC_STARTUP_LOCALSYSTEM));
  69. VERIFY(g_strLocalService.LoadString(IDS_SVC_STARTUP_LOCALSERVICE));
  70. VERIFY(g_strNetworkService.LoadString(IDS_SVC_STARTUP_NETWORKSERVICE));
  71. VERIFY(g_strUnknown.LoadString(IDS_SVC_UNKNOWN));
  72. VERIFY(g_strLocalMachine.LoadString(IDS_LOCAL_MACHINE));
  73. } // Service_LoadResourceStrings()
  74. /////////////////////////////////////////////////////////////////////
  75. // Service_PszMapStateToName()
  76. //
  77. // Map the service state to a null-terminated string.
  78. //
  79. // ISSUE-2002/03/18-JonN There is a theoretical issue here that the returned
  80. // LPCTSTR could go bad if the global strings are reloaded. This is unlikely.
  81. LPCTSTR
  82. Service_PszMapStateToName(
  83. DWORD dwServiceState, // From SERVICE_STATUS.dwCurrentState
  84. BOOL fLongString) // TRUE => Display the name in a long string format
  85. {
  86. switch(dwServiceState)
  87. {
  88. case SERVICE_STOPPED:
  89. if (fLongString)
  90. {
  91. return g_strSvcStateStopped;
  92. }
  93. // Note that, by design, we never display the service
  94. // status as "Stopped". Instead, we just don't display
  95. // the status. Hence, the empty string.
  96. return _T("");
  97. case SERVICE_STOP_PENDING:
  98. return g_strSvcStateStopping;
  99. case SERVICE_RUNNING:
  100. return g_strSvcStateStarted;
  101. case SERVICE_START_PENDING:
  102. return g_strSvcStateStarting;
  103. case SERVICE_PAUSED:
  104. return g_strSvcStatePaused;
  105. case SERVICE_PAUSE_PENDING:
  106. return g_strSvcStatePausing;
  107. case SERVICE_CONTINUE_PENDING:
  108. return g_strSvcStateResuming;
  109. default:
  110. TRACE0("INFO Unknown service state.\n");
  111. } // switch
  112. return g_strUnknown;
  113. } // Service_PszMapStateToName()
  114. /////////////////////////////////////////////////////////////////////
  115. // Service_PszMapStartupTypeToName()
  116. //
  117. // Map the service startup type to a null-terminated string.
  118. // -1L is blank string
  119. //
  120. LPCTSTR
  121. Service_PszMapStartupTypeToName(DWORD dwStartupType)
  122. {
  123. switch(dwStartupType)
  124. {
  125. case SERVICE_BOOT_START:
  126. return g_strSvcStartupBoot;
  127. case SERVICE_SYSTEM_START:
  128. return g_strSvcStartupSystem;
  129. case SERVICE_AUTO_START:
  130. return g_strSvcStartupAutomatic;
  131. case SERVICE_DEMAND_START:
  132. return g_strSvcStartupManual;
  133. case SERVICE_DISABLED :
  134. return g_strSvcStartupDisabled;
  135. case -1L:
  136. return L"";
  137. default:
  138. ASSERT(FALSE);
  139. }
  140. return g_strUnknown;
  141. } // Service_PszMapStartupTypeToName()
  142. /////////////////////////////////////////////////////////////////////
  143. // Service_PszMapStartupAccountToName()
  144. //
  145. // Map the service startup account to a null-terminated string.
  146. //
  147. // Note that if they use the localized version of the two special
  148. // accounts, I just won't pick that up. JSchwart and I agree that
  149. // this should be acceptable.
  150. //
  151. // JonN 188203 11/13/00
  152. // Services Snapin: Should support NetworkService and LocalService account
  153. //
  154. LPCTSTR
  155. Service_PszMapStartupAccountToName(LPCTSTR pcszStartupAccount)
  156. {
  157. if ( !pcszStartupAccount || !*pcszStartupAccount )
  158. return g_strLocalSystem;
  159. else if ( !_wcsicmp(pcszStartupAccount,TEXT("NT AUTHORITY\\LocalService")) )
  160. return g_strLocalService;
  161. else if ( !_wcsicmp(pcszStartupAccount,TEXT("NT AUTHORITY\\NetworkService")) )
  162. return g_strNetworkService;
  163. return pcszStartupAccount;
  164. } // Service_PszMapStartupAccountToName()
  165. /////////////////////////////////////////////////////////////////////
  166. // Service_FGetServiceButtonStatus()
  167. //
  168. // Query the service control manager database and fill in
  169. // array of flags indicating if the action is enabled.
  170. // rgfEnableButton[0] = TRUE; => Button 'start' is enabled
  171. // rgfEnableButton[0] = FALSE; => Button 'start' is disabled
  172. //
  173. // INTERFACE NOTES
  174. // The length of the array must be length iServiceActionMax (or larger).
  175. // Each representing start, stop, pause, resume and restart respectively.
  176. //
  177. // Return TRUE if the service status was queried successfully, otherwise FALSE.
  178. //
  179. BOOL
  180. Service_FGetServiceButtonStatus(
  181. SC_HANDLE hScManager, // IN: Handle of service control manager database
  182. CONST TCHAR * pszServiceName, // IN: Name of service
  183. BOOL rgfEnableButton[iServiceActionMax], // OUT: Array of flags to enable the buttons
  184. DWORD * pdwCurrentState, // OUT: Optional: Current state of service
  185. BOOL fSilentError) // IN: TRUE => Do not display any error message to user
  186. {
  187. Endorse(hScManager == NULL);
  188. Assert(pszServiceName != NULL);
  189. Assert(rgfEnableButton != NULL);
  190. Endorse(pdwCurrentState == NULL);
  191. // Open service to get its status
  192. BOOL fSuccess = TRUE;
  193. SC_HANDLE hService;
  194. SERVICE_STATUS ss;
  195. DWORD cbBytesNeeded;
  196. DWORD dwErr;
  197. ::ZeroMemory(OUT rgfEnableButton, iServiceActionMax * sizeof(BOOL));
  198. if (pdwCurrentState != NULL)
  199. *pdwCurrentState = 0;
  200. if (hScManager == NULL || pszServiceName[0] == '\0')
  201. return FALSE;
  202. hService = ::OpenService(
  203. hScManager,
  204. pszServiceName,
  205. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
  206. if (hService == NULL)
  207. {
  208. dwErr = ::GetLastError();
  209. Assert(dwErr != ERROR_SUCCESS);
  210. TRACE2("Failed to open service %s. err=%u.\n",
  211. pszServiceName, dwErr);
  212. if (!fSilentError)
  213. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr);
  214. return FALSE;
  215. }
  216. if (!::QueryServiceStatus(hService, OUT &ss))
  217. {
  218. dwErr = ::GetLastError();
  219. Assert(dwErr != ERROR_SUCCESS);
  220. TRACE2("::QueryServiceStatus(Service=%s) failed. err=%u.\n",
  221. pszServiceName, dwErr);
  222. if (!fSilentError)
  223. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr);
  224. fSuccess = FALSE;
  225. }
  226. else
  227. {
  228. // Determine which menu items should be grayed
  229. if (pdwCurrentState != NULL)
  230. *pdwCurrentState = ss.dwCurrentState;
  231. switch (ss.dwCurrentState)
  232. {
  233. default:
  234. Assert(FALSE && "Illegal service status state.");
  235. case SERVICE_START_PENDING:
  236. case SERVICE_STOP_PENDING:
  237. case SERVICE_PAUSE_PENDING:
  238. case SERVICE_CONTINUE_PENDING:
  239. break;
  240. case SERVICE_STOPPED:
  241. QUERY_SERVICE_CONFIG qsc;
  242. ZeroMemory( &qsc, sizeof(qsc) );
  243. qsc.dwStartType = (DWORD)-1;
  244. // JonN-2002/04/04-544089 handle long DisplayName value
  245. // If this fails, don't enable the Start button
  246. //
  247. // JonN-2002/04/29 fix regression
  248. // Even if QueryServiceConfig fails, it still fills in the
  249. // fixed-size area if it can. So ignore the error in this case.
  250. (void) ::QueryServiceConfig(
  251. hService,
  252. OUT &qsc,
  253. sizeof(qsc),
  254. OUT IGNORED &cbBytesNeeded);
  255. Report(qsc.dwStartType != (DWORD)-1);
  256. if (qsc.dwStartType != SERVICE_DISABLED)
  257. {
  258. rgfEnableButton[iServiceActionStart] = TRUE; // Enable 'Start' menu item
  259. }
  260. break;
  261. case SERVICE_RUNNING:
  262. // Some services are not allowed to be stoped and/or paused
  263. if (ss.dwControlsAccepted & SERVICE_ACCEPT_STOP)
  264. {
  265. rgfEnableButton[iServiceActionStop] = TRUE; // Enable 'Stop' menu item
  266. }
  267. if (ss.dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE)
  268. {
  269. rgfEnableButton[iServiceActionPause] = TRUE; // Enable 'Pause' menu item
  270. }
  271. break;
  272. case SERVICE_PAUSED:
  273. if (ss.dwControlsAccepted & SERVICE_ACCEPT_STOP)
  274. {
  275. rgfEnableButton[iServiceActionStop] = TRUE; // Enable 'Stop' menu item
  276. }
  277. rgfEnableButton[iServiceActionResume] = TRUE; // Enable 'Resume' menu item
  278. break;
  279. } // switch
  280. } // if...else
  281. // A 'Restart' has the same characteristics as a 'Stop'
  282. rgfEnableButton[iServiceActionRestart] = rgfEnableButton[iServiceActionStop];
  283. (void)::CloseServiceHandle(hService);
  284. return fSuccess;
  285. } // Service_FGetServiceButtonStatus()
  286. /////////////////////////////////////////////////////////////////////
  287. // Service_SplitCommandLine()
  288. //
  289. // Split a string into two strings.
  290. // Very similar to PchParseCommandLine() but uses CString objects.
  291. //
  292. void
  293. Service_SplitCommandLine(
  294. LPCTSTR pszFullCommand, // IN: Full command line
  295. CString * pstrBinaryPath, // OUT: Path of the executable binary
  296. CString * pstrParameters, // OUT: Parameters for the executable
  297. BOOL * pfAbend) // OUT: Optional: Search for string "/fail=%1%"
  298. {
  299. Assert(pszFullCommand != NULL);
  300. Assert(pstrBinaryPath != NULL);
  301. Assert(pstrParameters != NULL);
  302. Endorse(pfAbend == NULL);
  303. // Since there is no upper bound on the command
  304. // arguments, we need to allocate memory for
  305. // its processing.
  306. TCHAR * paszCommandT; // Temporary buffer
  307. TCHAR * pszCommandArguments;
  308. INT cchMemAlloc; // Number of bytes to allocate
  309. cchMemAlloc = lstrlen(pszFullCommand) + 1;
  310. paszCommandT = new TCHAR[cchMemAlloc];
  311. paszCommandT[0] = '\0'; // Just in case
  312. pszCommandArguments = PchParseCommandLine(
  313. IN pszFullCommand,
  314. OUT paszCommandT,
  315. cchMemAlloc);
  316. *pstrBinaryPath = paszCommandT;
  317. if (pfAbend != NULL)
  318. {
  319. INT cStringSubstitutions; // Number of string substitutions
  320. // Find out if the string contains "/fail=%1%"
  321. // 580255-2002/03/18 JonN fixed Str_SubstituteStrStr buffer overrun
  322. cStringSubstitutions = Str_RemoveSubStr(
  323. IN OUT pszCommandArguments,
  324. IN szAbend );
  325. Report((cStringSubstitutions == 0 || cStringSubstitutions == 1) &&
  326. "INFO: Multiple substitutions will be consolidated.");
  327. *pfAbend = cStringSubstitutions != 0;
  328. }
  329. *pstrParameters = pszCommandArguments;
  330. TrimString(*pstrParameters);
  331. delete paszCommandT;
  332. } // Service_SplitCommandLine()
  333. /////////////////////////////////////////////////////////////////////
  334. // Service_UnSplitCommandLine()
  335. //
  336. // Just do the opposite of Service_SplitCommandLine().
  337. // Combine the executable path and its arguments into a single string.
  338. //
  339. void
  340. Service_UnSplitCommandLine(
  341. CString * pstrFullCommand, // OUT: Full command line
  342. LPCTSTR pszBinaryPath, // IN: Path of the executable binary
  343. LPCTSTR pszParameters) // IN: Parameters for the executable
  344. {
  345. Assert(pstrFullCommand != NULL);
  346. Assert(pszBinaryPath != NULL);
  347. Assert(pszParameters != NULL);
  348. TCHAR * psz;
  349. psz = pstrFullCommand->GetBuffer(lstrlen(pszBinaryPath) + lstrlen(pszParameters) + 32);
  350. // Build a string with the binary path surrounded by quotes
  351. wsprintf(OUT psz, L"\"%s\" %s", pszBinaryPath, pszParameters);
  352. pstrFullCommand->ReleaseBuffer();
  353. } // Service_UnSplitCommandLine()
  354. /////////////////////////////////////////////////////////////////////
  355. // LoadSystemString()
  356. //
  357. // Load a string from system's resources. This function will check if
  358. // the string Id can be located in netmsg.dll before attempting to
  359. // load the string from the 'system resource'.
  360. // If string cannot be loaded, *ppaszBuffer is set to NULL.
  361. //
  362. // ISSUE-2002/03/18-JonN The above comment is inaccurate. If the string
  363. // cannot be loaded from netmsg.dll, it does not fall back to system.
  364. //
  365. // RETURN
  366. // Pointer to allocated string and number of characters put
  367. // into *ppaszBuffer.
  368. //
  369. // INTERFACE NOTES
  370. // Caller must call LocalFree(*ppaszBuffer) when done with the string.
  371. //
  372. // HISTORY
  373. // 96.10.21 t-danmo Copied from net\ui\common\src\string\string\strload.cxx.
  374. //
  375. /* JonN-2002/03/18-JonN This function is not used
  376. DWORD
  377. LoadSystemString(
  378. UINT wIdString, // IN: String Id. Typically error code from GetLastError().
  379. LPTSTR * ppaszBuffer) // OUT: Address of pointer to allocated string.
  380. {
  381. Assert(ppaszBuffer != NULL);
  382. UINT cch;
  383. HMODULE hModule = NULL;
  384. DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
  385. FORMAT_MESSAGE_IGNORE_INSERTS |
  386. FORMAT_MESSAGE_MAX_WIDTH_MASK;
  387. if ((wIdString >= MIN_LANMAN_MESSAGE_ID) && (wIdString <= MAX_LANMAN_MESSAGE_ID))
  388. {
  389. // Network Errors
  390. dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
  391. hModule = ::LoadLibrary(_T("netmsg.dll"));
  392. if (hModule == NULL)
  393. {
  394. TRACE1("LoadLibrary(\"netmsg.dll\") failed. err=%u.\n", GetLastError());
  395. Report("Unable to get module handle for netmsg.dll");
  396. }
  397. }
  398. else
  399. {
  400. // Other system errors
  401. dwFlags |= FORMAT_MESSAGE_FROM_SYSTEM;
  402. }
  403. *ppaszBuffer = NULL; // Just in case
  404. cch = ::FormatMessage(
  405. dwFlags,
  406. hModule,
  407. wIdString,
  408. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  409. OUT (LPTSTR)ppaszBuffer, // Buffer will be allocated by FormatMessage()
  410. 0,
  411. NULL);
  412. Report((cch > 0) && "FormatMessage() returned an empty string");
  413. if (hModule != NULL)
  414. {
  415. VERIFY(FreeLibrary(hModule));
  416. }
  417. return cch;
  418. } // LoadSystemString()
  419. */
  420. /////////////////////////////////////////////////////////////////////
  421. // GetMsgHelper()
  422. //
  423. // This function will retrieve the error msg if dwErr is specified,
  424. // load resource string if specified, and format the string with
  425. // the error msg and other optional arguments.
  426. //
  427. //
  428. HRESULT
  429. GetMsgHelper(
  430. OUT CString& strMsg,// OUT: the message
  431. DWORD dwErr, // IN: Error code from GetLastError()
  432. UINT wIdString, // IN: String ID
  433. va_list* parglist // IN: OPTIONAL arguments
  434. )
  435. {
  436. if (!dwErr && !wIdString)
  437. return E_INVALIDARG;
  438. TCHAR *pszMsgResourceString = NULL;
  439. TCHAR *pszT = L"";
  440. //
  441. // retrieve error msg
  442. //
  443. CString strErrorMessage;
  444. if (dwErr != 0)
  445. {
  446. GetErrorMessage(dwErr, strErrorMessage);
  447. pszT = (LPTSTR)(LPCTSTR)strErrorMessage;
  448. }
  449. //
  450. // load string resource, and format it with the error msg and
  451. // other optional arguments
  452. //
  453. if (wIdString == 0)
  454. {
  455. strMsg = pszT;
  456. } else
  457. {
  458. pszMsgResourceString = PaszLoadStringPrintf(wIdString, *parglist);
  459. if (dwErr == 0)
  460. strMsg = pszMsgResourceString;
  461. else if ((HRESULT)dwErr < 0)
  462. LoadStringPrintf(IDS_sus_ERROR_HR, OUT &strMsg, pszMsgResourceString, dwErr, pszT);
  463. else
  464. LoadStringPrintf(IDS_sus_ERROR, OUT &strMsg, pszMsgResourceString, dwErr, pszT);
  465. }
  466. if (pszMsgResourceString)
  467. LocalFree(pszMsgResourceString);
  468. return S_OK;
  469. } // GetMsgHelper()
  470. /////////////////////////////////////////////////////////////////////
  471. // GetMsg()
  472. //
  473. // This function will call GetMsgHelp to retrieve the error msg
  474. // if dwErr is specified, load resource string if specified, and
  475. // format the string with the error msg and other optional arguments.
  476. //
  477. //
  478. void
  479. GetMsg(
  480. OUT CString& strMsg,// OUT: the message
  481. DWORD dwErr, // IN: Error code from GetLastError()
  482. UINT wIdString, // IN: String resource Id
  483. ...) // IN: Optional arguments
  484. {
  485. va_list arglist;
  486. va_start(arglist, wIdString);
  487. HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist);
  488. if (FAILED(hr))
  489. strMsg.Format(_T("0x%x"), hr);
  490. va_end(arglist);
  491. } // GetMsg()
  492. /////////////////////////////////////////////////////////////////////
  493. // DoErrMsgBox()
  494. //
  495. // Display a message box for the error code. This function will
  496. // load the error message from the system resource and append
  497. // the optional string (if any)
  498. //
  499. // EXAMPLE
  500. // DoErrMsgBox(GetActiveWindow(), MB_OK, GetLastError(), IDS_s_FILE_READ_ERROR, L"foo.txt");
  501. //
  502. INT
  503. DoErrMsgBoxHelper(
  504. HWND hwndParent, // IN: Parent of the dialog box
  505. UINT uType, // IN: style of message box
  506. DWORD dwErr, // IN: Error code from GetLastError()
  507. UINT wIdString, // IN: String resource Id
  508. bool fServicesSnapin, // IN: Is this filemgmt or svcmgmt?
  509. va_list& arglist) // IN: Optional arguments
  510. {
  511. //
  512. // get string and the error msg
  513. //
  514. CString strMsg;
  515. HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist);
  516. if (FAILED(hr))
  517. strMsg.Format(_T("0x%x"), hr);
  518. //
  519. // Load the caption
  520. //
  521. CString strCaption;
  522. strCaption.LoadString(
  523. (fServicesSnapin) ? IDS_CAPTION_SERVICES : IDS_CAPTION_FILEMGMT);
  524. //
  525. // Display the message.
  526. //
  527. CThemeContextActivator activator;;
  528. return MessageBox(hwndParent, strMsg, strCaption, uType);
  529. } // DoErrMsgBox()
  530. INT
  531. DoErrMsgBox(
  532. HWND hwndParent, // IN: Parent of the dialog box
  533. UINT uType, // IN: style of message box
  534. DWORD dwErr, // IN: Error code from GetLastError()
  535. UINT wIdString, // IN: String resource Id
  536. ...) // IN: Optional arguments
  537. {
  538. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  539. //
  540. // get string and the error msg
  541. //
  542. va_list arglist;
  543. va_start(arglist, wIdString);
  544. INT retval = DoErrMsgBoxHelper(
  545. hwndParent, uType, dwErr, wIdString, false, arglist );
  546. va_end(arglist);
  547. return retval;
  548. } // DoErrMsgBox()
  549. //
  550. // JonN 3/5/01 4635
  551. // Services Snapin - String length error dialog title shouldn't be "File Service Management"
  552. //
  553. INT
  554. DoServicesErrMsgBox(
  555. HWND hwndParent, // IN: Parent of the dialog box
  556. UINT uType, // IN: style of message box
  557. DWORD dwErr, // IN: Error code from GetLastError()
  558. UINT wIdString, // IN: String resource Id
  559. ...) // IN: Optional arguments
  560. {
  561. //
  562. // get string and the error msg
  563. //
  564. va_list arglist;
  565. va_start(arglist, wIdString);
  566. INT retval = DoErrMsgBoxHelper(
  567. hwndParent, uType, dwErr, wIdString, true, arglist );
  568. va_end(arglist);
  569. return retval;
  570. }
  571. //+--------------------------------------------------------------------------
  572. //
  573. // Function: InitObjectPickerForUsers
  574. //
  575. // Synopsis: Call IDsObjectPicker::Initialize with arguments that will
  576. // set it to allow the user to pick one user.
  577. //
  578. // Arguments: [pDsObjectPicker] - object picker interface instance
  579. //
  580. // Returns: Result of calling IDsObjectPicker::Initialize.
  581. //
  582. // History: 10-14-1998 DavidMun Sample code InitObjectPickerForGroups
  583. // 10-14-1998 JonN Changed to InitObjectPickerForUsers
  584. // 11-11-2000 JonN 188203 support LocalService/NetworkService
  585. //
  586. //---------------------------------------------------------------------------
  587. // CODEWORK do I want to allow USER_ENTERED?
  588. HRESULT
  589. InitObjectPickerForUsers(
  590. IDsObjectPicker *pDsObjectPicker,
  591. LPCTSTR pszServerName)
  592. {
  593. //
  594. // Prepare to initialize the object picker.
  595. // Set up the array of scope initializer structures.
  596. //
  597. static const int SCOPE_INIT_COUNT = 5;
  598. DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
  599. ZeroMemory(aScopeInit, sizeof(aScopeInit));
  600. //
  601. // Target computer scope. This adds a "Look In" entry for the
  602. // target computer. Computer scopes are always treated as
  603. // downlevel (i.e., they use the WinNT provider).
  604. //
  605. aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  606. aScopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER;
  607. aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE
  608. | DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
  609. // JonN 11/14/00 188203 support LocalService/NetworkService
  610. aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS
  611. | DSOP_DOWNLEVEL_FILTER_LOCAL_SERVICE
  612. | DSOP_DOWNLEVEL_FILTER_NETWORK_SERVICE;
  613. //
  614. // The domain to which the target computer is joined. Note we're
  615. // combining two scope types into flType here for convenience.
  616. //
  617. aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  618. aScopeInit[1].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
  619. | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
  620. aScopeInit[1].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
  621. aScopeInit[1].FilterFlags.Uplevel.flNativeModeOnly =
  622. DSOP_FILTER_USERS;
  623. aScopeInit[1].FilterFlags.Uplevel.flMixedModeOnly =
  624. DSOP_FILTER_USERS;
  625. aScopeInit[1].FilterFlags.flDownlevel =
  626. DSOP_DOWNLEVEL_FILTER_USERS;
  627. //
  628. // The domains in the same forest (enterprise) as the domain to which
  629. // the target machine is joined. Note these can only be DS-aware
  630. //
  631. aScopeInit[2].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  632. aScopeInit[2].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN;
  633. aScopeInit[2].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
  634. aScopeInit[2].FilterFlags.Uplevel.flNativeModeOnly =
  635. DSOP_FILTER_USERS;
  636. aScopeInit[2].FilterFlags.Uplevel.flMixedModeOnly =
  637. DSOP_FILTER_USERS;
  638. //
  639. // Domains external to the enterprise but trusted directly by the
  640. // domain to which the target machine is joined.
  641. //
  642. // If the target machine is joined to an NT4 domain, only the
  643. // external downlevel domain scope applies, and it will cause
  644. // all domains trusted by the joined domain to appear.
  645. //
  646. aScopeInit[3].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  647. aScopeInit[3].flType = DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
  648. | DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN;
  649. aScopeInit[3].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
  650. aScopeInit[3].FilterFlags.Uplevel.flNativeModeOnly =
  651. DSOP_FILTER_USERS;
  652. aScopeInit[3].FilterFlags.Uplevel.flMixedModeOnly =
  653. DSOP_FILTER_USERS;
  654. aScopeInit[3].FilterFlags.flDownlevel =
  655. DSOP_DOWNLEVEL_FILTER_USERS;
  656. //
  657. // The Global Catalog
  658. //
  659. aScopeInit[4].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  660. aScopeInit[4].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT;
  661. aScopeInit[4].flType = DSOP_SCOPE_TYPE_GLOBAL_CATALOG;
  662. // Only native mode applies to gc scope.
  663. aScopeInit[4].FilterFlags.Uplevel.flNativeModeOnly =
  664. DSOP_FILTER_USERS;
  665. //
  666. // Put the scope init array into the object picker init array
  667. //
  668. DSOP_INIT_INFO InitInfo;
  669. ZeroMemory(&InitInfo, sizeof(InitInfo));
  670. InitInfo.cbSize = sizeof(InitInfo);
  671. //
  672. // The pwzTargetComputer member allows the object picker to be
  673. // retargetted to a different computer. It will behave as if it
  674. // were being run ON THAT COMPUTER.
  675. //
  676. InitInfo.pwzTargetComputer = pszServerName; // NULL == local machine
  677. // InitInfo.pwzTargetComputer = NULL; // NULL == local machine
  678. InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
  679. InitInfo.aDsScopeInfos = aScopeInit;
  680. // JonN 11/14/00 188203 support LocalService/NetworkService
  681. static PCWSTR g_pszObjectSid = L"objectSid";
  682. InitInfo.cAttributesToFetch = 1;
  683. InitInfo.apwzAttributeNames = &g_pszObjectSid;
  684. //
  685. // Note object picker makes its own copy of InitInfo. Also note
  686. // that Initialize may be called multiple times, last call wins.
  687. //
  688. HRESULT hr = pDsObjectPicker->Initialize(&InitInfo);
  689. ASSERT( SUCCEEDED(hr) );
  690. return hr;
  691. } // InitObjectPickerForUsers
  692. //+--------------------------------------------------------------------------
  693. //
  694. // Function: ExtractADsPathAndUPN
  695. //
  696. // Synopsis: Retrieve the selected username from the data object
  697. // created by the object picker.
  698. //
  699. // Arguments: [pdo] - data object returned by object picker
  700. //
  701. // History: 10-14-1998 DavidMun Sample code ProcessSelectedObjects
  702. // 10-14-1998 JonN Changed to ExtractADsPath
  703. // 01-25-1999 JonN Added pflScopeType parameter
  704. // 03-16-1999 JonN Changed to ExtractADsPathAndUPN
  705. // 11-14-2000 JonN Added svarrefObjectSid for 188203
  706. //
  707. //---------------------------------------------------------------------------
  708. UINT g_cfDsObjectPicker = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
  709. HRESULT
  710. ExtractADsPathAndUPN(
  711. IN IDataObject *pdo,
  712. OUT CString& strrefADsPath,
  713. OUT CString& strrefUPN,
  714. OUT CComVariant& svarrefObjectSid,
  715. OUT ULONG *pflScopeType)
  716. {
  717. if (NULL == pdo)
  718. return E_POINTER;
  719. HRESULT hr = S_OK;
  720. STGMEDIUM stgmedium =
  721. {
  722. TYMED_HGLOBAL,
  723. NULL,
  724. NULL
  725. };
  726. FORMATETC formatetc =
  727. {
  728. (CLIPFORMAT)g_cfDsObjectPicker,
  729. NULL,
  730. DVASPECT_CONTENT,
  731. -1,
  732. TYMED_HGLOBAL
  733. };
  734. bool fGotStgMedium = false;
  735. do
  736. {
  737. hr = pdo->GetData(&formatetc, &stgmedium);
  738. if (FAILED(hr))
  739. {
  740. ASSERT(FALSE);
  741. break;
  742. }
  743. fGotStgMedium = true;
  744. PDS_SELECTION_LIST pDsSelList =
  745. (PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
  746. if ( NULL == pDsSelList
  747. || 1 != pDsSelList->cItems
  748. )
  749. {
  750. ASSERT(FALSE);
  751. hr = E_FAIL;
  752. break;
  753. }
  754. DS_SELECTION& sel = pDsSelList->aDsSelection[0];
  755. strrefADsPath = sel.pwzADsPath;
  756. strrefUPN = sel.pwzUPN;
  757. if ( sel.pvarFetchedAttributes )
  758. svarrefObjectSid = sel.pvarFetchedAttributes[0];
  759. if (NULL != pflScopeType)
  760. *pflScopeType = pDsSelList->aDsSelection[0].flScopeType;
  761. GlobalUnlock(stgmedium.hGlobal);
  762. } while (0);
  763. if (fGotStgMedium)
  764. {
  765. ReleaseStgMedium(&stgmedium);
  766. }
  767. return hr;
  768. }
  769. /////////////////////////////////////////////////////////////////////
  770. // UiGetUser()
  771. //
  772. // Invoke a user picker dialog.
  773. //
  774. // Return TRUE iff an account was selected.
  775. //
  776. // HISTORY
  777. // 96.10.12 t-danmo Creation. Inspired from function GetUser() located
  778. // at \nt\private\windows\shell\security\aclui\misc.cpp.
  779. // 96.10.30 t-danmo Added/modified comments.
  780. // 98.03.17 jonn Modified to use User/Group Picker
  781. // 98.10.20 jonn Modified to use updated Object Picker interfaces
  782. //
  783. //+--------------------------------------------------------------------------
  784. //
  785. // Function: ExtractDomainUserString
  786. //
  787. // Synopsis: Converts an ADspath to the format needed by Service Controller
  788. //
  789. // History: 10-14-1998 JonN Created
  790. // 01-25-1999 JonN added flScopeType parameter
  791. //
  792. //---------------------------------------------------------------------------
  793. HRESULT
  794. ExtractDomainUserString(
  795. IN LPCTSTR pwzADsPath,
  796. IN ULONG flScopeType,
  797. IN OUT CString& strrefDomainUser)
  798. {
  799. HRESULT hr = S_OK;
  800. CComPtr<IADsPathname> spIADsPathname;
  801. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  802. IID_IADsPathname, (PVOID *)&spIADsPathname);
  803. RETURN_HR_IF_FAIL;
  804. hr = spIADsPathname->Set( const_cast<LPTSTR>(pwzADsPath), ADS_SETTYPE_FULL );
  805. RETURN_HR_IF_FAIL;
  806. CComBSTR sbstrUser;
  807. hr = spIADsPathname->GetElement( 0, &sbstrUser );
  808. RETURN_HR_IF_FAIL;
  809. CComBSTR sbstrDomain = OLESTR(".");
  810. if (DSOP_SCOPE_TYPE_TARGET_COMPUTER != flScopeType)
  811. {
  812. long lnNumPathElements = 0;
  813. hr = spIADsPathname->GetNumElements( &lnNumPathElements );
  814. RETURN_FALSE_IF_FAIL;
  815. switch (lnNumPathElements)
  816. {
  817. case 1:
  818. hr = spIADsPathname->Retrieve( ADS_FORMAT_SERVER, &sbstrDomain );
  819. RETURN_HR_IF_FAIL;
  820. break;
  821. case 2:
  822. hr = spIADsPathname->GetElement( 1, &sbstrDomain );
  823. RETURN_HR_IF_FAIL;
  824. break;
  825. default:
  826. ASSERT(FALSE);
  827. return E_FAIL;
  828. }
  829. }
  830. strrefDomainUser.Format(L"%s\\%s", sbstrDomain, sbstrUser);
  831. return hr;
  832. } // ExtractDomainUserString
  833. BOOL
  834. UiGetUser(
  835. HWND hwndOwner, // IN: Owner window
  836. BOOL /*fIsContainer*/, // IN: TRUE if invoked for a container
  837. LPCTSTR pszServerName, // IN: Initial target machine name
  838. OUT CString& strrefUser) // IN: Allocated buffer containing the user details
  839. {
  840. HRESULT hr = S_OK;
  841. CComPtr<IDsObjectPicker> spDsObjectPicker;
  842. hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER,
  843. IID_IDsObjectPicker, (PVOID *)&spDsObjectPicker);
  844. RETURN_FALSE_IF_FAIL;
  845. ASSERT( !!spDsObjectPicker );
  846. hr = InitObjectPickerForUsers(spDsObjectPicker, pszServerName);
  847. RETURN_FALSE_IF_FAIL;
  848. CComPtr<IDataObject> spDataObject;
  849. hr = spDsObjectPicker->InvokeDialog(hwndOwner, &spDataObject);
  850. RETURN_FALSE_IF_FAIL;
  851. if (S_FALSE == hr)
  852. return FALSE; // user cancelled
  853. ASSERT( !!spDataObject );
  854. CString strADsPath;
  855. ULONG flScopeType = DSOP_SCOPE_TYPE_TARGET_COMPUTER;
  856. CComVariant svarObjectSid;
  857. hr = ExtractADsPathAndUPN( spDataObject,
  858. strADsPath,
  859. strrefUser,
  860. svarObjectSid,
  861. &flScopeType );
  862. RETURN_FALSE_IF_FAIL;
  863. // JonN 11/15/00 188203 check for LocalService/NetworkService
  864. if (svarObjectSid.vt == (VT_ARRAY|VT_UI1))
  865. {
  866. PSID pSid = svarObjectSid.parray->pvData;
  867. if ( IsWellKnownSid(pSid, WinLocalServiceSid) )
  868. {
  869. strrefUser = TEXT("NT AUTHORITY\\LocalService");
  870. return TRUE;
  871. }
  872. else if ( IsWellKnownSid(pSid, WinNetworkServiceSid) )
  873. {
  874. strrefUser = TEXT("NT AUTHORITY\\NetworkService");
  875. return TRUE;
  876. }
  877. }
  878. if (strrefUser.IsEmpty())
  879. {
  880. if (strADsPath.IsEmpty())
  881. {
  882. ASSERT(FALSE);
  883. return FALSE;
  884. }
  885. hr = ExtractDomainUserString( strADsPath, flScopeType, strrefUser );
  886. RETURN_FALSE_IF_FAIL;
  887. }
  888. return TRUE;
  889. } // UiGetUser()
  890. /////////////////////////////////////////////////////////////////////
  891. // DoHelp()
  892. //
  893. // This routine handles context help for the WM_HELP message.
  894. //
  895. // The return value is always TRUE.
  896. //
  897. BOOL DoHelp(
  898. LPARAM lParam, // Pointer to HELPINFO structure
  899. const DWORD rgzHelpIDs[]) // Array of HelpIDs
  900. {
  901. Assert(rgzHelpIDs != NULL);
  902. const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  903. if (pHelpInfo != NULL)
  904. {
  905. if (pHelpInfo->iContextType == HELPINFO_WINDOW)
  906. {
  907. const HWND hwnd = (HWND)pHelpInfo->hItemHandle;
  908. Assert(IsWindow(hwnd));
  909. // Display context help for a control
  910. WinHelp(
  911. hwnd,
  912. g_szHelpFileFilemgmt,
  913. HELP_WM_HELP,
  914. (DWORD_PTR)rgzHelpIDs);
  915. }
  916. }
  917. return TRUE;
  918. } // DoHelp()
  919. /////////////////////////////////////////////////////////////////////
  920. // DoContextHelp()
  921. //
  922. // This routine handles context help for the WM_CONTEXTMENU message.
  923. //
  924. // The return value is always TRUE.
  925. //
  926. BOOL DoContextHelp(
  927. WPARAM wParam, // Window requesting help
  928. const DWORD rgzHelpIDs[]) // Array of HelpIDs
  929. {
  930. const HWND hwnd = (HWND)wParam;
  931. Assert(IsWindow(hwnd));
  932. Assert(rgzHelpIDs != NULL);
  933. WinHelp(hwnd, g_szHelpFileFilemgmt, HELP_CONTEXTMENU, (DWORD_PTR)rgzHelpIDs);
  934. return TRUE;
  935. } // DoContextHelp()