///////////////////////////////////////////////////////////////////// // // SvcUtils.cpp // // Utilities routines specific for system services. // Mostly used to display services properties. // // HISTORY // t-danmo 96.10.10 Creation. // ///////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include // IADsPathname #include // CComPtr and CComBSTR extern "C" { #include // IDsObjectPicker } // // Service current state // CString g_strSvcStateStarted; // Service is started CString g_strSvcStateStarting; // Service is starting CString g_strSvcStateStopped; // Service is stopped CString g_strSvcStateStopping; // Service is stopping CString g_strSvcStatePaused; // Service is paused CString g_strSvcStatePausing; // Service is pausing CString g_strSvcStateResuming; // Service is resuming // // Service startup type // CString g_strSvcStartupBoot; CString g_strSvcStartupSystem; CString g_strSvcStartupAutomatic; CString g_strSvcStartupManual; CString g_strSvcStartupDisabled; // // Service startup account // JonN 188203 11/13/00 // CString g_strLocalSystem; CString g_strLocalService; CString g_strNetworkService; CString g_strUnknown; CString g_strLocalMachine; // "Local Machine" BOOL g_fStringsLoaded = FALSE; ///////////////////////////////////////////////////////////////////// void Service_LoadResourceStrings() { if (g_fStringsLoaded) return; g_fStringsLoaded = TRUE; VERIFY(g_strSvcStateStarted.LoadString(IDS_SVC_STATUS_STARTED)); VERIFY(g_strSvcStateStarting.LoadString(IDS_SVC_STATUS_STARTING)); VERIFY(g_strSvcStateStopped.LoadString(IDS_SVC_STATUS_STOPPED)); VERIFY(g_strSvcStateStopping.LoadString(IDS_SVC_STATUS_STOPPING)); VERIFY(g_strSvcStatePaused.LoadString(IDS_SVC_STATUS_PAUSED)); VERIFY(g_strSvcStatePausing.LoadString(IDS_SVC_STATUS_PAUSING)); VERIFY(g_strSvcStateResuming.LoadString(IDS_SVC_STATUS_RESUMING)); VERIFY(g_strSvcStartupBoot.LoadString(IDS_SVC_STARTUP_BOOT)); VERIFY(g_strSvcStartupSystem.LoadString(IDS_SVC_STARTUP_SYSTEM)); VERIFY(g_strSvcStartupAutomatic.LoadString(IDS_SVC_STARTUP_AUTOMATIC)); VERIFY(g_strSvcStartupManual.LoadString(IDS_SVC_STARTUP_MANUAL)); VERIFY(g_strSvcStartupDisabled.LoadString(IDS_SVC_STARTUP_DISABLED)); // JonN 11/13/00 188203 support LocalService/NetworkService VERIFY(g_strLocalSystem.LoadString(IDS_SVC_STARTUP_LOCALSYSTEM)); VERIFY(g_strLocalService.LoadString(IDS_SVC_STARTUP_LOCALSERVICE)); VERIFY(g_strNetworkService.LoadString(IDS_SVC_STARTUP_NETWORKSERVICE)); VERIFY(g_strUnknown.LoadString(IDS_SVC_UNKNOWN)); VERIFY(g_strLocalMachine.LoadString(IDS_LOCAL_MACHINE)); } // Service_LoadResourceStrings() ///////////////////////////////////////////////////////////////////// // Service_PszMapStateToName() // // Map the service state to a null-terminated string. // // ISSUE-2002/03/18-JonN There is a theoretical issue here that the returned // LPCTSTR could go bad if the global strings are reloaded. This is unlikely. LPCTSTR Service_PszMapStateToName( DWORD dwServiceState, // From SERVICE_STATUS.dwCurrentState BOOL fLongString) // TRUE => Display the name in a long string format { switch(dwServiceState) { case SERVICE_STOPPED: if (fLongString) { return g_strSvcStateStopped; } // Note that, by design, we never display the service // status as "Stopped". Instead, we just don't display // the status. Hence, the empty string. return _T(""); case SERVICE_STOP_PENDING: return g_strSvcStateStopping; case SERVICE_RUNNING: return g_strSvcStateStarted; case SERVICE_START_PENDING: return g_strSvcStateStarting; case SERVICE_PAUSED: return g_strSvcStatePaused; case SERVICE_PAUSE_PENDING: return g_strSvcStatePausing; case SERVICE_CONTINUE_PENDING: return g_strSvcStateResuming; default: TRACE0("INFO Unknown service state.\n"); } // switch return g_strUnknown; } // Service_PszMapStateToName() ///////////////////////////////////////////////////////////////////// // Service_PszMapStartupTypeToName() // // Map the service startup type to a null-terminated string. // -1L is blank string // LPCTSTR Service_PszMapStartupTypeToName(DWORD dwStartupType) { switch(dwStartupType) { case SERVICE_BOOT_START: return g_strSvcStartupBoot; case SERVICE_SYSTEM_START: return g_strSvcStartupSystem; case SERVICE_AUTO_START: return g_strSvcStartupAutomatic; case SERVICE_DEMAND_START: return g_strSvcStartupManual; case SERVICE_DISABLED : return g_strSvcStartupDisabled; case -1L: return L""; default: ASSERT(FALSE); } return g_strUnknown; } // Service_PszMapStartupTypeToName() ///////////////////////////////////////////////////////////////////// // Service_PszMapStartupAccountToName() // // Map the service startup account to a null-terminated string. // // Note that if they use the localized version of the two special // accounts, I just won't pick that up. JSchwart and I agree that // this should be acceptable. // // JonN 188203 11/13/00 // Services Snapin: Should support NetworkService and LocalService account // LPCTSTR Service_PszMapStartupAccountToName(LPCTSTR pcszStartupAccount) { if ( !pcszStartupAccount || !*pcszStartupAccount ) return g_strLocalSystem; else if ( !_wcsicmp(pcszStartupAccount,TEXT("NT AUTHORITY\\LocalService")) ) return g_strLocalService; else if ( !_wcsicmp(pcszStartupAccount,TEXT("NT AUTHORITY\\NetworkService")) ) return g_strNetworkService; return pcszStartupAccount; } // Service_PszMapStartupAccountToName() ///////////////////////////////////////////////////////////////////// // Service_FGetServiceButtonStatus() // // Query the service control manager database and fill in // array of flags indicating if the action is enabled. // rgfEnableButton[0] = TRUE; => Button 'start' is enabled // rgfEnableButton[0] = FALSE; => Button 'start' is disabled // // INTERFACE NOTES // The length of the array must be length iServiceActionMax (or larger). // Each representing start, stop, pause, resume and restart respectively. // // Return TRUE if the service status was queried successfully, otherwise FALSE. // BOOL Service_FGetServiceButtonStatus( SC_HANDLE hScManager, // IN: Handle of service control manager database CONST TCHAR * pszServiceName, // IN: Name of service BOOL rgfEnableButton[iServiceActionMax], // OUT: Array of flags to enable the buttons DWORD * pdwCurrentState, // OUT: Optional: Current state of service BOOL fSilentError) // IN: TRUE => Do not display any error message to user { Endorse(hScManager == NULL); Assert(pszServiceName != NULL); Assert(rgfEnableButton != NULL); Endorse(pdwCurrentState == NULL); // Open service to get its status BOOL fSuccess = TRUE; SC_HANDLE hService; SERVICE_STATUS ss; DWORD cbBytesNeeded; DWORD dwErr; ::ZeroMemory(OUT rgfEnableButton, iServiceActionMax * sizeof(BOOL)); if (pdwCurrentState != NULL) *pdwCurrentState = 0; if (hScManager == NULL || pszServiceName[0] == '\0') return FALSE; hService = ::OpenService( hScManager, pszServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); if (hService == NULL) { dwErr = ::GetLastError(); Assert(dwErr != ERROR_SUCCESS); TRACE2("Failed to open service %s. err=%u.\n", pszServiceName, dwErr); if (!fSilentError) DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr); return FALSE; } if (!::QueryServiceStatus(hService, OUT &ss)) { dwErr = ::GetLastError(); Assert(dwErr != ERROR_SUCCESS); TRACE2("::QueryServiceStatus(Service=%s) failed. err=%u.\n", pszServiceName, dwErr); if (!fSilentError) DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr); fSuccess = FALSE; } else { // Determine which menu items should be grayed if (pdwCurrentState != NULL) *pdwCurrentState = ss.dwCurrentState; switch (ss.dwCurrentState) { default: Assert(FALSE && "Illegal service status state."); case SERVICE_START_PENDING: case SERVICE_STOP_PENDING: case SERVICE_PAUSE_PENDING: case SERVICE_CONTINUE_PENDING: break; case SERVICE_STOPPED: QUERY_SERVICE_CONFIG qsc; ZeroMemory( &qsc, sizeof(qsc) ); qsc.dwStartType = (DWORD)-1; // JonN-2002/04/04-544089 handle long DisplayName value // If this fails, don't enable the Start button // // JonN-2002/04/29 fix regression // Even if QueryServiceConfig fails, it still fills in the // fixed-size area if it can. So ignore the error in this case. (void) ::QueryServiceConfig( hService, OUT &qsc, sizeof(qsc), OUT IGNORED &cbBytesNeeded); Report(qsc.dwStartType != (DWORD)-1); if (qsc.dwStartType != SERVICE_DISABLED) { rgfEnableButton[iServiceActionStart] = TRUE; // Enable 'Start' menu item } break; case SERVICE_RUNNING: // Some services are not allowed to be stoped and/or paused if (ss.dwControlsAccepted & SERVICE_ACCEPT_STOP) { rgfEnableButton[iServiceActionStop] = TRUE; // Enable 'Stop' menu item } if (ss.dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) { rgfEnableButton[iServiceActionPause] = TRUE; // Enable 'Pause' menu item } break; case SERVICE_PAUSED: if (ss.dwControlsAccepted & SERVICE_ACCEPT_STOP) { rgfEnableButton[iServiceActionStop] = TRUE; // Enable 'Stop' menu item } rgfEnableButton[iServiceActionResume] = TRUE; // Enable 'Resume' menu item break; } // switch } // if...else // A 'Restart' has the same characteristics as a 'Stop' rgfEnableButton[iServiceActionRestart] = rgfEnableButton[iServiceActionStop]; (void)::CloseServiceHandle(hService); return fSuccess; } // Service_FGetServiceButtonStatus() ///////////////////////////////////////////////////////////////////// // Service_SplitCommandLine() // // Split a string into two strings. // Very similar to PchParseCommandLine() but uses CString objects. // void Service_SplitCommandLine( LPCTSTR pszFullCommand, // IN: Full command line CString * pstrBinaryPath, // OUT: Path of the executable binary CString * pstrParameters, // OUT: Parameters for the executable BOOL * pfAbend) // OUT: Optional: Search for string "/fail=%1%" { Assert(pszFullCommand != NULL); Assert(pstrBinaryPath != NULL); Assert(pstrParameters != NULL); Endorse(pfAbend == NULL); // Since there is no upper bound on the command // arguments, we need to allocate memory for // its processing. TCHAR * paszCommandT; // Temporary buffer TCHAR * pszCommandArguments; INT cchMemAlloc; // Number of bytes to allocate cchMemAlloc = lstrlen(pszFullCommand) + 1; paszCommandT = new TCHAR[cchMemAlloc]; paszCommandT[0] = '\0'; // Just in case pszCommandArguments = PchParseCommandLine( IN pszFullCommand, OUT paszCommandT, cchMemAlloc); *pstrBinaryPath = paszCommandT; if (pfAbend != NULL) { INT cStringSubstitutions; // Number of string substitutions // Find out if the string contains "/fail=%1%" // 580255-2002/03/18 JonN fixed Str_SubstituteStrStr buffer overrun cStringSubstitutions = Str_RemoveSubStr( IN OUT pszCommandArguments, IN szAbend ); Report((cStringSubstitutions == 0 || cStringSubstitutions == 1) && "INFO: Multiple substitutions will be consolidated."); *pfAbend = cStringSubstitutions != 0; } *pstrParameters = pszCommandArguments; TrimString(*pstrParameters); delete paszCommandT; } // Service_SplitCommandLine() ///////////////////////////////////////////////////////////////////// // Service_UnSplitCommandLine() // // Just do the opposite of Service_SplitCommandLine(). // Combine the executable path and its arguments into a single string. // void Service_UnSplitCommandLine( CString * pstrFullCommand, // OUT: Full command line LPCTSTR pszBinaryPath, // IN: Path of the executable binary LPCTSTR pszParameters) // IN: Parameters for the executable { Assert(pstrFullCommand != NULL); Assert(pszBinaryPath != NULL); Assert(pszParameters != NULL); TCHAR * psz; psz = pstrFullCommand->GetBuffer(lstrlen(pszBinaryPath) + lstrlen(pszParameters) + 32); // Build a string with the binary path surrounded by quotes wsprintf(OUT psz, L"\"%s\" %s", pszBinaryPath, pszParameters); pstrFullCommand->ReleaseBuffer(); } // Service_UnSplitCommandLine() ///////////////////////////////////////////////////////////////////// // LoadSystemString() // // Load a string from system's resources. This function will check if // the string Id can be located in netmsg.dll before attempting to // load the string from the 'system resource'. // If string cannot be loaded, *ppaszBuffer is set to NULL. // // ISSUE-2002/03/18-JonN The above comment is inaccurate. If the string // cannot be loaded from netmsg.dll, it does not fall back to system. // // RETURN // Pointer to allocated string and number of characters put // into *ppaszBuffer. // // INTERFACE NOTES // Caller must call LocalFree(*ppaszBuffer) when done with the string. // // HISTORY // 96.10.21 t-danmo Copied from net\ui\common\src\string\string\strload.cxx. // /* JonN-2002/03/18-JonN This function is not used DWORD LoadSystemString( UINT wIdString, // IN: String Id. Typically error code from GetLastError(). LPTSTR * ppaszBuffer) // OUT: Address of pointer to allocated string. { Assert(ppaszBuffer != NULL); UINT cch; HMODULE hModule = NULL; DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK; if ((wIdString >= MIN_LANMAN_MESSAGE_ID) && (wIdString <= MAX_LANMAN_MESSAGE_ID)) { // Network Errors dwFlags |= FORMAT_MESSAGE_FROM_HMODULE; hModule = ::LoadLibrary(_T("netmsg.dll")); if (hModule == NULL) { TRACE1("LoadLibrary(\"netmsg.dll\") failed. err=%u.\n", GetLastError()); Report("Unable to get module handle for netmsg.dll"); } } else { // Other system errors dwFlags |= FORMAT_MESSAGE_FROM_SYSTEM; } *ppaszBuffer = NULL; // Just in case cch = ::FormatMessage( dwFlags, hModule, wIdString, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language OUT (LPTSTR)ppaszBuffer, // Buffer will be allocated by FormatMessage() 0, NULL); Report((cch > 0) && "FormatMessage() returned an empty string"); if (hModule != NULL) { VERIFY(FreeLibrary(hModule)); } return cch; } // LoadSystemString() */ ///////////////////////////////////////////////////////////////////// // GetMsgHelper() // // This function will retrieve the error msg if dwErr is specified, // load resource string if specified, and format the string with // the error msg and other optional arguments. // // HRESULT GetMsgHelper( OUT CString& strMsg,// OUT: the message DWORD dwErr, // IN: Error code from GetLastError() UINT wIdString, // IN: String ID va_list* parglist // IN: OPTIONAL arguments ) { if (!dwErr && !wIdString) return E_INVALIDARG; TCHAR *pszMsgResourceString = NULL; TCHAR *pszT = L""; // // retrieve error msg // CString strErrorMessage; if (dwErr != 0) { GetErrorMessage(dwErr, strErrorMessage); pszT = (LPTSTR)(LPCTSTR)strErrorMessage; } // // load string resource, and format it with the error msg and // other optional arguments // if (wIdString == 0) { strMsg = pszT; } else { pszMsgResourceString = PaszLoadStringPrintf(wIdString, *parglist); if (dwErr == 0) strMsg = pszMsgResourceString; else if ((HRESULT)dwErr < 0) LoadStringPrintf(IDS_sus_ERROR_HR, OUT &strMsg, pszMsgResourceString, dwErr, pszT); else LoadStringPrintf(IDS_sus_ERROR, OUT &strMsg, pszMsgResourceString, dwErr, pszT); } if (pszMsgResourceString) LocalFree(pszMsgResourceString); return S_OK; } // GetMsgHelper() ///////////////////////////////////////////////////////////////////// // GetMsg() // // This function will call GetMsgHelp to retrieve the error msg // if dwErr is specified, load resource string if specified, and // format the string with the error msg and other optional arguments. // // void GetMsg( OUT CString& strMsg,// OUT: the message DWORD dwErr, // IN: Error code from GetLastError() UINT wIdString, // IN: String resource Id ...) // IN: Optional arguments { va_list arglist; va_start(arglist, wIdString); HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist); if (FAILED(hr)) strMsg.Format(_T("0x%x"), hr); va_end(arglist); } // GetMsg() ///////////////////////////////////////////////////////////////////// // DoErrMsgBox() // // Display a message box for the error code. This function will // load the error message from the system resource and append // the optional string (if any) // // EXAMPLE // DoErrMsgBox(GetActiveWindow(), MB_OK, GetLastError(), IDS_s_FILE_READ_ERROR, L"foo.txt"); // INT DoErrMsgBoxHelper( HWND hwndParent, // IN: Parent of the dialog box UINT uType, // IN: style of message box DWORD dwErr, // IN: Error code from GetLastError() UINT wIdString, // IN: String resource Id bool fServicesSnapin, // IN: Is this filemgmt or svcmgmt? va_list& arglist) // IN: Optional arguments { // // get string and the error msg // CString strMsg; HRESULT hr = GetMsgHelper(strMsg, dwErr, wIdString, &arglist); if (FAILED(hr)) strMsg.Format(_T("0x%x"), hr); // // Load the caption // CString strCaption; strCaption.LoadString( (fServicesSnapin) ? IDS_CAPTION_SERVICES : IDS_CAPTION_FILEMGMT); // // Display the message. // CThemeContextActivator activator;; return MessageBox(hwndParent, strMsg, strCaption, uType); } // DoErrMsgBox() INT DoErrMsgBox( HWND hwndParent, // IN: Parent of the dialog box UINT uType, // IN: style of message box DWORD dwErr, // IN: Error code from GetLastError() UINT wIdString, // IN: String resource Id ...) // IN: Optional arguments { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // get string and the error msg // va_list arglist; va_start(arglist, wIdString); INT retval = DoErrMsgBoxHelper( hwndParent, uType, dwErr, wIdString, false, arglist ); va_end(arglist); return retval; } // DoErrMsgBox() // // JonN 3/5/01 4635 // Services Snapin - String length error dialog title shouldn't be "File Service Management" // INT DoServicesErrMsgBox( HWND hwndParent, // IN: Parent of the dialog box UINT uType, // IN: style of message box DWORD dwErr, // IN: Error code from GetLastError() UINT wIdString, // IN: String resource Id ...) // IN: Optional arguments { // // get string and the error msg // va_list arglist; va_start(arglist, wIdString); INT retval = DoErrMsgBoxHelper( hwndParent, uType, dwErr, wIdString, true, arglist ); va_end(arglist); return retval; } //+-------------------------------------------------------------------------- // // Function: InitObjectPickerForUsers // // Synopsis: Call IDsObjectPicker::Initialize with arguments that will // set it to allow the user to pick one user. // // Arguments: [pDsObjectPicker] - object picker interface instance // // Returns: Result of calling IDsObjectPicker::Initialize. // // History: 10-14-1998 DavidMun Sample code InitObjectPickerForGroups // 10-14-1998 JonN Changed to InitObjectPickerForUsers // 11-11-2000 JonN 188203 support LocalService/NetworkService // //--------------------------------------------------------------------------- // CODEWORK do I want to allow USER_ENTERED? HRESULT InitObjectPickerForUsers( IDsObjectPicker *pDsObjectPicker, LPCTSTR pszServerName) { // // Prepare to initialize the object picker. // Set up the array of scope initializer structures. // static const int SCOPE_INIT_COUNT = 5; DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT]; ZeroMemory(aScopeInit, sizeof(aScopeInit)); // // Target computer scope. This adds a "Look In" entry for the // target computer. Computer scopes are always treated as // downlevel (i.e., they use the WinNT provider). // aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[0].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER; aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE | DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT; // JonN 11/14/00 188203 support LocalService/NetworkService aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS | DSOP_DOWNLEVEL_FILTER_LOCAL_SERVICE | DSOP_DOWNLEVEL_FILTER_NETWORK_SERVICE; // // The domain to which the target computer is joined. Note we're // combining two scope types into flType here for convenience. // aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[1].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN; aScopeInit[1].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT; aScopeInit[1].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS; aScopeInit[1].FilterFlags.Uplevel.flMixedModeOnly = DSOP_FILTER_USERS; aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS; // // The domains in the same forest (enterprise) as the domain to which // the target machine is joined. Note these can only be DS-aware // aScopeInit[2].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[2].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN; aScopeInit[2].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT; aScopeInit[2].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS; aScopeInit[2].FilterFlags.Uplevel.flMixedModeOnly = DSOP_FILTER_USERS; // // Domains external to the enterprise but trusted directly by the // domain to which the target machine is joined. // // If the target machine is joined to an NT4 domain, only the // external downlevel domain scope applies, and it will cause // all domains trusted by the joined domain to appear. // aScopeInit[3].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[3].flType = DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN | DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN; aScopeInit[3].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT; aScopeInit[3].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS; aScopeInit[3].FilterFlags.Uplevel.flMixedModeOnly = DSOP_FILTER_USERS; aScopeInit[3].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS; // // The Global Catalog // aScopeInit[4].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[4].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT; aScopeInit[4].flType = DSOP_SCOPE_TYPE_GLOBAL_CATALOG; // Only native mode applies to gc scope. aScopeInit[4].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_USERS; // // Put the scope init array into the object picker init array // DSOP_INIT_INFO InitInfo; ZeroMemory(&InitInfo, sizeof(InitInfo)); InitInfo.cbSize = sizeof(InitInfo); // // The pwzTargetComputer member allows the object picker to be // retargetted to a different computer. It will behave as if it // were being run ON THAT COMPUTER. // InitInfo.pwzTargetComputer = pszServerName; // NULL == local machine // InitInfo.pwzTargetComputer = NULL; // NULL == local machine InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT; InitInfo.aDsScopeInfos = aScopeInit; // JonN 11/14/00 188203 support LocalService/NetworkService static PCWSTR g_pszObjectSid = L"objectSid"; InitInfo.cAttributesToFetch = 1; InitInfo.apwzAttributeNames = &g_pszObjectSid; // // Note object picker makes its own copy of InitInfo. Also note // that Initialize may be called multiple times, last call wins. // HRESULT hr = pDsObjectPicker->Initialize(&InitInfo); ASSERT( SUCCEEDED(hr) ); return hr; } // InitObjectPickerForUsers //+-------------------------------------------------------------------------- // // Function: ExtractADsPathAndUPN // // Synopsis: Retrieve the selected username from the data object // created by the object picker. // // Arguments: [pdo] - data object returned by object picker // // History: 10-14-1998 DavidMun Sample code ProcessSelectedObjects // 10-14-1998 JonN Changed to ExtractADsPath // 01-25-1999 JonN Added pflScopeType parameter // 03-16-1999 JonN Changed to ExtractADsPathAndUPN // 11-14-2000 JonN Added svarrefObjectSid for 188203 // //--------------------------------------------------------------------------- UINT g_cfDsObjectPicker = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST); HRESULT ExtractADsPathAndUPN( IN IDataObject *pdo, OUT CString& strrefADsPath, OUT CString& strrefUPN, OUT CComVariant& svarrefObjectSid, OUT ULONG *pflScopeType) { if (NULL == pdo) return E_POINTER; HRESULT hr = S_OK; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL, NULL }; FORMATETC formatetc = { (CLIPFORMAT)g_cfDsObjectPicker, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; bool fGotStgMedium = false; do { hr = pdo->GetData(&formatetc, &stgmedium); if (FAILED(hr)) { ASSERT(FALSE); break; } fGotStgMedium = true; PDS_SELECTION_LIST pDsSelList = (PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal); if ( NULL == pDsSelList || 1 != pDsSelList->cItems ) { ASSERT(FALSE); hr = E_FAIL; break; } DS_SELECTION& sel = pDsSelList->aDsSelection[0]; strrefADsPath = sel.pwzADsPath; strrefUPN = sel.pwzUPN; if ( sel.pvarFetchedAttributes ) svarrefObjectSid = sel.pvarFetchedAttributes[0]; if (NULL != pflScopeType) *pflScopeType = pDsSelList->aDsSelection[0].flScopeType; GlobalUnlock(stgmedium.hGlobal); } while (0); if (fGotStgMedium) { ReleaseStgMedium(&stgmedium); } return hr; } ///////////////////////////////////////////////////////////////////// // UiGetUser() // // Invoke a user picker dialog. // // Return TRUE iff an account was selected. // // HISTORY // 96.10.12 t-danmo Creation. Inspired from function GetUser() located // at \nt\private\windows\shell\security\aclui\misc.cpp. // 96.10.30 t-danmo Added/modified comments. // 98.03.17 jonn Modified to use User/Group Picker // 98.10.20 jonn Modified to use updated Object Picker interfaces // //+-------------------------------------------------------------------------- // // Function: ExtractDomainUserString // // Synopsis: Converts an ADspath to the format needed by Service Controller // // History: 10-14-1998 JonN Created // 01-25-1999 JonN added flScopeType parameter // //--------------------------------------------------------------------------- HRESULT ExtractDomainUserString( IN LPCTSTR pwzADsPath, IN ULONG flScopeType, IN OUT CString& strrefDomainUser) { HRESULT hr = S_OK; CComPtr spIADsPathname; hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spIADsPathname); RETURN_HR_IF_FAIL; hr = spIADsPathname->Set( const_cast(pwzADsPath), ADS_SETTYPE_FULL ); RETURN_HR_IF_FAIL; CComBSTR sbstrUser; hr = spIADsPathname->GetElement( 0, &sbstrUser ); RETURN_HR_IF_FAIL; CComBSTR sbstrDomain = OLESTR("."); if (DSOP_SCOPE_TYPE_TARGET_COMPUTER != flScopeType) { long lnNumPathElements = 0; hr = spIADsPathname->GetNumElements( &lnNumPathElements ); RETURN_FALSE_IF_FAIL; switch (lnNumPathElements) { case 1: hr = spIADsPathname->Retrieve( ADS_FORMAT_SERVER, &sbstrDomain ); RETURN_HR_IF_FAIL; break; case 2: hr = spIADsPathname->GetElement( 1, &sbstrDomain ); RETURN_HR_IF_FAIL; break; default: ASSERT(FALSE); return E_FAIL; } } strrefDomainUser.Format(L"%s\\%s", sbstrDomain, sbstrUser); return hr; } // ExtractDomainUserString BOOL UiGetUser( HWND hwndOwner, // IN: Owner window BOOL /*fIsContainer*/, // IN: TRUE if invoked for a container LPCTSTR pszServerName, // IN: Initial target machine name OUT CString& strrefUser) // IN: Allocated buffer containing the user details { HRESULT hr = S_OK; CComPtr spDsObjectPicker; hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (PVOID *)&spDsObjectPicker); RETURN_FALSE_IF_FAIL; ASSERT( !!spDsObjectPicker ); hr = InitObjectPickerForUsers(spDsObjectPicker, pszServerName); RETURN_FALSE_IF_FAIL; CComPtr spDataObject; hr = spDsObjectPicker->InvokeDialog(hwndOwner, &spDataObject); RETURN_FALSE_IF_FAIL; if (S_FALSE == hr) return FALSE; // user cancelled ASSERT( !!spDataObject ); CString strADsPath; ULONG flScopeType = DSOP_SCOPE_TYPE_TARGET_COMPUTER; CComVariant svarObjectSid; hr = ExtractADsPathAndUPN( spDataObject, strADsPath, strrefUser, svarObjectSid, &flScopeType ); RETURN_FALSE_IF_FAIL; // JonN 11/15/00 188203 check for LocalService/NetworkService if (svarObjectSid.vt == (VT_ARRAY|VT_UI1)) { PSID pSid = svarObjectSid.parray->pvData; if ( IsWellKnownSid(pSid, WinLocalServiceSid) ) { strrefUser = TEXT("NT AUTHORITY\\LocalService"); return TRUE; } else if ( IsWellKnownSid(pSid, WinNetworkServiceSid) ) { strrefUser = TEXT("NT AUTHORITY\\NetworkService"); return TRUE; } } if (strrefUser.IsEmpty()) { if (strADsPath.IsEmpty()) { ASSERT(FALSE); return FALSE; } hr = ExtractDomainUserString( strADsPath, flScopeType, strrefUser ); RETURN_FALSE_IF_FAIL; } return TRUE; } // UiGetUser() ///////////////////////////////////////////////////////////////////// // DoHelp() // // This routine handles context help for the WM_HELP message. // // The return value is always TRUE. // BOOL DoHelp( LPARAM lParam, // Pointer to HELPINFO structure const DWORD rgzHelpIDs[]) // Array of HelpIDs { Assert(rgzHelpIDs != NULL); const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; if (pHelpInfo != NULL) { if (pHelpInfo->iContextType == HELPINFO_WINDOW) { const HWND hwnd = (HWND)pHelpInfo->hItemHandle; Assert(IsWindow(hwnd)); // Display context help for a control WinHelp( hwnd, g_szHelpFileFilemgmt, HELP_WM_HELP, (DWORD_PTR)rgzHelpIDs); } } return TRUE; } // DoHelp() ///////////////////////////////////////////////////////////////////// // DoContextHelp() // // This routine handles context help for the WM_CONTEXTMENU message. // // The return value is always TRUE. // BOOL DoContextHelp( WPARAM wParam, // Window requesting help const DWORD rgzHelpIDs[]) // Array of HelpIDs { const HWND hwnd = (HWND)wParam; Assert(IsWindow(hwnd)); Assert(rgzHelpIDs != NULL); WinHelp(hwnd, g_szHelpFileFilemgmt, HELP_CONTEXTMENU, (DWORD_PTR)rgzHelpIDs); return TRUE; } // DoContextHelp()