///////////////////////////////////////////////////////////////////// // Chooser.cpp // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997-1998 // // // Dialog to choose a machine name. // // PURPOSE // (Important -- Please Read) // This code was written for you to save you time. // What you have to do is to copy all the files from the // snapin\chooser\ directory into your project (you may add // \nt\private\admin\snapin\chooser\ to your include directory if // you prefer not copying the code). // If you decide to copy the code to your project, please send mail // to Dan Morin (T-DanM) and cc to Jon Newman (JonN) so we can // mail you when we have updates available. The next update will // be the "Browse" button to select a machine name. // // // DYNALOADED LIBRARIES // $(SDK_LIB_PATH)\shell32.lib // CommandLineToArgvW() // $(SDK_LIB_PATH)\netapi32.lib // I_NetName*() // // EXTRA INFO // If you don't know how this works, take a look at the inheritance tree // in chooser.h. Then, take a look at the existing code that inherit and/or // uses CChooseMachinePropPage. // // HISTORY // 13-May-1997 t-danm Creation. // 23-May-1997 t-danm Checkin into public tree. Comments updates. // 25-May-1997 t-danm Added MMCPropPageCallback(). // 31-Oct-1997 mattt Added dynaload, fixed user logic // ///////////////////////////////////////////////////////////////////// #include "chooser.h" #include // NET_API_STATUS #include // NERR_Success #include // I_NetNameValidate(), I_NetNameCanonicalize(). Found in \nt\private\net\inc. #include #include "stdutils.h" // IsLocalComputername #include // NetServerGetInfo JonN 2002/04/08 585301 #include // NetApiBufferFree JonN 2002/04/08 585301 #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE #define THIS_FILE __FILE__ #endif #ifndef INOUT // The following defines are found in \nt\private\admin\snapin\filemgmt\stdafx.h #define INOUT #define Endorse(f) // Dummy macro #define LENGTH(x) (sizeof(x)/sizeof(x[0])) #define Assert(f) ASSERT(f) #endif ///////////////////////////////////////////////////////////////////// // CanonicalizeComputername() // // Function to validate the computer name and optionally // add the \\ at beginning of machine name. // typedef NET_API_STATUS NET_API_FUNCTION INETNAMEVALIDATE( LPTSTR ServerName, LPTSTR Name, DWORD NameType, DWORD Flags); typedef NET_API_STATUS NET_API_FUNCTION INETNAMECANONICALIZE( LPTSTR ServerName, LPTSTR Name, LPTSTR Outbuf, DWORD OutbufLen, DWORD NameType, DWORD Flags); NET_API_STATUS CanonicalizeComputername( INOUT CString& rstrMachineName, IN BOOL fAddWackWack = TRUE) // TRUE => Add the \\ at beginning of name { NET_API_STATUS err; LPTSTR pszTemp; rstrMachineName.TrimLeft(); rstrMachineName.TrimRight(); if ( rstrMachineName.IsEmpty() ) return NERR_Success; if ( 2 <= rstrMachineName.GetLength() && _T('\\') == rstrMachineName[0] && _T('\\') == rstrMachineName[1] ) { // Remove the \\ at the beginning of name CString strShorter = rstrMachineName.Right( rstrMachineName.GetLength() - 2 ); rstrMachineName = strShorter; } // DYNALOAD NETAPI32.dll HINSTANCE hNetApiDll = NULL; INETNAMEVALIDATE *pfnValidate; INETNAMECANONICALIZE *pfnCanonicalize; if (NULL == (hNetApiDll = LoadLibrary(L"netapi32.dll"))) return GetLastError(); if (NULL == (pfnValidate = (INETNAMEVALIDATE*)GetProcAddress(hNetApiDll, "I_NetNameValidate")) ) { err = GetLastError(); goto Ret; } if (NULL == (pfnCanonicalize = (INETNAMECANONICALIZE*)GetProcAddress(hNetApiDll, "I_NetNameCanonicalize")) ) { err = GetLastError(); goto Ret; } err = pfnValidate( NULL, const_cast((LPCTSTR)rstrMachineName), NAMETYPE_COMPUTER, 0L ); if (NERR_Success != err) goto Ret; if ( MAX_PATH <= rstrMachineName.GetLength() ) { err = ERROR_INVALID_NAME; goto Ret; } pszTemp = (LPTSTR)alloca( MAX_PATH*sizeof(TCHAR) ); ASSERT( NULL != pszTemp ); // 2002/03/28-JonN CliffV confirms that this API takes a bytecount err = pfnCanonicalize( NULL, IN const_cast((LPCTSTR)rstrMachineName), OUT pszTemp, MAX_PATH*sizeof(TCHAR), NAMETYPE_COMPUTER, 0L ); if (NERR_Success != err) goto Ret; if (fAddWackWack && pszTemp[0] != '\0') { // Add the \\ at beginning of name rstrMachineName = _T("\\\\"); rstrMachineName += pszTemp; } else { rstrMachineName = pszTemp; } err = NERR_Success; Ret: if (hNetApiDll) FreeLibrary(hNetApiDll); return err; } // CanonicalizeComputername() ///////////////////////////////////////////////// // Machine name override const TCHAR szOverrideCommandLineEquals[] = _T("/Computer="); // Not subject to localization const TCHAR szOverrideCommandLineColon[] = _T("/Computer:"); // Not subject to localization const TCHAR szLocalMachine[] = _T("LocalMachine"); // Not subject to localization const int cchOverrideCommandLine = LENGTH(szOverrideCommandLineEquals) - 1; // Assumption: both command line strings are the same length static CString g_strOverrideMachineName; static LPCTSTR g_pszOverrideMachineName; // NULL => No override provided, "" => LocalMachine /////////////////////////////////////////////////////////////////////////////// // PchGetMachineNameOverride() // // Parse the command line arguments and return a pointer to the // machine name override if present. // // INTERFACE NOTES // If the machine name is other than local machine, the machine name // will have the \\ at the beginning of its name. // // RETURN // - Return NULL if no override (ie, no command line override) // - Return pointer to empty string if override is "local machine" // - Otherwise return pointer to machine name override with \\ at beginning. // typedef LPWSTR * COMMANDLINETOARGVW( LPCWSTR lpCmdLine, // pointer to a command-line string int *pNumArgs); // pointer to a variable that receives the argument count LPCTSTR PchGetMachineNameOverride () { static BOOL fAlreadyInitialized = FALSE; if (fAlreadyInitialized) { // We already have parsed the command line return g_pszOverrideMachineName; } fAlreadyInitialized = TRUE; ASSERT(g_pszOverrideMachineName == NULL); LPCWSTR * lpServiceArgVectors = 0; // Array of pointers to string int cArgs = 0; // Count of arguments // DYNALOAD Shell32 { HINSTANCE hShellDll = LoadLibrary (L"shell32.dll"); if ( !hShellDll ) return NULL; COMMANDLINETOARGVW *pfnCmdToArgs = (COMMANDLINETOARGVW*) GetProcAddress (hShellDll, "CommandLineToArgvW"); if ( !pfnCmdToArgs ) { VERIFY (FreeLibrary (hShellDll)); return NULL; } lpServiceArgVectors = (LPCWSTR *) pfnCmdToArgs (GetCommandLineW (), OUT &cArgs); VERIFY (FreeLibrary (hShellDll)); pfnCmdToArgs = NULL; } if (lpServiceArgVectors == NULL) return NULL; // ISSUE-2002/03/28-JonN I wouldn't mind being a little more cautious here // by checking the overall length of lpServiceArgVectors and the string-ness // of its components. for (int i = 1; i < cArgs; i++) { Assert(lpServiceArgVectors[i] != NULL); CString str = lpServiceArgVectors[i]; // Copy the string str = str.Left(cchOverrideCommandLine); if (0 != str.CompareNoCase(szOverrideCommandLineEquals) && 0 != str.CompareNoCase(szOverrideCommandLineColon) ) { continue; } str = lpServiceArgVectors[i] + cchOverrideCommandLine; if (0 == str.CompareNoCase(szLocalMachine)) str.Empty(); if (NERR_Success != CanonicalizeComputername(INOUT str)) continue; g_strOverrideMachineName = str; // Copy the argument into the global string g_pszOverrideMachineName = g_strOverrideMachineName; } LocalFree(lpServiceArgVectors); return g_pszOverrideMachineName; } // PchGetMachineNameOverride() ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CAutoDeletePropPage, CPropertyPage) //{{AFX_MSG_MAP(CAutoDeletePropPage) ON_MESSAGE(WM_HELP, OnHelp) ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////// // Constructor CAutoDeletePropPage::CAutoDeletePropPage(UINT uIDD) : CPropertyPage(uIDD) { m_prgzHelpIDs = NULL; m_autodeleteStuff.cWizPages = 1; // Number of pages in wizard m_autodeleteStuff.pfnOriginalPropSheetPageProc = m_psp.pfnCallback; m_psp.pfnCallback = S_PropSheetPageProc; m_psp.lParam = reinterpret_cast(this); // The following line is to enable MFC property pages to run under MMC. MMCPropPageCallback(INOUT &m_psp); } CAutoDeletePropPage::~CAutoDeletePropPage() { } ///////////////////////////////////////////////////////////////////// void CAutoDeletePropPage::SetCaption(LPCTSTR pszCaption) { m_strCaption = pszCaption; // Copy the caption m_psp.pszTitle = m_strCaption; // Set the title m_psp.dwFlags |= PSP_USETITLE; } ///////////////////////////////////////////////////////////////////// void CAutoDeletePropPage::SetCaption(UINT uStringID) { VERIFY(m_strCaption.LoadString(uStringID)); SetCaption(m_strCaption); } ///////////////////////////////////////////////////////////////////// void CAutoDeletePropPage::SetHelp(LPCTSTR szHelpFile, const DWORD rgzHelpIDs[]) { Endorse(szHelpFile == NULL); // TRUE => No help file supplied (meaning no help) Endorse(rgzHelpIDs == NULL); // TRUE => No help at all m_strHelpFile = szHelpFile; m_prgzHelpIDs = rgzHelpIDs; } ///////////////////////////////////////////////////////////////////// void CAutoDeletePropPage::EnableDlgItem(INT nIdDlgItem, BOOL fEnable) { Assert(IsWindow(::GetDlgItem(m_hWnd, nIdDlgItem))); ::EnableWindow(::GetDlgItem(m_hWnd, nIdDlgItem), fEnable); } ///////////////////////////////////////////////////////////////////// BOOL CAutoDeletePropPage::OnSetActive() { HWND hwndParent = ::GetParent(m_hWnd); Assert(IsWindow(hwndParent)); ::PropSheet_SetWizButtons(hwndParent, PSWIZB_FINISH); return CPropertyPage::OnSetActive(); } ///////////////////////////////////////////////////////////////////// BOOL CAutoDeletePropPage::OnHelp(WPARAM /*wParam*/, LPARAM lParam) { if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty()) return TRUE; const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; if (pHelpInfo != NULL && pHelpInfo->iContextType == HELPINFO_WINDOW) { // Display context help for a control ::WinHelp((HWND)pHelpInfo->hItemHandle, m_strHelpFile, HELP_WM_HELP, (DWORD_PTR)m_prgzHelpIDs); } return TRUE; } ///////////////////////////////////////////////////////////////////// BOOL CAutoDeletePropPage::OnContextHelp(WPARAM wParam, LPARAM /*lParam*/) { if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty()) return TRUE; Assert(IsWindow((HWND)wParam)); ::WinHelp((HWND)wParam, m_strHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)m_prgzHelpIDs); return TRUE; } ///////////////////////////////////////////////////////////////////// // S_PropSheetPageProc() // // Static member function used to delete the CAutoDeletePropPage object // when wizard terminates // UINT CALLBACK CAutoDeletePropPage::S_PropSheetPageProc( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { Assert(ppsp != NULL); CChooseMachinePropPage * pThis; pThis = reinterpret_cast(ppsp->lParam); Assert(pThis != NULL); switch (uMsg) { case PSPCB_RELEASE: if (--(pThis->m_autodeleteStuff.cWizPages) <= 0) { // Remember callback on stack since "this" will be deleted LPFNPSPCALLBACK pfnOrig = pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc; delete pThis; return (pfnOrig)(hwnd, uMsg, ppsp); } break; case PSPCB_CREATE: // do not increase refcount, PSPCB_CREATE may or may not be called // depending on whether the page was created. PSPCB_RELEASE can be // depended upon to be called exactly once per page however. break; } // switch return (pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc)(hwnd, uMsg, ppsp); } // CAutoDeletePropPage::S_PropSheetPageProc() ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CChooseMachinePropPage, CAutoDeletePropPage) //{{AFX_MSG_MAP(CChooseMachinePropPage) ON_BN_CLICKED(IDC_CHOOSER_RADIO_LOCAL_MACHINE, OnRadioLocalMachine) ON_BN_CLICKED(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, OnRadioSpecificMachine) ON_BN_CLICKED(IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, OnChooserButtonBrowseMachinenames) //}}AFX_MSG_MAP END_MESSAGE_MAP() #ifdef _DEBUG static void AssertValidDialogTemplate(HWND hwnd) { ASSERT(::IsWindow(hwnd)); // Mandatory controls for a valid dialog template static const UINT rgzidDialogControl[] = { IDC_CHOOSER_RADIO_LOCAL_MACHINE, IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, IDC_CHOOSER_EDIT_MACHINE_NAME, 0 }; for (int i = 0; rgzidDialogControl[i] != 0; i++) { ASSERT(NULL != GetDlgItem(hwnd, rgzidDialogControl[i]) && "Control ID not found in dialog template."); } } // AssertValidDialogTemplate() #else #define AssertValidDialogTemplate(hwnd) #endif // ~_DEBUG ///////////////////////////////////////////////////////////////////// // Constructor CChooseMachinePropPage::CChooseMachinePropPage(UINT uIDD) : CAutoDeletePropPage(uIDD) { // ISSUE-2002/03/28-JonN initialize m_hwndCheckboxOverride m_fIsRadioLocalMachine = TRUE; m_fAllowOverrideMachineName = FALSE; m_pfAllowOverrideMachineNameOut = NULL; m_pstrMachineNameOut = NULL; m_pstrMachineNameEffectiveOut = NULL; } ///////////////////////////////////////////////////////////////////// CChooseMachinePropPage::~CChooseMachinePropPage() { } ///////////////////////////////////////////////////////////////////// // Load the initial state of CChooseMachinePropPage void CChooseMachinePropPage::InitMachineName(LPCTSTR pszMachineName) { Endorse(pszMachineName == NULL); m_strMachineName = pszMachineName; m_fIsRadioLocalMachine = m_strMachineName.IsEmpty(); } ///////////////////////////////////////////////////////////////////// // SetOutputBuffers() // // - Set the pointer to the CString object to store the machine name. // - Set the pointer to the boolean flag for command line override. // - Set the pointer pointer to store the overriden machine name. // void CChooseMachinePropPage::SetOutputBuffers( OUT CString * pstrMachineNamePersist, // Machine name the user typed. Empty string == local machine. OUT BOOL * pfAllowOverrideMachineName, OUT CString * pstrMachineNameEffective) { Assert(pstrMachineNamePersist != NULL && "Invalid output buffer"); Endorse(pfAllowOverrideMachineName == NULL); // TRUE => Do not want to support override from command line Endorse(pstrMachineNameEffective == NULL); // TRUE => Don't care of override m_pstrMachineNameOut = pstrMachineNamePersist; m_pfAllowOverrideMachineNameOut = pfAllowOverrideMachineName; m_pstrMachineNameEffectiveOut = pstrMachineNameEffective; } ///////////////////////////////////////////////////////////////////// void CChooseMachinePropPage::DoDataExchange(CDataExchange* pDX) { CAutoDeletePropPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CChooseMachinePropPage) //}}AFX_DATA_MAP DDX_Text(pDX, IDC_CHOOSER_EDIT_MACHINE_NAME, m_strMachineName); DDV_MaxChars(pDX, m_strMachineName, MAX_PATH); if (NULL != m_hwndCheckboxOverride) { DDX_Check(pDX, IDC_CHOOSER_CHECK_OVERRIDE_MACHINE_NAME, m_fAllowOverrideMachineName); } // JonN 10/25/01 485853 if (pDX->m_bSaveAndValidate && !m_fIsRadioLocalMachine) { // User clicked on OK if (NERR_Success != CanonicalizeComputername(INOUT m_strMachineName) ) { // AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Required for AfxMessageBox() // AfxMessageBox(IDS_CHOOSER_INVALID_COMPUTERNAME); CString text; CString caption; text.LoadString (IDS_CHOOSER_INVALID_COMPUTERNAME); caption.LoadString (IDS_SELECT_COMPUTER); ::MessageBox (m_hWnd, text, caption, MB_ICONEXCLAMATION | MB_OK); //::SetFocus(::GetDlgItem(m_hWnd,IDC_CHOOSER_EDIT_MACHINE_NAME)); pDX->Fail(); Assert(FALSE && "Unreachable code"); } } // if } // DoDataExchange() ///////////////////////////////////////////////////////////////////// BOOL CChooseMachinePropPage::OnInitDialog() { // ISSUE-2002/03/28-JonN chooser2 calls Edit_LimitText(MAX_PATH+2) AssertValidDialogTemplate(m_hWnd); CAutoDeletePropPage::OnInitDialog(); InitRadioButtons(); m_hwndCheckboxOverride = ::GetDlgItem(m_hWnd, IDC_CHOOSER_CHECK_OVERRIDE_MACHINE_NAME); if (m_pfAllowOverrideMachineNameOut == NULL && m_hwndCheckboxOverride != NULL) { // We are not interested with the command line override ::EnableWindow(m_hwndCheckboxOverride, FALSE); // Disable the window ::ShowWindow(m_hwndCheckboxOverride, SW_HIDE); // Hide the window } return TRUE; } ///////////////////////////////////////////////////////////////////// BOOL CChooseMachinePropPage::OnWizardFinish() { if (!UpdateData()) // Do the data exchange to collect data return FALSE; // don't destroy on error if (m_fIsRadioLocalMachine) m_strMachineName.Empty(); if (m_pstrMachineNameOut != NULL) { // Store the machine name into its output buffer *m_pstrMachineNameOut = m_strMachineName; if (m_pfAllowOverrideMachineNameOut != NULL) *m_pfAllowOverrideMachineNameOut = m_fAllowOverrideMachineName; if (m_pstrMachineNameEffectiveOut != NULL) { if (m_fAllowOverrideMachineName && PchGetMachineNameOverride()) *m_pstrMachineNameEffectiveOut = PchGetMachineNameOverride(); else *m_pstrMachineNameEffectiveOut = m_strMachineName; // JonN 1/27/99: If the persisted name is the local computername, // leave the persisted name alone but make the effective name (Local). if ( IsLocalComputername( *m_pstrMachineNameEffectiveOut ) ) m_pstrMachineNameEffectiveOut->Empty(); } // if } else Assert(FALSE && "FYI: You have not specified any output buffer to store the machine name."); return CAutoDeletePropPage::OnWizardFinish(); } void CChooseMachinePropPage::InitRadioButtons() { SendDlgItemMessage(IDC_CHOOSER_RADIO_LOCAL_MACHINE, BM_SETCHECK, m_fIsRadioLocalMachine); SendDlgItemMessage(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, BM_SETCHECK, !m_fIsRadioLocalMachine); SendDlgItemMessage(IDC_CHOOSER_EDIT_MACHINE_NAME, MAX_PATH-1); EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, !m_fIsRadioLocalMachine); EnableDlgItem (IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, !m_fIsRadioLocalMachine); } void CChooseMachinePropPage::OnRadioLocalMachine() { m_fIsRadioLocalMachine = TRUE; EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, FALSE); EnableDlgItem (IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, FALSE); } void CChooseMachinePropPage::OnRadioSpecificMachine() { m_fIsRadioLocalMachine = FALSE; EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, TRUE); EnableDlgItem (IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, TRUE); } void CChooseMachinePropPage::OnChooserButtonBrowseMachinenames() { CString computerName; HRESULT hr = ComputerNameFromObjectPicker (m_hWnd, computerName); if ( S_OK == hr ) // S_FALSE means user pressed "Cancel" { SetDlgItemText (IDC_CHOOSER_EDIT_MACHINE_NAME, computerName); } else if ( FAILED (hr) ) { CString text; CString caption; text.LoadString (IDS_UNABLE_TO_OPEN_COMPUTER_SELECTOR); caption.LoadString (IDS_SELECT_COMPUTER); MessageBox (text, caption, MB_ICONEXCLAMATION | MB_OK); } } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Generic Computer Picker /////////////////////////////////////////////////////////////////////////////// //+-------------------------------------------------------------------------- // // Function: InitObjectPickerForComputers // // Synopsis: Call IDsObjectPicker::Initialize with arguments that will // set it to allow the user to pick a single computer object. // // Arguments: [pDsObjectPicker] - object picker interface instance // // Returns: Result of calling IDsObjectPicker::Initialize. // // History: 10-14-1998 DavidMun Created // //--------------------------------------------------------------------------- HRESULT InitObjectPickerForComputers(IDsObjectPicker *pDsObjectPicker) { if ( !pDsObjectPicker ) return E_POINTER; // // Prepare to initialize the object picker. // Set up the array of scope initializer structures. // static const int SCOPE_INIT_COUNT = 2; DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT]; ZeroMemory(aScopeInit, sizeof(aScopeInit)); // JonN 3/28/02 // // 127399: JonN 10/30/00 JOINED_DOMAIN should be starting scope // aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN; aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE; aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS; aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS; aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO); aScopeInit[1].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN | DSOP_SCOPE_TYPE_GLOBAL_CATALOG | DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN | DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN | DSOP_SCOPE_TYPE_WORKGROUP | DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE | DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE; aScopeInit[1].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS; aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS; // // Put the scope init array into the object picker init array // DSOP_INIT_INFO initInfo; ZeroMemory(&initInfo, sizeof(initInfo)); initInfo.cbSize = sizeof(initInfo); initInfo.pwzTargetComputer = NULL; // NULL == local machine initInfo.cDsScopeInfos = SCOPE_INIT_COUNT; initInfo.aDsScopeInfos = aScopeInit; initInfo.cAttributesToFetch = 1; static PCWSTR pwszDnsHostName = L"dNSHostName"; initInfo.apwzAttributeNames = &pwszDnsHostName; // // Note object picker makes its own copy of initInfo. Also note // that Initialize may be called multiple times, last call wins. // return pDsObjectPicker->Initialize(&initInfo); } //+-------------------------------------------------------------------------- // // Function: ProcessSelectedObjects // // Synopsis: Retrieve the list of selected items from the data object // created by the object picker and print out each one. // // Arguments: [pdo] - data object returned by object picker // // History: 10-14-1998 DavidMun Created // //--------------------------------------------------------------------------- HRESULT ProcessSelectedObjects(IDataObject *pdo, CString& computerName) { if ( !pdo ) return E_POINTER; HRESULT hr = S_OK; static UINT g_cfDsObjectPicker = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST); 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 ( SUCCEEDED (hr) ) { fGotStgMedium = true; PDS_SELECTION_LIST pDsSelList = (PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal); if (!pDsSelList) { hr = HRESULT_FROM_WIN32 (GetLastError()); break; } ASSERT (1 == pDsSelList->cItems); if ( 1 == pDsSelList->cItems ) { PDS_SELECTION psel = &(pDsSelList->aDsSelection[0]); // ISSUE-2002/03/28-JonN check for NULL == psel VARIANT* pvarDnsName = &(psel->pvarFetchedAttributes[0]); if ( NULL == pvarDnsName || VT_BSTR != pvarDnsName->vt || NULL == pvarDnsName->bstrVal || L'\0' == (pvarDnsName->bstrVal)[0] ) { computerName = psel->pwzName; } else { computerName = pvarDnsName->bstrVal; // // JonN 2002/04/08 585301 // Computer management snapin only attempts to use the DnsHostName // to connect to a remote computer, even when the dns name // is not valid // // Bank of America encounters a problem because they // set RegisterDnsARecord to 1, turning off client DNS // records. The dnsHostName is therefore not a valid // binding name. The fix is to test the dnsHostName. // LPBYTE pbDummy = NULL; NET_API_STATUS err = NetServerGetInfo( (LPTSTR)(LPCTSTR)computerName, 101, &pbDummy ); if (pbDummy) { NetApiBufferFree( pbDummy ); pbDummy = NULL; } if (NERR_Success != err) { err = NetServerGetInfo( psel->pwzName, 101, &pbDummy ); if (pbDummy) { NetApiBufferFree( pbDummy ); pbDummy = NULL; } if (NERR_Success == err) computerName = psel->pwzName; } // end new code: JonN 2002/04/08 585301 } } else hr = E_UNEXPECTED; GlobalUnlock(stgmedium.hGlobal); } } while (0); if (fGotStgMedium) { ReleaseStgMedium(&stgmedium); } return hr; } /////////////////////////////////////////////////////////////////////////////// // Generic method for launching a single-select computer picker // // Paremeters: // hwndParent (IN) - window handle of parent window // computerName (OUT) - computer name returned // // Returns S_OK if everything succeeded, S_FALSE if user pressed "Cancel" // ////////////////////////////////////////////////////////////////////////////// HRESULT ComputerNameFromObjectPicker (HWND hwndParent, CString& computerName) { // // Create an instance of the object picker. The implementation in // objsel.dll is apartment model. // CComPtr spDsObjectPicker; HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (void **) &spDsObjectPicker); if ( SUCCEEDED (hr) ) { ASSERT(!!spDsObjectPicker); // // Initialize the object picker to choose computers // hr = InitObjectPickerForComputers(spDsObjectPicker); if ( SUCCEEDED (hr) ) { // // Now pick a computer // CComPtr spDataObject; hr = spDsObjectPicker->InvokeDialog(hwndParent, &spDataObject); if ( S_OK == hr ) { ASSERT(!!spDataObject); hr = ProcessSelectedObjects(spDataObject, computerName); } } } return hr; }