//+---------------------------------------------------------------------------- // // Windows NT Directory Service Property Pages // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: propbase.cxx // // Contents: CDsPropPageBase, the base class for property page classes. // // History: 31-March-97 EricB created // //----------------------------------------------------------------------------- #include "pch.h" #include "proppage.h" //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::~CADsApplyErrors // //----------------------------------------------------------------------------- CADsApplyErrors::~CADsApplyErrors() { if (m_pszTitle != NULL) { delete[] m_pszTitle; } Clear(); } //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::SetError // //----------------------------------------------------------------------------- void CADsApplyErrors::SetError(PADSPROPERROR pError) { if (m_nCount == m_nArraySize) { PAPPLY_ERROR_ENTRY pNewTable = new APPLY_ERROR_ENTRY[m_nCount + m_nIncAmount]; m_nArraySize = m_nCount + m_nIncAmount; if (pNewTable != NULL) { memset(pNewTable, 0, sizeof(APPLY_ERROR_ENTRY) * (m_nCount + m_nIncAmount)); if (m_pErrorTable != NULL) { for (UINT nIdx = 0; nIdx < m_nCount; nIdx++) { pNewTable[nIdx].pszPath = m_pErrorTable[nIdx].pszPath; pNewTable[nIdx].pszClass = m_pErrorTable[nIdx].pszClass; pNewTable[nIdx].hr = m_pErrorTable[nIdx].hr; pNewTable[nIdx].pszStringError = m_pErrorTable[nIdx].pszStringError; } delete[] m_pErrorTable; } m_pErrorTable = pNewTable; } } // // Copy the path to the object // if (pError->pszObjPath != NULL) { m_pErrorTable[m_nCount].pszPath = new WCHAR[wcslen(pError->pszObjPath) + 1]; dspAssert(m_pErrorTable[m_nCount].pszPath != NULL); if (m_pErrorTable[m_nCount].pszPath != NULL) { wcscpy(m_pErrorTable[m_nCount].pszPath, pError->pszObjPath); } } // // Copy the class to the object // if (pError->pszObjClass != NULL) { // Note: this memory is freed in the Clear() method which is called from // the class destructor m_pErrorTable[m_nCount].pszClass = new WCHAR[wcslen(pError->pszObjClass) + 1]; dspAssert(m_pErrorTable[m_nCount].pszClass != NULL); if (m_pErrorTable[m_nCount].pszClass != NULL) { wcscpy(m_pErrorTable[m_nCount].pszClass, pError->pszObjClass); } } // // Copy the error // if (pError->hr != S_OK) { m_pErrorTable[m_nCount].hr = pError->hr; } else { if (pError->pszError != NULL) { m_pErrorTable[m_nCount].pszStringError = new WCHAR[wcslen(pError->pszError) + 1]; dspAssert(m_pErrorTable[m_nCount].pszStringError != NULL); if (m_pErrorTable[m_nCount].pszStringError != NULL) { wcscpy(m_pErrorTable[m_nCount].pszStringError, pError->pszError); } } } // // Copy the page title // if (pError->pszPageTitle != NULL) { m_pszTitle = new WCHAR[wcslen(pError->pszPageTitle) + 1]; if (m_pszTitle != NULL) { wcscpy(m_pszTitle, pError->pszPageTitle); } } m_nCount++; } //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::GetError // //----------------------------------------------------------------------------- HRESULT CADsApplyErrors::GetError(UINT nIndex) { dspAssert(nIndex < m_nCount); if (nIndex < m_nCount) { return m_pErrorTable[nIndex].hr; } return S_FALSE; } //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::GetStringError // //----------------------------------------------------------------------------- PWSTR CADsApplyErrors::GetStringError(UINT nIndex) { dspAssert(nIndex < m_nCount); if (nIndex < m_nCount) { return m_pErrorTable[nIndex].pszStringError; } return NULL; } //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::Clear // //----------------------------------------------------------------------------- void CADsApplyErrors::Clear() { if (m_pErrorTable != NULL) { for (UINT idx = 0; idx < m_nCount; idx++) { if (m_pErrorTable[idx].pszPath != NULL) { delete[] m_pErrorTable[idx].pszPath; m_pErrorTable[idx].pszPath = NULL; } if (m_pErrorTable[idx].pszClass != NULL) { delete[] m_pErrorTable[idx].pszClass; m_pErrorTable[idx].pszClass = NULL; } if (m_pErrorTable[idx].pszStringError != NULL) { delete[] m_pErrorTable[idx].pszStringError; m_pErrorTable[idx].pszStringError = NULL; } } delete[] m_pErrorTable; m_pErrorTable = NULL; } m_nCount = 0; m_nArraySize = 0; } //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::GetName // //----------------------------------------------------------------------------- PWSTR CADsApplyErrors::GetName(UINT nIndex) { dspAssert(nIndex < m_nCount); if (nIndex < m_nCount) { return m_pErrorTable[nIndex].pszPath; } return NULL; } //+---------------------------------------------------------------------------- // // Member: CADsApplyErrors::GetClass // //----------------------------------------------------------------------------- PWSTR CADsApplyErrors::GetClass(UINT nIndex) { dspAssert(nIndex < m_nCount); if (nIndex < m_nCount) { return m_pErrorTable[nIndex].pszClass; } return NULL; } //+---------------------------------------------------------------------------- // // Member: CDsPropPageBase::CDsPropPageBase // //----------------------------------------------------------------------------- CDsPropPageBase::CDsPropPageBase(PDSPAGE pDsPage, LPDATAOBJECT pDataObj, HWND hNotifyObj, DWORD dwFlags) : m_hPage(NULL), m_fInInit(FALSE), m_fPageDirty(FALSE), m_fReadOnly(FALSE), m_fMultiselectPage(FALSE), m_pDataObj(pDataObj), m_pWPTDataObj(NULL), m_pDataObjStrm(NULL), m_pDsObj(NULL), m_nPageTitle(pDsPage->nPageTitle), m_nDlgTemplate(pDsPage->nDlgTemplate), m_cAttrs(pDsPage->cAttrs), m_rgpAttrMap(pDsPage->rgpAttrMap), m_pwszObjPathName(NULL), m_pwszObjClass(NULL), m_pwszRDName(NULL), m_pDispSpec(NULL), m_pObjSel(NULL), m_fObjSelInited(FALSE), m_rgAttrData(NULL), m_uRefs(1), m_hNotifyObj(hNotifyObj), m_pWritableAttrs(NULL), m_hrInit(S_OK) { TRACE2(CDsPropPageBase,CDsPropPageBase); // // Get the read-only state. // if (dwFlags & DSOBJECT_READONLYPAGES) { m_fReadOnly = TRUE; } } //+---------------------------------------------------------------------------- // // Member: CDsPropPageBase::~CDsPropPageBase // //----------------------------------------------------------------------------- CDsPropPageBase::~CDsPropPageBase() { TRACE2(CDsPropPageBase,~CDsPropPageBase); if (m_pwszObjPathName) { delete m_pwszObjPathName; } if (m_pwszObjClass) { delete m_pwszObjClass; } if (m_pwszRDName) { delete m_pwszRDName; } if (m_rgAttrData) { delete [] m_rgAttrData; } if (m_pObjSel) { m_pObjSel->Release(); } if (m_pDispSpec) { m_pDispSpec->Release(); } if (m_pDataObjStrm) { m_pDataObjStrm->Release(); } } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::Init // // Synopsis: Initialize the page object. This is the second part of a two // phase creation where operations that could fail are located. // Failures here are recorded in m_hrInit and then an error page // is substituted in CreatePage. // //----------------------------------------------------------------------------- void CDsPropPageBase::Init(PWSTR pwzADsPath, LPWSTR pwzClass, const CDSSmartBasePathsInfo& basePathsInfo) { TRACE(CDsPropPageBase,Init); CWaitCursor cWait; ADSPROPINITPARAMS InitParams = {0}; InitParams.dwSize = sizeof(ADSPROPINITPARAMS); ADsPropGetInitInfo(m_hNotifyObj, &InitParams); if (FAILED(InitParams.hr)) { m_hrInit = InitParams.hr; return; } m_basePathsInfo = basePathsInfo; if (!AllocWStr(pwzADsPath, &m_pwszObjPathName) || !AllocWStr(InitParams.pwzCN, &m_pwszRDName) || !AllocWStr(pwzClass, &m_pwszObjClass)) { m_hrInit = E_OUTOFMEMORY; return; } dspAssert(InitParams.pDsObj); m_pDsObj = InitParams.pDsObj; DBG_OUT("+++++++++++++++++++++++++++addrefing object"); m_pDsObj->AddRef(); m_pWritableAttrs = InitParams.pWritableAttrs; // // Allocate memory for the attribute data. // m_rgAttrData = new ATTR_DATA[m_cAttrs]; CHECK_NULL(m_rgAttrData, m_hrInit = E_OUTOFMEMORY; return); memset(m_rgAttrData, 0, m_cAttrs * sizeof(ATTR_DATA)); // // Marshall the data object pointer for passing to the window proc thread. // HRESULT hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, m_pDataObj, &m_pDataObjStrm); m_pDataObj = NULL; // to make sure no one calls here CHECK_HRESULT(hr, m_hrInit = hr; return); } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::CreatePage // // Synopsis: Create the prop page // //----------------------------------------------------------------------------- HRESULT CDsPropPageBase::CreatePage(HPROPSHEETPAGE * phPage) { TCHAR szTitle[MAX_PATH]; if (!LoadStringReport(m_nPageTitle, szTitle, MAX_PATH, NULL)) { return HRESULT_FROM_WIN32(GetLastError()); } PROPSHEETPAGE psp; psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_USECALLBACK | PSP_USETITLE; psp.pszTemplate = MAKEINTRESOURCE((SUCCEEDED(m_hrInit)) ? m_nDlgTemplate : IDD_ERROR_PAGE); psp.pfnDlgProc = StaticDlgProc; psp.pfnCallback = PageCallback; psp.pcRefParent = NULL; // do not set PSP_USEREFPARENT psp.lParam = (LPARAM) this; psp.hInstance = g_hInstance; psp.pszTitle = szTitle; *phPage = CreatePropertySheetPage(&psp); if (*phPage == NULL) { return HRESULT_FROM_WIN32(GetLastError()); } return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::StaticDlgProc // // Synopsis: static dialog proc // //----------------------------------------------------------------------------- INT_PTR CALLBACK CDsPropPageBase::StaticDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CDsPropPageBase * pPage = (CDsPropPageBase *)GetWindowLongPtr(hDlg, DWLP_USER); if (uMsg == WM_INITDIALOG) { LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam; pPage = (CDsPropPageBase *) ppsp->lParam; pPage->m_hPage = hDlg; SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pPage); if (pPage->m_pDataObjStrm) { // Unmarshall the Data Object pointer. // HRESULT hr; hr = CoGetInterfaceAndReleaseStream(pPage->m_pDataObjStrm, IID_IDataObject, reinterpret_cast(&pPage->m_pWPTDataObj)); CHECK_HRESULT_REPORT(hr, hDlg, return FALSE); // The stream should have been released above so set the // pointer to NULL so that we don't try to release again pPage->m_pDataObjStrm = 0; } return pPage->DlgProc(hDlg, uMsg, wParam, lParam); } if (pPage != NULL && (SUCCEEDED(pPage->m_hrInit))) { if (uMsg == WM_ADSPROP_PAGE_GET_NOTIFY) { HWND* pHWnd = (HWND*)wParam; *pHWnd = pPage->m_hNotifyObj; return TRUE; } return pPage->DlgProc(hDlg, uMsg, wParam, lParam); } return FALSE; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::InitDlg // // Synopsis: Handles dialog initialization for error cases. Passes non- // error initialization to subclass' OnInitDialog. // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::InitDlg(LPARAM lParam) { m_fInInit = TRUE; if (FAILED(m_hrInit)) { // Bind to the object failed, display an error page with the error // message string. // PTSTR ptz = NULL; BOOL fSpecialCaseErr = TRUE; switch (HRESULT_CODE(m_hrInit)) { case ERROR_DS_NO_ATTRIBUTE_OR_VALUE: LoadStringToTchar(IDS_ERROR_VIEW_PERMISSIONS, &ptz); break; case ERROR_DS_REFERRAL: LoadStringToTchar(IDS_ERRMSG_NO_DC_RESPONSE, &ptz); break; case ERROR_DS_NO_SUCH_OBJECT: LoadStringToTchar(IDS_ERRMSG_NO_LONGER_EXISTS, &ptz); break; default: fSpecialCaseErr = FALSE; break; } if (fSpecialCaseErr && ptz) { SetWindowText(GetDlgItem(m_hPage, IDC_ERROR_MSG), ptz); delete ptz; } else { int cch; cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, m_hrInit, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (PTSTR)&ptz, 0, NULL); if (!cch) { // Try ADSI errors. // cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(TEXT("activeds.dll")), m_hrInit, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (PTSTR)&ptz, 0, NULL); } if (cch) { SetWindowText(GetDlgItem(m_hPage, IDC_ERROR_MSG), ptz); LocalFree(ptz); } } m_fInInit = FALSE; return S_OK; } HRESULT hResult = OnInitDialog(lParam); m_fInInit = FALSE; return hResult; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnNotify // // Synopsis: Handles notification messages // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnNotify(WPARAM, LPARAM lParam) { LRESULT lResult; BOOL fPageDirty; switch (((LPNMHDR)lParam)->code) { case PSN_APPLY: if (FAILED(m_hrInit)) { return PSNRET_NOERROR; } lResult = PSNRET_NOERROR; // // The member var m_fPageDirty gets cleared in OnApply, so save a local // copy for passing as the wParam of the WM_ADSPROP_NOTIFY_APPLY msg. // fPageDirty = m_fPageDirty; if (m_fPageDirty) { // Call the virtual function OnApply() lResult = OnApply(); } // Store the result into the dialog SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, (LONG_PTR)lResult); if (lResult == PSNRET_NOERROR) { m_fPageDirty = FALSE; // // Signal the change notification. Note that the notify-apply // message must be sent even if the page is not dirty so that the // notify ref-counting will properly decrement. // SendMessage(m_hNotifyObj, WM_ADSPROP_NOTIFY_APPLY, fPageDirty, (LPARAM)m_hPage); } else { EnableWindow(GetDlgItem(GetParent(m_hPage), IDCANCEL), TRUE); } return lResult; case PSN_RESET: OnCancel(); return FALSE; // allow the property sheet to be destroyed. case PSN_SETACTIVE: return OnPSNSetActive(lParam); case PSN_KILLACTIVE: return OnPSNKillActive(lParam); } return TRUE; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnCommand // // Synopsis: Handles the WM_COMMAND message // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnCommand(int id, HWND hwndCtl, UINT codeNotify) { dspDebugOut((DEB_USER3, "CDsPropPageBase::OnCommand - id: %d, code: %x\n", id, codeNotify)); if ((codeNotify == EN_CHANGE) && !m_fInInit) { SetDirty(); } if ((codeNotify == BN_CLICKED) && (id == IDCANCEL)) { // // Pressing ESC in a multi-line edit control results in this // WM_COMMAND being sent. Pass it on to the parent (the sheet proc) to // close the sheet. // PostMessage(GetParent(m_hPage), WM_COMMAND, MAKEWPARAM(id, codeNotify), (LPARAM)hwndCtl); } return 0; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::CheckIfPageAttrsWritable // // Synopsis: See which attributes are writable by checking if they are in // the allowedAttributesEffective array. // // Notes: The m_rgAttrData array is 1 to 1 with the m_rgpAttrMap array. //----------------------------------------------------------------------------- void CDsPropPageBase::CheckIfPageAttrsWritable(void) { DWORD iAllowed; if (m_fReadOnly || !m_pWritableAttrs) { return; } for (DWORD iAttrs = 0; iAttrs < m_cAttrs; iAttrs++) { if (m_rgpAttrMap[iAttrs]->AttrInfo.pszAttrName) { for (iAllowed = 0; iAllowed < m_pWritableAttrs->dwNumValues; iAllowed++) { if (_wcsicmp(m_rgpAttrMap[iAttrs]->AttrInfo.pszAttrName, m_pWritableAttrs->pADsValues[iAllowed].CaseIgnoreString) == 0) { ATTR_DATA_SET_WRITABLE(m_rgAttrData[iAttrs]); break; } } } } return; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::CheckIfWritable // // Synopsis: See if the attribute is writable by checking if it is in // the allowedAttributesEffective array. // //----------------------------------------------------------------------------- BOOL CDsPropPageBase::CheckIfWritable(const PWSTR & wzAttr) { BOOL fWritable = FALSE; if (m_fReadOnly || !m_pWritableAttrs) { return FALSE; } for (DWORD i = 0; i < m_pWritableAttrs->dwNumValues; i++) { if (_wcsicmp(m_pWritableAttrs->pADsValues[i].CaseIgnoreString, wzAttr) == 0) { fWritable = TRUE; break; } } return fWritable; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnCancel // // Synopsis: // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnCancel(void) { return FALSE; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnSetFocus // // Synopsis: // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnSetFocus(HWND) { // An application should return zero if it processes this message. return 1; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnPSNSetActive // // Synopsis: Page activation event. // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnPSNSetActive(LPARAM) { SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, 0); return TRUE; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnPSNKillActive // // Synopsis: Page deactivation event (when other pages cover this one). // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnPSNKillActive(LPARAM) { SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, 0); return TRUE; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnDestroy // // Synopsis: Exit cleanup // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnDestroy(void) { return 1; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnShowWindow // // Synopsis: On dialog window show operations, resizes the view window. // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnShowWindow(void) { return 0; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::GetIDispSpec // // Synopsis: If needed, create the interface instance and return the pointer. // //----------------------------------------------------------------------------- HRESULT CDsPropPageBase::GetIDispSpec(IDsDisplaySpecifier ** ppDispSpec) { HRESULT hr; TRACE2(CDsPropPageBase, GetIDispSpec); if (!m_pDispSpec) { hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (PVOID *)&m_pDispSpec); CHECK_HRESULT(hr, return hr); CStrW strDC; CComPtr spDsObj; if (m_pDsObj == NULL) { // // For the retrieval of the DS Object names // FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM objMedium; hr = m_pWPTDataObj->GetData(&fmte, &objMedium); CHECK_HRESULT(hr, return hr); LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal; // // Get the objects path // LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName); // // Bind to the object // hr = DSAdminOpenObject(pwzObjADsPath, IID_IDirectoryObject, (PVOID*)&spDsObj); ReleaseStgMedium(&objMedium); CHECK_HRESULT(hr, return hr); } else { spDsObj = m_pDsObj; } hr = GetLdapServerName(spDsObj, strDC); CHECK_HRESULT(hr, return hr); hr = m_pDispSpec->SetServer(strDC, NULL, NULL, 0); CHECK_HRESULT(hr, return hr); } if (ppDispSpec) { *ppDispSpec = m_pDispSpec; } return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::GetADsPathname // // Synopsis: If needed, create the interface instance and return the pointer. // //----------------------------------------------------------------------------- HRESULT CDsPropPageBase::GetADsPathname(CComPtr& refADsPath) { HRESULT hr; if (!m_pADsPath) { hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&m_pADsPath); CHECK_HRESULT(hr, return hr); } refADsPath = m_pADsPath; return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::SkipPrefix // // Synopsis: Given an object name, returns a buffer containing the same // name without the provider/server prefix. The buffer must be // freed using delete. // // Notes: The fX500 parameter defaults to true and applies whenever the // input path uses the LDAP provider prefix. The path cracker // interface can be used to strip the prefix in this case. However, // if the provider is WINNT, then the path cracker doesn't give the // desired results so simple string manipulation is used instead. //----------------------------------------------------------------------------- HRESULT CDsPropPageBase::SkipPrefix(PWSTR pwzObj, PWSTR * ppResult, BOOL fX500) { if (fX500) { // Strip of the "LDAP://" prefix using the path cracker. // CComPtr spPathname; HRESULT hr = GetADsPathname(spPathname); CHECK_HRESULT(hr, return hr); hr = spPathname->Set(CComBSTR(pwzObj), ADS_SETTYPE_FULL); CHECK_HRESULT(hr, return hr); BSTR bstr; hr = spPathname->Retrieve(ADS_FORMAT_X500_DN, &bstr); CHECK_HRESULT(hr, return hr); if (!AllocWStr(bstr, ppResult)) { SysFreeString(bstr); return E_OUTOFMEMORY; } SysFreeString(bstr); } else { // Strip off the "WINNT://" prefix. // if (wcslen(pwzObj) < 9 || pwzObj[7] != L'/') { // Can't be a valid WINNT name if not at least "WINNT://x" // return E_INVALIDARG; } if (!AllocWStr(&pwzObj[8], ppResult)) { return E_OUTOFMEMORY; } } return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::AddLdapPrefix // // Synopsis: Given an object name, returns same name with the LDAP provider // prefix. The server name is also added by default. // //----------------------------------------------------------------------------- HRESULT CDsPropPageBase::AddLDAPPrefix(PWSTR pwzObj, CStrW &pstrResult, BOOL fServer) { return ::AddLDAPPrefix(this, pwzObj, pstrResult, fServer); } // // Non-class member version. // HRESULT AddLDAPPrefix(CDsPropPageBase * pPage, PWSTR pwzObj, CStrW &strResult, BOOL fServer) { HRESULT hr; CComPtr spPathCracker; strResult.Empty(); if (pPage) { hr = pPage->GetADsPathname(spPathCracker); CHECK_HRESULT(hr, return hr); } else { hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (PVOID *)&spPathCracker); CHECK_HRESULT(hr, return hr); } hr = spPathCracker->Set(CComBSTR(L"LDAP"), ADS_SETTYPE_PROVIDER); CHECK_HRESULT(hr, return hr); if (pPage) { CStrW strDC; CComPtr spDsObj; if (pPage->m_pDsObj == NULL) { // // For the retrieval of the DS Object names // FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM objMedium; hr = pPage->m_pWPTDataObj->GetData(&fmte, &objMedium); CHECK_HRESULT(hr, return hr); LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal; // // Get the objects path // LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName); // // Bind to the object // hr = DSAdminOpenObject(pwzObjADsPath, IID_IDirectoryObject, (PVOID*)&spDsObj); ReleaseStgMedium(&objMedium); CHECK_HRESULT(hr, return hr); } else { spDsObj = pPage->m_pDsObj; } hr = GetLdapServerName(spDsObj, strDC); CHECK_HRESULT(hr, return hr); hr = spPathCracker->Set(CComBSTR(strDC), ADS_SETTYPE_SERVER); CHECK_HRESULT(hr, return hr); } hr = spPathCracker->Set(CComBSTR(pwzObj), ADS_SETTYPE_DN); CHECK_HRESULT(hr, return hr); CComBSTR bstr; hr = spPathCracker->Retrieve((fServer) ? ADS_FORMAT_X500 : ADS_FORMAT_X500_NO_SERVER, &bstr); CHECK_HRESULT(hr, return hr); strResult = bstr; return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::GetObjSel // // Synopsis: CoCreates the object picker if needed, returns the pointer. // //----------------------------------------------------------------------------- HRESULT CDsPropPageBase::GetObjSel(IDsObjectPicker ** ppObjSel, PBOOL pfIsInited) { HRESULT hr; TRACE2(CDsPropPageBase,GetObjSel); if (!m_pObjSel) { hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (PVOID *)&m_pObjSel); if (FAILED(hr)) { REPORT_ERROR(hr, m_hPage); return hr; } } *ppObjSel = m_pObjSel; if (pfIsInited) { *pfIsInited = m_fObjSelInited; } return S_OK; } #ifdef DO_HELP #include "helpids.h" #endif //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::OnHelp // // Synopsis: Put up popup help for the control. // //----------------------------------------------------------------------------- LRESULT CDsPropPageBase::OnHelp(LPHELPINFO pHelpInfo) { dspDebugOut((DEB_ITRACE, "WM_HELP: CtrlId = %d, ContextId = 0x%x\n", pHelpInfo->iCtrlId, pHelpInfo->dwContextId)); if (pHelpInfo->iCtrlId < 1 || IDH_NO_HELP == pHelpInfo->dwContextId) { return 0; } WinHelp(m_hPage, DSPROP_HELP_FILE_NAME, HELP_CONTEXTPOPUP, pHelpInfo->dwContextId); #ifdef DONT_DO_THIS WinHelp((HWND)pHelpInfo->hItemHandle, DSPROP_HELP_FILE_NAME, HELP_WM_HELP, (DWORD)g_aHelpIDs); #endif return 0; } //+---------------------------------------------------------------------------- // // Method: CDsPropPageBase::PageCallback // // Synopsis: Callback used to free the CDsPropPageBase object when the // property sheet has been destroyed. // //----------------------------------------------------------------------------- UINT CALLBACK CDsPropPageBase::PageCallback(HWND hDlg, UINT uMsg, LPPROPSHEETPAGE ppsp) { TRACE_FUNCTION(CDsPropPageBase::PageCallback); if (uMsg == PSPCB_RELEASE) { // // Determine instance that invoked this static function // CDsPropPageBase * pPage = (CDsPropPageBase *) ppsp->lParam; // // Call all function pointers so that they can do any needed cleanup. // if (SUCCEEDED(pPage->m_hrInit)) { for (DWORD i = 0; i < pPage->m_cAttrs; i++) { if (pPage->m_rgpAttrMap[i]->pAttrFcn) { (*pPage->m_rgpAttrMap[i]->pAttrFcn)(pPage, pPage->m_rgpAttrMap[i], NULL, 0, &pPage->m_rgAttrData[i], fOnCallbackRelease); } } } if (IsWindow(pPage->m_hNotifyObj)) { SendMessage(pPage->m_hNotifyObj, WM_ADSPROP_NOTIFY_EXIT, 0, 0); } // Release on same thread on which created. // DO_RELEASE(pPage->m_pWPTDataObj); //DBG_OUT("-----------------------releasing object in page callback."); DO_RELEASE(pPage->m_pDsObj); dspDebugOut((DEB_ITRACE, "Deleting CDsPropPageBase instance 0x%x\n", pPage)); pPage->Release(); SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NULL); } return TRUE; } //+---------------------------------------------------------------------------- // // Member: CDsPropPageBase::IUnknown::QueryInterface // // Synopsis: Returns requested interface pointer // //----------------------------------------------------------------------------- STDMETHODIMP CDsPropPageBase::QueryInterface(REFIID riid, void ** ppvObject) { TRACE2(CDsPropPageBase,QueryInterface); if (IID_IUnknown == riid) { *ppvObject = (IUnknown *)this; } else { *ppvObject = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } //+---------------------------------------------------------------------------- // // Member: CDsPropPageBase::IUnknown::AddRef // // Synopsis: increments reference count // // Returns: the reference count // //----------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDsPropPageBase::AddRef(void) { dspDebugOut((DEB_USER2, "CDsPropPageBase::AddRef refcount going in %d\n", m_uRefs)); return InterlockedIncrement((long *)&m_uRefs); } //+---------------------------------------------------------------------------- // // Member: CDsPropPageBase::IUnknown::Release // // Synopsis: Decrements the object's reference count and frees it when // no longer referenced. // // Returns: zero if the reference count is zero or non-zero otherwise // //----------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDsPropPageBase::Release(void) { dspDebugOut((DEB_USER2, "CDsPropPageBase::Release ref count going in %d\n", m_uRefs)); unsigned long uTmp; if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0) { delete this; } return uTmp; } //+---------------------------------------------------------------------------- // // Function: GetLdapServerName // // Synopsis: Given an IDirectoryObject* that supports IADsObjectOptions, it // returns the server name ADSI is bound to. // //----------------------------------------------------------------------------- HRESULT GetLdapServerName(IUnknown * pDsObj, CStrW& strServer) { HRESULT hr; strServer.Empty(); CComPtr spIADsObjectOptions; hr = pDsObj->QueryInterface(IID_IADsObjectOptions, (void**)&spIADsObjectOptions); CHECK_HRESULT(hr, return hr); CComVariant var; hr = spIADsObjectOptions->GetOption(ADS_OPTION_SERVERNAME, &var); CHECK_HRESULT(hr, return hr); dspAssert(var.vt == VT_BSTR); strServer = V_BSTR(&var); return hr; } //+---------------------------------------------------------------------------- // // Function: BindToGCcopyOfObj // // Synopsis: Bind to the GC copy of the object. // //----------------------------------------------------------------------------- HRESULT BindToGCcopyOfObj(CDsPropPageBase * pPage, PWSTR pwzObjADsPath, IDirectoryObject ** ppDsObj) { CSmartWStr cswzCleanObj; PWSTR pwzDnsDom; PDOMAIN_CONTROLLER_INFOW pDCInfo; HRESULT hr = pPage->SkipPrefix(pwzObjADsPath, &cswzCleanObj); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); // To bind to a GC, you need to supply the tree root domain name rather // than the server path because the current DC/domain may not be hosting a // GC. // hr = CrackName(cswzCleanObj, &pwzDnsDom, GET_DNS_DOMAIN_NAME, pPage->GetHWnd()); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); DWORD dwErr = DsGetDcNameW(NULL, pwzDnsDom, NULL,NULL, DS_DIRECTORY_SERVICE_REQUIRED, &pDCInfo); LocalFreeStringW(&pwzDnsDom); hr = HRESULT_FROM_WIN32(dwErr); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); CComPtr spADsPath; long lEscapeMode; hr = pPage->GetADsPathname(spADsPath); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); spADsPath->get_EscapedMode(&lEscapeMode); hr = spADsPath->Set(CComBSTR(L"GC"), ADS_SETTYPE_PROVIDER); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); hr = spADsPath->Set(CComBSTR(pDCInfo->DnsForestName), ADS_SETTYPE_SERVER); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); NetApiBufferFree(pDCInfo); hr = spADsPath->Set(CComBSTR((PCWSTR)cswzCleanObj), ADS_SETTYPE_DN); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); spADsPath->put_EscapedMode(ADS_ESCAPEDMODE_ON); CComBSTR bstrEscapedPath; hr = spADsPath->Retrieve(ADS_FORMAT_X500, &bstrEscapedPath); // restore defaults spADsPath->Set(CComBSTR(L"LDAP"), ADS_SETTYPE_PROVIDER); spADsPath->put_EscapedMode(lEscapeMode); CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); dspDebugOut((DEB_ITRACE, "Binding to object at %ws\n", bstrEscapedPath)); hr = DSAdminOpenObject(bstrEscapedPath, IID_IDirectoryObject, (PVOID*)ppDsObj); return hr; }