|
|
//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: proppage.cxx
//
// Contents: CDsPropPagesHost, the class that exposes IShellExtInit and
// IShellPropSheetExt
//
// History: 24-March-97 EricB created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include "proppage.h"
#include <propcfg.h>
#include <pcrack.h>
CLIPFORMAT g_cfDsObjectNames = 0; CLIPFORMAT g_cfDsDispSpecOptions = 0; CLIPFORMAT g_cfShellIDListArray = 0; CLIPFORMAT g_cfMMCGetNodeType = 0; CLIPFORMAT g_cfDsPropCfg = 0; CLIPFORMAT g_cfDsSelList = 0; CLIPFORMAT g_cfDsMultiSelectProppages = 0; //CLIPFORMAT g_cfMMCGetCoClass = 0;
static void ToggleMVDefaultBtn(HWND hDlg, BOOL fOK);
//+----------------------------------------------------------------------------
//
// Member: CDsPropPagesHost::CDsPropPagesHost
//
//-----------------------------------------------------------------------------
CDsPropPagesHost::CDsPropPagesHost(PDSCLASSPAGES pDsPP) : m_pDsPPages(pDsPP), m_pDataObj(NULL), m_hNotifyObj(NULL), m_uRefs(1) { TRACE2(CDsPropPagesHost,CDsPropPagesHost); #ifdef _DEBUG
strcpy(szClass, "CDsPropPagesHost"); #endif
m_ObjMedium.tymed = TYMED_NULL; m_ObjMedium.hGlobal = NULL; }
//+----------------------------------------------------------------------------
//
// Member: CDsPropPagesHost::~CDsPropPagesHost
//
//-----------------------------------------------------------------------------
CDsPropPagesHost::~CDsPropPagesHost() { TRACE(CDsPropPagesHost,~CDsPropPagesHost); if (m_pDataObj) { m_pDataObj->Release(); } if (m_ObjMedium.tymed != TYMED_NULL) { ReleaseStgMedium(&m_ObjMedium); } }
//+----------------------------------------------------------------------------
//
// Member: CDsPropPagesHost::IShellExtInit::Initialize
//
// Synopsis:
//
// Arguments:
//
// Returns: HRESULTS
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDsPropPagesHost::Initialize(LPCITEMIDLIST, LPDATAOBJECT pDataObj, HKEY) { TRACE2(CDsPropPagesHost,Initialize);
if (IsBadReadPtr(pDataObj, sizeof(LPDATAOBJECT))) { DBG_OUT("Failed because we don't have a data object"); return E_INVALIDARG; }
if (m_pDataObj) { m_pDataObj->Release(); m_pDataObj = NULL; }
// Hang onto the IDataObject we are being passed.
m_pDataObj = pDataObj; if (m_pDataObj) { m_pDataObj->AddRef(); } else { return E_INVALIDARG; }
return S_OK; }
//+----------------------------------------------------------------------------
//
// Member: CDsPropPagesHost::IShellExtInit::AddPages
//
// Synopsis:
//
// Arguments:
//
// Returns: HRESULTS
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDsPropPagesHost::AddPages(LPFNADDPROPSHEETPAGE pAddPageProc, LPARAM lParam) { TRACE(CDsPropPagesHost,AddPages);
CWaitCursor cWait;
HRESULT hr = S_OK; HPROPSHEETPAGE hPage; PWSTR pwzObjADsPath, pwzClass; DWORD i; BOOL fPageCreated = FALSE;
//
// Get the unique identifier for the notify object from the data object
//
FORMATETC mfmte = {g_cfDsMultiSelectProppages, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM objMedium; LPWSTR lpszUniqueID = NULL; LPWSTR lpszTempUniqueID = NULL;
hr = m_pDataObj->GetData(&mfmte, &objMedium); if (SUCCEEDED(hr)) { lpszTempUniqueID = (LPWSTR)objMedium.hGlobal; if (lpszTempUniqueID == NULL) { DBG_OUT("Unique identifier not available for property pages."); ReleaseStgMedium(&objMedium); return ERROR_INVALID_DATA; }
size_t iLength = wcslen(lpszTempUniqueID); lpszUniqueID = new WCHAR[iLength + 1]; if (lpszUniqueID) { wcscpy(lpszUniqueID, lpszTempUniqueID); }
ReleaseStgMedium(&objMedium); } //
// Retrieve the DS object names
//
FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; LPDSOBJECTNAMES pDsObjectNames; //
// Get the path to the DS object from the data object.
// Note: This call runs on the caller's main thread. The pages' window
// procs run on a different thread, so don't reference the data object
// from a winproc unless it is first marshalled on this thread.
//
hr = m_pDataObj->GetData(&fmte, &m_ObjMedium); CHECK_HRESULT(hr, return hr);
pDsObjectNames = (LPDSOBJECTNAMES)m_ObjMedium.hGlobal;
if (pDsObjectNames->cItems < 1) { DBG_OUT("Not enough objects in DSOBJECTNAMES structure"); return ERROR_INVALID_DATA; }
pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName); pwzClass = (PWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetClass); dspDebugOut((DEB_ITRACE, "Object name: %ws, Class: %ws\n", pwzObjADsPath, pwzClass));
// Crack the name to get the server name and use that to create a
// CDSBasePathsInfo that can be used by the pages
CDSBasePathsInfo* pBasePathsInfo = new CDSBasePathsInfo; CHECK_NULL(pBasePathsInfo, return E_OUTOFMEMORY);
CDSSmartBasePathsInfo basePathsInfo(pBasePathsInfo); CPathCracker pathCracker; hr = pathCracker.Set(CComBSTR(pwzObjADsPath), ADS_SETTYPE_FULL); if (SUCCEEDED(hr)) { CComBSTR sbstrServer; hr = pathCracker.Retrieve(ADS_FORMAT_SERVER, &sbstrServer); if (SUCCEEDED(hr)) { hr = basePathsInfo->InitFromName(sbstrServer); } else { // The shell calls the prop-page without a server in the path.
//
hr = basePathsInfo->InitFromName(NULL); } }
if (FAILED(hr)) { DBG_OUT("Failed to create/initialize the base paths info for the pages"); return ERROR_INVALID_DATA; }
//
// Loop to see if any pages will be created.
//
for (i = 0; i < m_pDsPPages->cPages; i++) { PDSPAGE pDsPage = m_pDsPPages->rgpDsPages[i];
if ((pDsPage->dwFlags & DSPROVIDER_ADVANCED) && !(pDsObjectNames->aObjects[0].dwProviderFlags & DSPROVIDER_ADVANCED)) { // The page should only be displayed if in advanced mode.
//
continue; }
if (pDsPage->nCLSIDs) { // Only show the page if there is a match on the snapin (namespace)
// CLSID.
//
BOOL fFound = FALSE; for (DWORD j = 0; j < pDsPage->nCLSIDs; j++) { if (IsEqualCLSID(pDsPage->rgCLSID[j], pDsObjectNames->clsidNamespace)) { fFound = TRUE; } } if (!fFound) { continue; } }
fPageCreated = TRUE; }
if (fPageCreated) { //
// At least one page will be created, so contact the notification
// object. If it doesn't already exist, it will be created.
//
if (lpszUniqueID == NULL) { //
// Copy the path to be used as the unique ID for the page
// This should only be done if the DataObject does not support g_cfDsMultiSelectProppages
//
size_t iLength = wcslen(pwzObjADsPath); lpszUniqueID = new WCHAR[iLength + 1]; if (lpszUniqueID) { wcscpy(lpszUniqueID, pwzObjADsPath); } } hr = ADsPropCreateNotifyObj(m_pDataObj, lpszUniqueID, &m_hNotifyObj); delete[] lpszUniqueID; CHECK_HRESULT(hr, return hr); } else { if (lpszUniqueID) { delete[] lpszUniqueID; lpszUniqueID = 0; } }
//
// Create each page.
//
for (i = 0; i < m_pDsPPages->cPages; i++) { PDSPAGE pDsPage = m_pDsPPages->rgpDsPages[i];
if ((pDsPage->dwFlags & DSPROVIDER_ADVANCED) && !(pDsObjectNames->aObjects[0].dwProviderFlags & DSPROVIDER_ADVANCED)) { // The page should only be displayed if in advanced mode.
//
continue; }
if (pDsPage->nCLSIDs) { // Only show the page if there is a match on the snapin (namespace)
// CLSID.
//
BOOL fFound = FALSE; for (DWORD j = 0; j < pDsPage->nCLSIDs; j++) { if (IsEqualCLSID(pDsPage->rgCLSID[j], pDsObjectNames->clsidNamespace)) { fFound = TRUE; } } if (!fFound) { continue; } }
// Call the page's creation function.
//
hr = (*pDsPage->pCreateFcn)(pDsPage, m_pDataObj, pwzObjADsPath, pwzClass, m_hNotifyObj, pDsObjectNames->aObjects[0].dwFlags, basePathsInfo, &hPage); if (hr == S_FALSE) { // If the page doesn't want to be shown, it should return S_FALSE.
//
continue; } if (hr == HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP)) { break; } CHECK_HRESULT(hr, continue);
// Pass the page handle back to the app wanting to post the prop sheet.
//
if (!(*pAddPageProc)(hPage, lParam)) { CHECK_HRESULT(E_FAIL, return E_FAIL); } }
return hr; }
//+----------------------------------------------------------------------------
//
// Member: CDsPropPagesHost::IShellExtInit::ReplacePage
//
// Synopsis: Unused.
//
//-----------------------------------------------------------------------------
STDMETHODIMP CDsPropPagesHost::ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM) { TRACE(CDsPropPagesHost,ReplacePage); return E_NOTIMPL; }
//+----------------------------------------------------------------------------
//
// Multi-valued attribute editing.
//
//-----------------------------------------------------------------------------
//+----------------------------------------------------------------------------
//
// Class: CMultiStringAttrDlg
//
// Purpose: Read, edit, and write a multi-valued, string property. This is
// the dialog that contains the CMultiStringAttr class controls.
//
//-----------------------------------------------------------------------------
CMultiStringAttrDlg::CMultiStringAttrDlg(CDsPropPageBase * pPage) : m_pPage(pPage), m_MSA(pPage) { }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttrDlg::Init
//
// Synopsis: Do initialization where failures can occur and then be
// returned. Can be only called once as written.
//
// Arguments: [pAttrMap] - contains the attr name.
// [pAttrInfo] - place to store the values.
// [nLimit] - the max number of values (zero means no limit).
// [fCommaList] - if TRUE, pAttrInfo is a single-valued, comma
// delimited list.
//-----------------------------------------------------------------------------
HRESULT CMultiStringAttrDlg::Init(PATTR_MAP pAttrMap, PADS_ATTR_INFO pAttrInfo, BOOL fWritable, int nLimit, BOOL fCommaList, BOOL fMultiselectPage) { return m_MSA.Init(pAttrMap, pAttrInfo, fWritable, nLimit, fCommaList, fMultiselectPage); }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttrDlg::Write
//
// Synopsis: Return the ADS_ATTR_INFO array of values to be Applied.
//
//-----------------------------------------------------------------------------
HRESULT CMultiStringAttrDlg::Write(PADS_ATTR_INFO pAttrInfo) { return m_MSA.Write(pAttrInfo); }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttrDlg::Edit
//
// Synopsis: Post the edit dialog.
//
//-----------------------------------------------------------------------------
INT_PTR CMultiStringAttrDlg::Edit(void) { INT_PTR nRet;
nRet = DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_MULTI_VALUE), m_pPage->GetHWnd(), StaticDlgProc, (LPARAM)this); if (IDOK == nRet) { EnableWindow(GetDlgItem(GetParent(m_pPage->GetHWnd()), IDOK), TRUE);
m_pPage->SetDirty(); }
return nRet; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttrDlg::StaticDlgProc
//
// Synopsis: The static dialog proc for editing a multi-valued attribute.
//
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CMultiStringAttrDlg::StaticDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMultiStringAttrDlg * pMSAD = (CMultiStringAttrDlg *)GetWindowLongPtr(hDlg, DWLP_USER);
if (uMsg == WM_INITDIALOG) { pMSAD = (CMultiStringAttrDlg *)lParam; SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pMSAD); }
if (pMSAD) { return pMSAD->MultiValDlgProc(hDlg, uMsg, wParam, lParam); }
return FALSE; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttrDlg::MultiValDlgProc
//
// Synopsis: The instancce dialog proc for editing a multi-valued attribute.
//
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CMultiStringAttrDlg::MultiValDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMultiStringAttrDlg * pMSAD = (CMultiStringAttrDlg *)GetWindowLongPtr(hDlg, DWLP_USER); CMultiStringAttr * pMSA = &pMSAD->m_MSA;
switch (uMsg) { case WM_INITDIALOG: CHECK_NULL_REPORT(pMSA, hDlg, return 0;); return pMSA->DoDlgInit(hDlg);
case WM_COMMAND: CHECK_NULL_REPORT(pMSA, hDlg, return 0;); return pMSA->DoCommand(hDlg, GET_WM_COMMAND_ID(wParam, lParam), GET_WM_COMMAND_CMD(wParam, lParam));
case WM_NOTIFY: CHECK_NULL_REPORT(pMSA, hDlg, return 0;); return pMSA->DoNotify(hDlg, (NMHDR *)lParam);
case WM_HELP: LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; dspDebugOut((DEB_ITRACE, "WM_HELP: CtrlId = %d, ContextId = 0x%x\n", pHelpInfo->iCtrlId, pHelpInfo->dwContextId)); if (pHelpInfo->iCtrlId < 1) { return 0; } WinHelp(hDlg, DSPROP_HELP_FILE_NAME, HELP_CONTEXTPOPUP, pHelpInfo->dwContextId); break; }
return 0; }
//+----------------------------------------------------------------------------
//
// Class: CMultiStringAttr
//
// Purpose: Read, edit, and write a multi-valued, string property.
//
//-----------------------------------------------------------------------------
CMultiStringAttr::CMultiStringAttr(CDsPropPageBase * pPage) : m_pPage(pPage), m_pAttrLDAPname(NULL), m_nMaxLen(0), m_nCurDefCtrl(IDC_CLOSE), m_fListHasSel(FALSE), m_nLimit(0), m_cValues(0), m_fWritable(TRUE), m_fCommaList(FALSE), m_fDirty(FALSE), m_fAppend(FALSE) { m_AttrInfo.pADsValues = NULL; m_AttrInfo.dwNumValues = 0; m_AttrInfo.pszAttrName = NULL; }
CMultiStringAttr::~CMultiStringAttr() { ClearAttrInfo(); DO_DEL(m_pAttrLDAPname); }
void CMultiStringAttr::ClearAttrInfo(void) { for (DWORD i = 0; i < m_AttrInfo.dwNumValues; i++) { delete [] m_AttrInfo.pADsValues[i].CaseIgnoreString; } if (m_AttrInfo.pADsValues) { delete [] m_AttrInfo.pADsValues; } m_AttrInfo.pADsValues = NULL; m_AttrInfo.dwNumValues = 0; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::Init
//
// Synopsis: Do initialization where failures can occur and then be
// returned. Can be only called once as written.
//
// Arguments: [pAttrMap] - contains the attr name.
// [pAttrInfo] - place to store the values.
// [nLimit] - the max number of values (zero means no limit).
// [fCommaList] - if TRUE, pAttrInfo is a single-valued, comma
// delimited list.
//-----------------------------------------------------------------------------
HRESULT CMultiStringAttr::Init(PATTR_MAP pAttrMap, PADS_ATTR_INFO pAttrInfo, BOOL fWritable, int nLimit, BOOL fCommaList, BOOL fAppend) { if (!AllocWStr(pAttrMap->AttrInfo.pszAttrName, &m_pAttrLDAPname)) { REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd()); return E_OUTOFMEMORY; }
m_nLimit = nLimit; m_fCommaList = fCommaList; m_fWritable = fWritable; m_fAppend = fAppend;
m_nMaxLen = pAttrMap->nSizeLimit;
m_AttrInfo.dwADsType = pAttrMap->AttrInfo.dwADsType;
if (NULL == pAttrInfo) { return S_OK; }
DWORD cItems = 0; PWSTR pwzComma, pwzCur;
if (fCommaList) { pwzCur = pAttrInfo->pADsValues->CaseIgnoreString; //
// Count the number of elements. This count includes empty elements,
// e.g. leading, trailing, or adjacent commas.
//
while (*pwzCur) { cItems++; pwzComma = wcschr(pwzCur, L','); if (pwzComma) { pwzCur = pwzComma + 1; } else { break; } } } else { cItems = pAttrInfo->dwNumValues; }
m_AttrInfo.pADsValues = new ADSVALUE[cItems];
CHECK_NULL_REPORT(m_AttrInfo.pADsValues, m_pPage->GetHWnd(), return E_OUTOFMEMORY);
for (DWORD i = 0, j = 0; i < cItems; i++) { if (fCommaList) { if (i == 0) { pwzCur = wcstok(pAttrInfo->pADsValues->CaseIgnoreString, L",\0"); } else { pwzCur = wcstok(NULL, L",\0"); } if (!pwzCur) { break; } if (!*pwzCur) { // Skip empty elements.
//
continue; } if (!AllocWStr(pwzCur, &m_AttrInfo.pADsValues[j].CaseIgnoreString)) { REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd()); return E_OUTOFMEMORY; } } else { dspAssert(i == j);
if (!AllocWStr(pAttrInfo->pADsValues[j].CaseIgnoreString, &m_AttrInfo.pADsValues[j].CaseIgnoreString)) { REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd()); return E_OUTOFMEMORY; } } m_AttrInfo.pADsValues[j].dwType = m_AttrInfo.dwADsType; m_AttrInfo.dwNumValues++; j++; } return S_OK; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::ToggleDefaultBtn
//
// Synopsis: Calls ToggleMVDefaultBtn which sets the default button
// to the correct control for the state of the dialog
//
//-----------------------------------------------------------------------------
void CMultiStringAttr::ToggleDefaultBtn(HWND hDlg, BOOL fOK) { ToggleMVDefaultBtn(hDlg, fOK); }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::Write
//
// Synopsis: Return the ADS_ATTR_INFO array of values to be Applied.
//
//-----------------------------------------------------------------------------
HRESULT CMultiStringAttr::Write(PADS_ATTR_INFO pAttrInfo) { pAttrInfo->dwADsType = m_AttrInfo.dwADsType; pAttrInfo->dwNumValues = 0;
if (!m_fWritable) { return ADM_S_SKIP; }
if (m_AttrInfo.dwNumValues) { PADSVALUE pADsValues;
int nValues = (m_fCommaList) ? 1 : m_AttrInfo.dwNumValues;
pADsValues = new ADSVALUE[nValues];
CHECK_NULL_REPORT(pADsValues, m_pPage->GetHWnd(), return E_OUTOFMEMORY);
if (m_fAppend) { pAttrInfo->dwControlCode = ADS_ATTR_APPEND; } else { pAttrInfo->dwControlCode = ADS_ATTR_UPDATE; } pAttrInfo->pADsValues = pADsValues;
if (m_fCommaList) { // For simplicity, just go ahead and allocate the max. That is,
// there are m_AttrInfo.dwNumValues values each which can be a max
// length of m_nMaxLen. The comma separator is included in the
// count.
//
pADsValues->CaseIgnoreString = new WCHAR[(m_AttrInfo.dwNumValues * (m_nMaxLen + 1)) + 1]; CHECK_NULL_REPORT(pADsValues->CaseIgnoreString, m_pPage->GetHWnd(), return E_OUTOFMEMORY);
wcscpy(pADsValues->CaseIgnoreString, m_AttrInfo.pADsValues[0].CaseIgnoreString);
for (DWORD i = 1; i < m_AttrInfo.dwNumValues; i++) { wcscat(pADsValues->CaseIgnoreString, L","); wcscat(pADsValues->CaseIgnoreString, m_AttrInfo.pADsValues[i].CaseIgnoreString); } pADsValues->dwType = m_AttrInfo.dwADsType; pAttrInfo->dwNumValues = 1; } else { for (DWORD i = 0; i < m_AttrInfo.dwNumValues; i++) { PWSTR pwz; if (!AllocWStr(m_AttrInfo.pADsValues[i].CaseIgnoreString, &pwz)) { REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd()); return E_OUTOFMEMORY; } pADsValues[i].dwType = m_AttrInfo.dwADsType; pADsValues[i].CaseIgnoreString = pwz; pAttrInfo->dwNumValues++; } } } else { pAttrInfo->pADsValues = NULL; pAttrInfo->dwControlCode = ADS_ATTR_CLEAR; } return S_OK; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::SetDirty
//
// Synopsis: Marks the page dirty and enables the OK button
//
//-----------------------------------------------------------------------------
void CMultiStringAttr::SetDirty(HWND hDlg) { m_fDirty = TRUE; EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), m_fDirty); }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::EnableControls
//
// Synopsis: Enable or disable all of the controls.
//
//-----------------------------------------------------------------------------
void CMultiStringAttr::EnableControls(HWND hDlg, BOOL fEnable) { EnableWindow(GetDlgItem(hDlg, IDC_EDIT), fEnable); EnableWindow(GetDlgItem(hDlg, IDC_LIST), fEnable); if (!fEnable) { EnableWindow(GetDlgItem(hDlg, IDC_ADD_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE); m_fListHasSel = FALSE; }
EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), IsDirty()); }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::DoDlgInit
//
// Synopsis: WM_INITDIALOG code.
//
//-----------------------------------------------------------------------------
BOOL CMultiStringAttr::DoDlgInit(HWND hDlg) { LPTSTR ptz; HRESULT hr = S_OK; LONG i; HWND hList; LV_ITEM lvi; /*
//
// Create the dialog caption: "<obj-name> - <attribute-name>"
//
TCHAR szCaption[MAX_PATH]; if (!UnicodeToTchar(m_pPage->GetObjRDName(), &ptz)) { CHECK_WIN32_REPORT(ERROR_NOT_ENOUGH_MEMORY, hDlg, return FALSE); } _tcscpy(szCaption, ptz); delete [] ptz; _tcscat(szCaption, TEXT(" - ")); int len = _tcslen(szCaption); */
// Get the attribute "friendly" name.
//
WCHAR wzBuf[MAX_PATH + 1]; IDsDisplaySpecifier * pDispSpec;
hr = m_pPage->GetIDispSpec(&pDispSpec);
CHECK_HRESULT_REPORT(hr, hDlg, return 0);
//
// If this is multi-select it must be a homogenous selection so if
// m_pPage->GetObjClass() returns NULL then get the class from the data object
//
CStrW szClassName = m_pPage->GetObjClass(); if (szClassName.IsEmpty()) { //
// For the retrieval of the DS Object names
//
FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM objMedium; hr = m_pPage->m_pWPTDataObj->GetData(&fmte, &objMedium); CHECK_HRESULT(hr, return FALSE);
LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
//
// Get the objects class
//
szClassName = (PWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetClass);
ReleaseStgMedium(&objMedium); } hr = pDispSpec->GetFriendlyAttributeName((LPCWSTR)szClassName, m_pAttrLDAPname, wzBuf, MAX_PATH); CHECK_HRESULT_REPORT(hr, hDlg, return 0);
if (!UnicodeToTchar(wzBuf, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, hDlg); return 0; } //_tcscat(szCaption, ptz);
SetWindowText(hDlg, ptz); delete [] ptz;
// Limit the entry length of the edit control.
//
SendDlgItemMessage(hDlg, IDC_EDIT, EM_LIMITTEXT, m_nMaxLen, 0);
// Initialize the list view.
//
RECT rect; LV_COLUMN lvc; hList = GetDlgItem(hDlg, IDC_LIST); ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT); if (!m_fWritable) { LONG_PTR lStyle = GetWindowLongPtr(hList, GWL_STYLE); lStyle &= ~(LVS_EDITLABELS); SetWindowLongPtr(hList, GWL_STYLE, lStyle); }
GetClientRect(hList, &rect); lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.cx = rect.right; lvc.iSubItem = 0;
ListView_InsertColumn(hList, 0, &lvc);
// Load the list view.
//
lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iSubItem = 0; lvi.lParam = m_nMaxLen;
for (i = 0; (DWORD)i < m_AttrInfo.dwNumValues; i++) { if (!UnicodeToTchar(m_AttrInfo.pADsValues[i].CaseIgnoreString, &ptz)) { ReportError(E_OUTOFMEMORY, 0, hDlg); return 0; } lvi.pszText = ptz; lvi.iItem = i; ListView_InsertItem(hList, &lvi); m_cValues++;
delete[] ptz; ptz = 0; }
//
// Disable the Add, Change, and Remove buttons.
//
EnableWindow(GetDlgItem(hDlg, IDC_ADD_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), FALSE);
if (!m_fWritable) { EnableWindow(GetDlgItem(hDlg, IDC_EDIT), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), TRUE);
CStr close; BOOL loadResult = close.LoadString(g_hInstance, IDS_CLOSE); dspAssert(loadResult);
if (loadResult) { SetDlgItemText(hDlg, IDC_CLOSE, close); } } //
// Make the CLOSE button the default.
//
int style;
style = (int)GetWindowLongPtr(GetDlgItem(hDlg, IDCANCEL), GWL_STYLE);
style |= BS_DEFPUSHBUTTON;
SendMessage(hDlg, DM_SETDEFID, (WPARAM)IDCANCEL, 0); SendDlgItemMessage(hDlg, IDC_CLOSE, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); SendDlgItemMessage(hDlg, IDCANCEL, BM_SETSTYLE, (WPARAM)LOWORD(style), MAKELPARAM(TRUE, 0)); m_nCurDefCtrl = IDCANCEL; return 1; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::DoCommand
//
// Synopsis: WM_COMMAND code.
//
//-----------------------------------------------------------------------------
int CMultiStringAttr::DoCommand(HWND hDlg, int id, int code) { LPTSTR ptz; LONG i; HWND hList; LV_ITEM lvi; switch (code) { case BN_CLICKED: if (id == IDOK) { // Hitting Return causes IDOK to be sent. Replace that with the
// ID of the control that is currently the default.
//
id = m_nCurDefCtrl; } switch (id) { case IDC_ADD_BTN: if (m_nLimit && (m_cValues >= m_nLimit)) { ErrMsgParam(IDS_MULTISEL_LIMIT, (LPARAM)m_nLimit, hDlg); return 1; } ptz = new TCHAR[m_nMaxLen + 1];
CHECK_NULL_REPORT(ptz, hDlg, return -1); // NTRAID#NTBUG9-525208-2002/01/29-ronmart-off by one error on buffer len
if (GetWindowText(GetDlgItem(hDlg, IDC_EDIT), ptz, m_nMaxLen + 1)) { hList = GetDlgItem(hDlg, IDC_LIST); //
// See if the string already exists
//
LVFINDINFO lvSearchInfo = {0}; lvSearchInfo.flags = LVFI_STRING; lvSearchInfo.psz = ptz; i = ListView_FindItem(hList, -1, &lvSearchInfo); if (i == -1) { i = ListView_GetItemCount(hList); // NTRAID#NTBUG9-525198-2002/01/29-ronmart-store max length in lparam
lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iSubItem = 0; lvi.pszText = ptz; // NTRAID#NTBUG9-525198-2002/01/29-ronmart-Set the max length allowed
lvi.lParam = m_nMaxLen; lvi.iItem = i; ListView_InsertItem(hList, &lvi); //Make this item selected and make it visible
ListView_SetItemState( hList, i, LVIS_SELECTED|LVIS_FOCUSED , LVIS_SELECTED|LVIS_FOCUSED ); } ListView_EnsureVisible(hList, i, FALSE);
m_cValues++;
SetWindowText(GetDlgItem(hDlg, IDC_EDIT), TEXT("")); //
// Disable the Save button and make the OK button the
// default.
//
ToggleMVDefaultBtn(hDlg, TRUE);
m_nCurDefCtrl = IDC_CLOSE; SetDirty(hDlg); }
delete [] ptz;
return 1;
case IDC_DELETE_BTN: case IDC_EDIT_BTN: hList = GetDlgItem(hDlg, IDC_LIST);
i = ListView_GetNextItem(hList, -1, LVNI_SELECTED); dspDebugOut((DEB_ITRACE, "List element %d selected\n", i));
if (i >= 0) { if (id == IDC_DELETE_BTN) { ListView_DeleteItem(hList, i); m_cValues--;
//Get the count of list view items
LONG itemCount = ListView_GetItemCount(hList); if(itemCount) { ListView_SetItemState( hList, (itemCount > i) ? i : i-1, LVIS_SELECTED|LVIS_FOCUSED , LVIS_SELECTED|LVIS_FOCUSED ); } else { EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE); SetFocus(GetDlgItem(hDlg, IDC_EDIT)); m_fListHasSel = FALSE; } SetDirty(hDlg); ToggleMVDefaultBtn(hDlg, TRUE); } else { ToggleMVDefaultBtn(hDlg, TRUE); SetFocus(GetDlgItem(hDlg, IDC_LIST)); ListView_EditLabel(hList, i); } }
return 1;
case IDC_CLOSE: { // Copy the list box back to the attr info list.
//
int nItems; ClearAttrInfo(); m_fListHasSel = FALSE;
hList = GetDlgItem(hDlg, IDC_LIST); nItems = ListView_GetItemCount(hList);
if (nItems == 0) { EndDialog(hDlg, IDOK); return 1; }
m_AttrInfo.pADsValues = new ADSVALUE[nItems];
CHECK_NULL_REPORT(m_AttrInfo.pADsValues, hDlg, return -1);
ptz = new TCHAR[m_nMaxLen + 1];
CHECK_NULL_REPORT(ptz, hDlg, return -1);
lvi.mask = LVIF_TEXT; lvi.iSubItem = 0; lvi.pszText = ptz; lvi.cchTextMax = m_nMaxLen + 1;
for (i = 0; i < nItems; i++) { lvi.iItem = i; if (!ListView_GetItem(hList, &lvi)) { REPORT_ERROR(GetLastError(), hDlg); delete [] ptz; EndDialog(hDlg, IDCANCEL); return -1; } if (!TcharToUnicode(ptz, &m_AttrInfo.pADsValues[i].CaseIgnoreString)) { REPORT_ERROR(E_OUTOFMEMORY, hDlg); return E_OUTOFMEMORY; } m_AttrInfo.pADsValues[i].dwType = m_AttrInfo.dwADsType; m_AttrInfo.dwNumValues++; } delete [] ptz; EndDialog(hDlg, IDOK); } return IDOK;
case IDCANCEL: m_fListHasSel = FALSE; EndDialog(hDlg, IDCANCEL); return IDCANCEL; } break;
case EN_CHANGE: if (id == IDC_EDIT) { BOOL fEnableAdd = FALSE; LRESULT lTextLen = SendDlgItemMessage(hDlg, IDC_EDIT, WM_GETTEXTLENGTH, 0, 0);
PTSTR pszText = new TCHAR[lTextLen + 1]; if (pszText != NULL) { if (!GetDlgItemText(hDlg, IDC_EDIT, pszText, static_cast<int>(lTextLen + 1))) { fEnableAdd = lTextLen > 0; } else { CStr strText; strText = pszText; strText.TrimLeft(); strText.TrimRight();
if (strText.IsEmpty()) { fEnableAdd = FALSE; } else { fEnableAdd = TRUE; } } delete[] pszText; } else { fEnableAdd = lTextLen > 0; }
if (fEnableAdd && (m_nCurDefCtrl == IDC_ADD_BTN)) { return 1; }
m_nCurDefCtrl = (fEnableAdd) ? IDC_ADD_BTN : IDC_CLOSE;
EnableWindow(GetDlgItem(hDlg, IDC_ADD_BTN), fEnableAdd);
ToggleMVDefaultBtn(hDlg, !fEnableAdd);
return 1; } break; } return 0; }
//+----------------------------------------------------------------------------
//
// Member: CMultiStringAttr::DoNotify
//
// Synopsis: WM_NOTIFY code.
//
//-----------------------------------------------------------------------------
BOOL CMultiStringAttr::DoNotify(HWND hDlg, NMHDR * pNmHdr) { if (pNmHdr->idFrom != IDC_LIST) { return TRUE; }
LV_DISPINFO * pldi = (LV_DISPINFO *)pNmHdr;
switch (pNmHdr->code) { case LVN_ENDLABELEDIT: if (pldi->item.pszText) { // NTRAID#NTBUG9-525223-2002/01/29-ronmart-don't allow zero length string
// NTRAID#NTBUG9-525198-2002/01/29-ronmart-Check the lParam for the max length allowed
int nLen = lstrlen(pldi->item.pszText); if(nLen < 1 || nLen > pldi->item.lParam) return FALSE; dspDebugOut((DEB_ITRACE, "Editing item %d, new value %S\n", pldi->item.iItem, pldi->item.pszText)); ListView_SetItemText(pldi->hdr.hwndFrom, pldi->item.iItem, 0, pldi->item.pszText);
//
// Disable the Save button and make the OK button the
// default.
//
SetDirty(hDlg); ToggleMVDefaultBtn(hDlg, TRUE); } break;
case NM_SETFOCUS: dspDebugOut((DEB_ITRACE, "NM_SETFOCUS received\n")); if (pldi->hdr.idFrom == IDC_LIST) { //
// If the list control gets the focus by tabbing and no item
// is selected, then set the selection to the first item.
//
if (!m_fListHasSel && ListView_GetItemCount(GetDlgItem(hDlg, IDC_LIST))) { dspDebugOut((DEB_ITRACE, "setting the list selection\n")); m_fListHasSel = TRUE; ListView_SetItemState(GetDlgItem(hDlg, IDC_LIST), 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); if (m_fWritable) { EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), TRUE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), TRUE); } } } return 1;
case LVN_ITEMCHANGED: if (pldi->hdr.idFrom == IDC_LIST) { if(ListView_GetSelectedCount(GetDlgItem(hDlg, IDC_LIST))) { m_fListHasSel = TRUE; if (m_fWritable) { EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), TRUE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), TRUE); } } else { m_fListHasSel = FALSE; if (m_fWritable) { EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE); } } } return 1; } return 0; }
//+----------------------------------------------------------------------------
//
// Function: OtherValuesBtn
//
// Synopsis: "Others..." button that brings up a dialog (similar to the
// multi-valued attribute dialog) to modify the otherXXXX
// attribute. Usage: if a multi-valued property needs to
// have one value designated at the primary value, then this
// must be expressed as two separate attributes since multi-
// valued attributes are un-ordered. For example, consider tele-
// phone numbers; Telephone-Number, which is single-valued is the
// primary value and Phone-Office-Other, which is multi-valued,
// is used to store the "other" numbers.
//
//-----------------------------------------------------------------------------
HRESULT OtherValuesBtn(CDsPropPageBase * pPage, PATTR_MAP pAttrMap, PADS_ATTR_INFO pAttrInfo, LPARAM lParam, PATTR_DATA pAttrData, DLG_OP DlgOp) { HRESULT hr = S_OK; CMultiStringAttrDlg * pMultiS = NULL;
switch (DlgOp) { case fInit: { pMultiS = new CMultiStringAttrDlg(pPage);
CHECK_NULL_REPORT(pMultiS, pPage->GetHWnd(), return E_OUTOFMEMORY);
BOOL fMultiselectPage = pPage->IsMultiselectPage(); hr = pMultiS->Init(pAttrMap, pAttrInfo, PATTR_DATA_IS_WRITABLE(pAttrData), 0, FALSE, fMultiselectPage);
CHECK_HRESULT(hr, return hr);
pAttrData->pVoid = reinterpret_cast<LPARAM>(pMultiS); // save the object pointer.
} break;
case fOnCommand: if (lParam == BN_CLICKED) { CHECK_NULL(pAttrData->pVoid, return E_OUTOFMEMORY); pMultiS = (CMultiStringAttrDlg *)pAttrData->pVoid;
if (IDOK == pMultiS->Edit()) { PATTR_DATA_SET_DIRTY(pAttrData); } } break;
case fApply: if (!PATTR_DATA_IS_DIRTY(pAttrData)) { return ADM_S_SKIP; } CHECK_NULL(pAttrData->pVoid, return E_OUTOFMEMORY); pMultiS = (CMultiStringAttrDlg *)pAttrData->pVoid;
return pMultiS->Write(pAttrInfo);
case fOnDestroy: if (pAttrData->pVoid) { delete (CMultiStringAttrDlg *)pAttrData->pVoid; } break; } return S_OK; }
//+----------------------------------------------------------------------------
//
// Function ToggleMVDefaultBtn
//
// Synopsis: Toggle the default pushbutton of the multi-valued dialog.
//
//-----------------------------------------------------------------------------
void ToggleMVDefaultBtn(HWND hDlg, BOOL fOK) { LONG style, newstyle; int nDefault = IDC_CLOSE, nNotDefault = IDC_ADD_BTN;
if (!fOK) { nDefault = IDC_ADD_BTN; nNotDefault = IDC_CLOSE; }
//
// Clear the default bit on this one.
//
style = (LONG)GetWindowLongPtr(GetDlgItem(hDlg, nNotDefault), GWL_STYLE);
newstyle = style & ~(BS_DEFPUSHBUTTON);
SendDlgItemMessage(hDlg, nNotDefault, BM_SETSTYLE, (WPARAM)LOWORD(newstyle), MAKELPARAM(TRUE, 0));
//
// Make this one the default.
//
style = (LONG)GetWindowLongPtr(GetDlgItem(hDlg, nDefault), GWL_STYLE);
newstyle = style | BS_DEFPUSHBUTTON;
SendMessage(hDlg, DM_SETDEFID, (WPARAM)nDefault, 0); SendDlgItemMessage(hDlg, nDefault, BM_SETSTYLE, (WPARAM)LOWORD(newstyle), MAKELPARAM(TRUE, 0)); if (fOK) { SetFocus(GetDlgItem(hDlg, IDC_EDIT)); } }
//+----------------------------------------------------------------------------
//
// Function: GetObjectClass
//
// Synopsis: Object page attribute function for object class.
//
//-----------------------------------------------------------------------------
HRESULT GetObjectClass(CDsPropPageBase * pPage, PATTR_MAP, PADS_ATTR_INFO, LPARAM, PATTR_DATA, DLG_OP DlgOp) { if (DlgOp == fInit) { WCHAR wszBuf[120]; PTSTR ptz; HRESULT hr; IDsDisplaySpecifier * pDispSpec;
hr = pPage->GetIDispSpec(&pDispSpec);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr); //
// Look up the localized class name on the object display
// specification cache.
//
hr = pDispSpec->GetFriendlyClassName(pPage->GetObjClass(), wszBuf, 120);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
if (!UnicodeToTchar(wszBuf, &ptz)) { REPORT_ERROR(E_OUTOFMEMORY, pPage->GetHWnd()); return E_OUTOFMEMORY; }
SetDlgItemText(pPage->GetHWnd(), IDC_CLASS_STATIC, ptz);
delete [] ptz; }
return S_OK; }
//+----------------------------------------------------------------------------
//
// Function: GetObjectTimestamp
//
// Synopsis: Object page attribute function for object timestamps.
//
//-----------------------------------------------------------------------------
HRESULT GetObjectTimestamp(CDsPropPageBase * pPage, PATTR_MAP pAttrMap, PADS_ATTR_INFO pAttrInfo, LPARAM, PATTR_DATA, DLG_OP DlgOp) { DWORD dwErr;
if ((DlgOp == fInit) && pPage) { TCHAR tszBuf[MAX_MSG_LEN];
if (pAttrInfo && pAttrInfo->dwNumValues && pAttrInfo->pADsValues && pAttrInfo->pADsValues->dwType == ADSTYPE_UTC_TIME) { SYSTEMTIME st = {0};
if (!SystemTimeToTzSpecificLocalTime(NULL, &pAttrInfo->pADsValues->UTCTime, &st)) { dwErr = GetLastError(); CHECK_WIN32_REPORT(dwErr, pPage->GetHWnd(), return dwErr); }
int cch = GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, tszBuf, MAX_MSG_LEN); if (cch == 0) { dwErr = GetLastError(); CHECK_WIN32_REPORT(dwErr, pPage->GetHWnd(), return dwErr); } //NTRAID#NTBUG9-573434-2002/03/10-jmessec possible buffer overrun
_tcscat(tszBuf, TEXT(" ")); cch = static_cast<int>(_tcslen(tszBuf));
GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, tszBuf + cch, MAX_MSG_LEN - cch); } else { if (!LoadString(g_hInstance, IDS_NO_VALUE, tszBuf, MAX_MSG_LEN - 1)) { _tcscpy(tszBuf, TEXT(" ")); } }
int nCtrl = 0;
switch (pAttrMap->nCtrlID) { case IDC_CREATED_TIME_STATIC: DBG_OUT("Getting creation timestamp."); nCtrl = IDC_CREATED_TIME_STATIC; break;
case IDC_MODIFIED_TIME_STATIC: DBG_OUT("Getting last modification timestamp."); nCtrl = IDC_MODIFIED_TIME_STATIC; break;
default: REPORT_ERROR(E_INVALIDARG, pPage->GetHWnd()); }
SetDlgItemText(pPage->GetHWnd(), nCtrl, tszBuf); }
return S_OK; }
//+----------------------------------------------------------------------------
//
// Function: UnescapeCanonicalNameEx
//
// Synopsis: Takes a canonical name in the DS_CANONICAL_NAME format
// and removes the escaping
//
//-----------------------------------------------------------------------------
HRESULT UnescapeCanonicalNameEx( PCWSTR pszName, CStrW& strUnescapedName) { HRESULT hr = S_OK;
strUnescapedName = pszName;
return hr; } //+----------------------------------------------------------------------------
//
// Function: ObjectPathField
//
// Synopsis: Handles the Object page path field.
//
//-----------------------------------------------------------------------------
HRESULT ObjectPathField(CDsPropPageBase * pPage, PATTR_MAP, PADS_ATTR_INFO, LPARAM, PATTR_DATA, DLG_OP DlgOp) { if (DlgOp == fInit) { PWSTR pwzPath, pwzDNSname;
HRESULT hr = pPage->SkipPrefix(pPage->GetObjPathName(), &pwzPath);
CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
hr = CrackName(pwzPath, &pwzDNSname, GET_OBJ_CAN_NAME, pPage->GetHWnd());
delete [] pwzPath;
CHECK_HRESULT(hr, return hr);
CStrW strUnescapedCanonicalName; hr = UnescapeCanonicalNameEx(pwzDNSname, strUnescapedCanonicalName); dspAssert(SUCCEEDED(hr));
LocalFreeStringW(&pwzDNSname);
PTSTR ptszPath;
if (!UnicodeToTchar((PWSTR)(PCWSTR)strUnescapedCanonicalName, &ptszPath)) { REPORT_ERROR(E_OUTOFMEMORY, pPage->GetHWnd()); return E_OUTOFMEMORY; }
SetDlgItemText(pPage->GetHWnd(), IDC_PATH_FIELD, ptszPath);
delete [] ptszPath; }
return S_OK; }
|