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.
1338 lines
38 KiB
1338 lines
38 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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<void**>(&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<IDirectoryObject> 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<IADsPathname>& 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<IADsPathname> 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<IADsPathname> 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<IDirectoryObject> 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<IADsObjectOptions> 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<IADsPathname> 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;
|
|
}
|
|
|