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.

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