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.
1054 lines
33 KiB
1054 lines
33 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Windows NT Directory Service Property Pages
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1999
|
|
//
|
|
// File: tablpage.cxx
|
|
//
|
|
// Contents: CDsTableDrivenPage, the class that implements table-driven
|
|
// property pages
|
|
//
|
|
// History: 1-April-97 EricB created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#include <stdio.h>
|
|
#include "proppage.h"
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CDsTableDrivenPage::CDsTableDrivenPage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CDsTableDrivenPage::CDsTableDrivenPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj,
|
|
HWND hNotifyWnd, DWORD dwFlags) :
|
|
m_pData(NULL),
|
|
CDsPropPageBase(pDsPage, pDataObj, hNotifyWnd, dwFlags)
|
|
{
|
|
TRACE(CDsTableDrivenPage,CDsTableDrivenPage);
|
|
#ifdef _DEBUG
|
|
strcpy(szClass, "CDsTableDrivenPage");
|
|
#endif
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CDsTableDrivenPage::~CDsTableDrivenPage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CDsTableDrivenPage::~CDsTableDrivenPage()
|
|
{
|
|
TRACE(CDsTableDrivenPage,~CDsTableDrivenPage);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateTableDrivenPage
|
|
//
|
|
// Synopsis: Creates an instance of a page window.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CreateTableDrivenPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj,
|
|
PWSTR pwzADsPath, PWSTR pwzClass, HWND hNotifyWnd,
|
|
DWORD dwFlags,
|
|
const CDSSmartBasePathsInfo& basePathsInfo,
|
|
HPROPSHEETPAGE * phPage)
|
|
{
|
|
TRACE_FUNCTION(CreateTableDrivenPage);
|
|
|
|
CDsTableDrivenPage * pPageObj = new CDsTableDrivenPage(pDsPage, pDataObj,
|
|
hNotifyWnd, dwFlags);
|
|
|
|
CHECK_NULL(pPageObj, return E_OUTOFMEMORY);
|
|
|
|
pPageObj->Init(pwzADsPath, pwzClass, basePathsInfo);
|
|
|
|
return pPageObj->CreatePage(phPage);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::DlgProc
|
|
//
|
|
// Synopsis: per-instance dialog proc
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
INT_PTR CALLBACK
|
|
CDsTableDrivenPage::DlgProc(HWND, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == g_uChangeMsg)
|
|
{
|
|
return OnAttrChanged(wParam);
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return InitDlg(lParam);
|
|
|
|
case WM_NOTIFY:
|
|
return OnNotify(wParam, lParam);
|
|
|
|
case PSM_QUERYSIBLINGS:
|
|
return OnQuerySibs(wParam, lParam);
|
|
|
|
case WM_ADSPROP_NOTIFY_CHANGE:
|
|
return OnObjChanged();
|
|
|
|
case WM_SHOWWINDOW:
|
|
return OnShowWindow();
|
|
|
|
case WM_SETFOCUS:
|
|
return OnSetFocus((HWND)wParam);
|
|
|
|
case WM_HELP:
|
|
return OnHelp((LPHELPINFO)lParam);
|
|
|
|
case WM_COMMAND:
|
|
if (m_fInInit)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return(OnCommand(GET_WM_COMMAND_ID(wParam, lParam),
|
|
GET_WM_COMMAND_HWND(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam)));
|
|
case WM_DESTROY:
|
|
return OnDestroy();
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnInitDialog
|
|
//
|
|
// Synopsis: Set the initial control values from the corresponding DS
|
|
// attributes.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDsTableDrivenPage::OnInitDialog(LPARAM)
|
|
{
|
|
TRACE(CDsTableDrivenPage,OnInitDialog);
|
|
|
|
if (!ADsPropSetHwnd(m_hNotifyObj, m_hPage))
|
|
{
|
|
m_pWritableAttrs = NULL;
|
|
}
|
|
|
|
if (SUCCEEDED(m_hrInit))
|
|
{
|
|
return ReadAttrsSetCtrls(fInit);
|
|
}
|
|
else
|
|
{
|
|
// error page is posted automatically.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnApply
|
|
//
|
|
// Synopsis: Handles the Apply notification.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnApply(void)
|
|
{
|
|
TRACE(CDsTableDrivenPage,OnApply);
|
|
HRESULT hr = S_OK;
|
|
LPTSTR ptsz;
|
|
LPWSTR pwszValue;
|
|
PADSVALUE pADsValue;
|
|
DWORD cAttrs = 0;
|
|
|
|
if (m_fReadOnly)
|
|
{
|
|
return PSNRET_NOERROR;
|
|
}
|
|
|
|
PADS_ATTR_INFO pAttrs = new ADS_ATTR_INFO[m_cAttrs];
|
|
CHECK_NULL_REPORT(pAttrs, GetHWnd(), return -1);
|
|
|
|
memset(pAttrs, 0, sizeof(ADS_ATTR_INFO) * m_cAttrs);
|
|
|
|
for (DWORD i = 0; i < m_cAttrs; i++)
|
|
{
|
|
if (m_rgpAttrMap[i]->fIsReadOnly ||
|
|
(!m_rgpAttrMap[i]->pAttrFcn &&
|
|
(!ATTR_DATA_IS_WRITABLE(m_rgAttrData[i]) ||
|
|
!ATTR_DATA_IS_DIRTY(m_rgAttrData[i]))))
|
|
{
|
|
// If the map defines it to be read-only or no attr function is
|
|
// defined and the attribute is not writable or not dirty, then
|
|
// skip it.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
pAttrs[cAttrs] = m_rgpAttrMap[i]->AttrInfo;
|
|
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
// Handle special-case attribute.
|
|
//
|
|
hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
|
|
&pAttrs[cAttrs], 0,
|
|
&m_rgAttrData[i], fApply);
|
|
CHECK_HRESULT(hr, goto Cleanup);
|
|
|
|
if (hr == ADM_S_SKIP)
|
|
{
|
|
// Don't write the attribute.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (hr != S_FALSE)
|
|
{
|
|
// If the attr fcn didn't return S_FALSE, that means that it
|
|
// handled the value. If it did return S_FALSE, then let the
|
|
// standard edit control processing below handle the value.
|
|
//
|
|
cAttrs++;
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (m_rgpAttrMap[i]->AttrInfo.dwADsType == ADSTYPE_BOOLEAN)
|
|
{
|
|
// Handle boolean checkbox attributes.
|
|
//
|
|
|
|
pADsValue = new ADSVALUE;
|
|
CHECK_NULL_REPORT(pADsValue, GetHWnd(), goto Cleanup);
|
|
|
|
pAttrs[cAttrs].pADsValues = pADsValue;
|
|
pAttrs[cAttrs].dwNumValues = 1;
|
|
pADsValue->dwType = m_rgpAttrMap[i]->AttrInfo.dwADsType;
|
|
|
|
pADsValue->Boolean =
|
|
IsDlgButtonChecked(m_hPage, m_rgpAttrMap[i]->nCtrlID)
|
|
== BST_CHECKED;
|
|
cAttrs++;
|
|
|
|
continue;
|
|
}
|
|
|
|
// Assumes that all non-special-case attributes,
|
|
// if single-valued and not boolean, come from a text control.
|
|
//
|
|
ptsz = new TCHAR[m_rgpAttrMap[i]->nSizeLimit + 1];
|
|
CHECK_NULL_REPORT(ptsz, GetHWnd(), goto Cleanup);
|
|
|
|
GetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, ptsz,
|
|
m_rgpAttrMap[i]->nSizeLimit + 1);
|
|
|
|
CStr csValue = ptsz;
|
|
|
|
csValue.TrimLeft();
|
|
csValue.TrimRight();
|
|
|
|
if (_tcslen(ptsz) != (size_t)csValue.GetLength())
|
|
{
|
|
// the length is different, it must have been trimmed. Write trimmed
|
|
// value back to the control.
|
|
//
|
|
SetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, const_cast<PTSTR>((LPCTSTR)csValue));
|
|
}
|
|
delete [] ptsz;
|
|
|
|
if (csValue.IsEmpty())
|
|
{
|
|
// An empty control means remove the attribute value from the
|
|
// object.
|
|
//
|
|
pAttrs[cAttrs].dwControlCode = ADS_ATTR_CLEAR;
|
|
pAttrs[cAttrs].dwNumValues = 0;
|
|
pAttrs[cAttrs].pADsValues = NULL;
|
|
|
|
cAttrs++;
|
|
continue;
|
|
}
|
|
|
|
if (!TcharToUnicode(const_cast<PTSTR>((LPCTSTR)csValue), &pwszValue))
|
|
{
|
|
CHECK_HRESULT_REPORT(E_OUTOFMEMORY, GetHWnd(), goto Cleanup);
|
|
}
|
|
|
|
pADsValue = new ADSVALUE;
|
|
CHECK_NULL_REPORT(pADsValue, GetHWnd(), goto Cleanup);
|
|
|
|
pAttrs[cAttrs].pADsValues = pADsValue;
|
|
pAttrs[cAttrs].dwNumValues = 1;
|
|
pADsValue->dwType = m_rgpAttrMap[i]->AttrInfo.dwADsType;
|
|
|
|
switch (pADsValue->dwType)
|
|
{
|
|
case ADSTYPE_DN_STRING:
|
|
pADsValue->DNString = pwszValue;
|
|
break;
|
|
case ADSTYPE_CASE_EXACT_STRING:
|
|
pADsValue->CaseExactString = pwszValue;
|
|
break;
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
pADsValue->CaseIgnoreString = pwszValue;
|
|
break;
|
|
case ADSTYPE_PRINTABLE_STRING:
|
|
pADsValue->PrintableString = pwszValue;
|
|
break;
|
|
case ADSTYPE_NUMERIC_STRING:
|
|
pADsValue->NumericString = pwszValue;
|
|
break;
|
|
case ADSTYPE_INTEGER:
|
|
pADsValue->Integer = _wtoi(pwszValue);
|
|
break;
|
|
default:
|
|
dspDebugOut((DEB_ERROR, "OnApply: Unknown ADS Type %x\n",
|
|
pADsValue->dwType));
|
|
}
|
|
cAttrs++;
|
|
}
|
|
|
|
// cAttrs could be zero if a page was read-only. Don't call ADSI if so.
|
|
//
|
|
if (cAttrs < 1)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
dspDebugOut((DEB_USER1, "TablePage, about to write %d attrs.\n", cAttrs));
|
|
//
|
|
// Write the changes.
|
|
//
|
|
DWORD cModified;
|
|
|
|
hr = m_pDsObj->SetObjectAttributes(pAttrs, cAttrs, &cModified);
|
|
|
|
CHECK_ADS_HR(&hr, m_hPage);
|
|
|
|
Cleanup:
|
|
|
|
for (i = 0; i < cAttrs; i++)
|
|
HelperDeleteADsValues( &(pAttrs[i]) );
|
|
|
|
delete [] pAttrs;
|
|
|
|
if (SUCCEEDED(hr) && cAttrs > 0)
|
|
{
|
|
for (i = 0; i < m_cAttrs; i++)
|
|
{
|
|
ATTR_DATA_CLEAR_DIRTY(m_rgAttrData[i]);
|
|
}
|
|
}
|
|
|
|
return SUCCEEDED(hr) ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
|
|
}
|
|
|
|
void HelperDeleteADsValues( ADS_ATTR_INFO* pAttrs )
|
|
{
|
|
if (pAttrs)
|
|
{
|
|
if (pAttrs->pADsValues)
|
|
{
|
|
for (DWORD j = 0; j < pAttrs->dwNumValues; j++)
|
|
{
|
|
LPWSTR pwszValue = NULL;
|
|
switch (pAttrs->dwADsType)
|
|
{
|
|
case ADSTYPE_DN_STRING:
|
|
pwszValue = pAttrs->pADsValues[j].DNString;
|
|
break;
|
|
case ADSTYPE_CASE_EXACT_STRING:
|
|
pwszValue = pAttrs->pADsValues[j].CaseExactString;
|
|
break;
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
pwszValue = pAttrs->pADsValues[j].CaseIgnoreString;
|
|
break;
|
|
case ADSTYPE_PRINTABLE_STRING:
|
|
pwszValue = pAttrs->pADsValues[j].PrintableString;
|
|
break;
|
|
case ADSTYPE_NUMERIC_STRING:
|
|
pwszValue = pAttrs->pADsValues[j].NumericString;
|
|
break;
|
|
}
|
|
if (pwszValue)
|
|
delete [] pwszValue;
|
|
}
|
|
delete [] pAttrs->pADsValues;
|
|
}
|
|
pAttrs->pADsValues = NULL;
|
|
pAttrs->dwNumValues = 0;
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnCommand
|
|
//
|
|
// Synopsis: Handle control notifications.
|
|
//
|
|
// Notes: Standard multi-valued attribute handling assumes that the
|
|
// "modify" button has an ID that is one greater than the
|
|
// corresponding combo box.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnCommand(int id, HWND hwndCtl, UINT codeNotify)
|
|
{
|
|
if (m_fInInit)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
for (i = 0; i < m_cAttrs; i++)
|
|
{
|
|
if (id == m_rgpAttrMap[i]->nCtrlID)
|
|
{
|
|
// Give attr functions first crack at the command notification.
|
|
//
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
|
|
codeNotify, &m_rgAttrData[i],
|
|
fOnCommand);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
// If the attr function returns S_FALSE, then don't return
|
|
// to the base class OnCommand.
|
|
//
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if (codeNotify == BN_CLICKED &&
|
|
m_rgpAttrMap[i]->AttrInfo.dwADsType == ADSTYPE_BOOLEAN)
|
|
{
|
|
// NOTE: Must do this to allow saving from the WAB-hosted sheet.
|
|
EnableWindow(GetDlgItem(GetParent(m_hPage), IDOK), TRUE);
|
|
// NOTE: end hack.
|
|
|
|
// The check box was clicked.
|
|
//
|
|
SetDirty(i);
|
|
|
|
return CDsPropPageBase::OnCommand(id, hwndCtl, codeNotify);
|
|
}
|
|
if (codeNotify == EN_CHANGE)
|
|
{
|
|
// NOTE: Must do this to allow saving from the WAB-hosted sheet.
|
|
EnableWindow(GetDlgItem(GetParent(m_hPage), IDOK), TRUE);
|
|
// Note: End Hack.
|
|
|
|
SetDirty(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
return CDsPropPageBase::OnCommand(id, hwndCtl, codeNotify);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnObjChanged
|
|
//
|
|
// Synopsis: Object Change notification for inter-sheet syncronization.
|
|
// Handles the private WM_ADSPROP_NOTIFY_CHANGE message.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnObjChanged(void)
|
|
{
|
|
TRACE(CDsTableDrivenPage,OnObjChanged);
|
|
return ReadAttrsSetCtrls(fObjChanged);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::ReadAttrsSetCtrls
|
|
//
|
|
// Synopsis: Refreshes the UI.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
CDsTableDrivenPage::ReadAttrsSetCtrls(DLG_OP DlgOp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PADS_ATTR_INFO pAttrs = NULL;
|
|
DWORD cAttrs = 0, i, j;
|
|
CWaitCursor wait;
|
|
|
|
PWSTR * rgpwszAttrNames = new LPWSTR[m_cAttrs];
|
|
CHECK_NULL_REPORT(rgpwszAttrNames, GetHWnd(), return E_OUTOFMEMORY);
|
|
|
|
if (fInit == DlgOp)
|
|
{
|
|
// Check what attributes are writable.
|
|
//
|
|
CheckIfPageAttrsWritable();
|
|
}
|
|
|
|
// Build the list of attribute names.
|
|
//
|
|
for (i = 0; i < m_cAttrs; i++)
|
|
{
|
|
// If the attr name in the table is null, then don't try to do a
|
|
// fetch on that attr. Attr table entries of that sort are used for
|
|
// special purposes such as push buttons or check boxes. If the
|
|
// attr name is set to null, then the attr must be declared as read-
|
|
// only.
|
|
//
|
|
if (m_rgpAttrMap[i]->AttrInfo.pszAttrName)
|
|
{
|
|
// If the attribute already appears in the attribute list
|
|
// then don't add it again
|
|
bool fAlreadyPresent = false;
|
|
for (j = 0; j < cAttrs; j++)
|
|
{
|
|
if ( _wcsicmp(m_rgpAttrMap[i]->AttrInfo.pszAttrName,
|
|
rgpwszAttrNames[j] ) == 0 )
|
|
{
|
|
fAlreadyPresent = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!fAlreadyPresent)
|
|
{
|
|
rgpwszAttrNames[cAttrs] = m_rgpAttrMap[i]->AttrInfo.pszAttrName;
|
|
cAttrs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the attribute values.
|
|
//
|
|
hr = m_pDsObj->GetObjectAttributes(rgpwszAttrNames, cAttrs, &pAttrs,
|
|
&cAttrs);
|
|
if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, m_hPage))
|
|
{
|
|
goto ExitCleanup;
|
|
}
|
|
|
|
// The returned values are a subset of the requested values. Loop over
|
|
// both sets, checking for matches.
|
|
//
|
|
// JonN 5/5/98 Removed assumption that returned values are in same order,
|
|
// added support for multiple table entries for same attribute (all but
|
|
// one must be read-only)
|
|
//
|
|
for (i = 0; i < m_cAttrs; i++)
|
|
{
|
|
if (!ATTR_DATA_IS_WRITABLE(m_rgAttrData[i]) &&
|
|
!m_rgpAttrMap[i]->fIsReadOnly &&
|
|
!m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
// If user does not have write permission for the attribute and
|
|
// the control is not already read-only and there is no attr
|
|
// function then disable the control.
|
|
//
|
|
if (ADSTYPE_CASE_IGNORE_STRING == m_rgpAttrMap[i]->AttrInfo.dwADsType &&
|
|
!m_rgpAttrMap[i]->fIsMultiValued)
|
|
{
|
|
// If it is a single-valued text attribute, make its edit box
|
|
// read only.
|
|
//
|
|
SendDlgItemMessage(m_hPage, m_rgpAttrMap[i]->nCtrlID, EM_SETREADONLY, (WPARAM)TRUE, 0);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(m_hPage, m_rgpAttrMap[i]->nCtrlID), FALSE);
|
|
}
|
|
}
|
|
BOOL fFound = FALSE;
|
|
for (j = 0; j < cAttrs; j++)
|
|
{
|
|
if (m_rgpAttrMap[i]->AttrInfo.pszAttrName &&
|
|
_wcsicmp(m_rgpAttrMap[i]->AttrInfo.pszAttrName,
|
|
pAttrs[j].pszAttrName) == 0)
|
|
{
|
|
dspAssert(!fFound);
|
|
fFound = TRUE;
|
|
|
|
if (m_rgpAttrMap[i]->AttrInfo.dwADsType != pAttrs[j].dwADsType)
|
|
{
|
|
dspDebugOut((DEB_ITRACE,
|
|
"ADsType: from table = %d, returned = %d.\n",
|
|
m_rgpAttrMap[i]->AttrInfo.dwADsType,
|
|
pAttrs[j].dwADsType));
|
|
m_rgpAttrMap[i]->AttrInfo.dwADsType = pAttrs[j].dwADsType;
|
|
}
|
|
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
// Handle special-case attribute
|
|
//
|
|
hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
|
|
&pAttrs[j], 0,
|
|
&m_rgAttrData[i], DlgOp);
|
|
if (hr != S_FALSE)
|
|
{
|
|
// If the attr function returns S_FALSE, that means
|
|
// let the standard text control processing below
|
|
// display the value.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
dspAssert(pAttrs[j].dwNumValues > 0);
|
|
|
|
if (m_rgpAttrMap[i]->AttrInfo.dwADsType == ADSTYPE_BOOLEAN)
|
|
{
|
|
// Handle boolean attribute, initialize the checkbox.
|
|
//
|
|
if (pAttrs[j].pADsValues->Boolean)
|
|
{
|
|
CheckDlgButton(m_hPage, m_rgpAttrMap[i]->nCtrlID,
|
|
BST_CHECKED);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Assumes that all non-special-case attributes, if
|
|
// single-valued and not boolean, go into a text control.
|
|
//
|
|
SendDlgItemMessage(m_hPage, m_rgpAttrMap[i]->nCtrlID,
|
|
EM_LIMITTEXT, m_rgpAttrMap[i]->nSizeLimit,
|
|
0);
|
|
LPTSTR ptszValue = NULL;
|
|
LPWSTR pwszValue;
|
|
WCHAR wszNum[64];
|
|
switch (pAttrs[j].dwADsType)
|
|
{
|
|
case ADSTYPE_DN_STRING:
|
|
pwszValue = pAttrs[j].pADsValues->DNString;
|
|
break;
|
|
case ADSTYPE_CASE_EXACT_STRING:
|
|
pwszValue = pAttrs[j].pADsValues->CaseExactString;
|
|
break;
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
pwszValue = pAttrs[j].pADsValues->CaseIgnoreString;
|
|
break;
|
|
case ADSTYPE_PRINTABLE_STRING:
|
|
pwszValue = pAttrs[j].pADsValues->PrintableString;
|
|
break;
|
|
case ADSTYPE_NUMERIC_STRING:
|
|
pwszValue = pAttrs[j].pADsValues->NumericString;
|
|
break;
|
|
case ADSTYPE_INTEGER:
|
|
wsprintfW(wszNum, L"%d", pAttrs[j].pADsValues->Integer);
|
|
pwszValue = wszNum;
|
|
break;
|
|
case ADSTYPE_LARGE_INTEGER:
|
|
__int64 i64;
|
|
memcpy(&i64, &pAttrs[j].pADsValues->LargeInteger,
|
|
sizeof(pAttrs[j].pADsValues->LargeInteger));
|
|
swprintf(wszNum, L"%I64d", i64);
|
|
pwszValue = wszNum;
|
|
break;
|
|
default:
|
|
dspDebugOut((DEB_ERROR, "Unknown ADS Type %x\n",
|
|
pAttrs[j].dwADsType));
|
|
pwszValue = L"";
|
|
}
|
|
|
|
if (!UnicodeToTchar(pwszValue, &ptszValue))
|
|
{
|
|
goto ExitCleanup;
|
|
}
|
|
|
|
SetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, ptszValue);
|
|
|
|
delete [] ptszValue;
|
|
|
|
break;
|
|
}
|
|
}
|
|
if (!fFound)
|
|
{
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
(*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
|
|
0, &m_rgAttrData[i], DlgOp);
|
|
continue;
|
|
}
|
|
if (!m_rgpAttrMap[i]->fIsMultiValued)
|
|
{
|
|
SendDlgItemMessage(m_hPage, m_rgpAttrMap[i]->nCtrlID,
|
|
EM_LIMITTEXT, m_rgpAttrMap[i]->nSizeLimit,
|
|
0);
|
|
switch (m_rgpAttrMap[i]->AttrInfo.dwADsType)
|
|
{
|
|
case ADSTYPE_DN_STRING:
|
|
case ADSTYPE_CASE_EXACT_STRING:
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
case ADSTYPE_PRINTABLE_STRING:
|
|
case ADSTYPE_NUMERIC_STRING:
|
|
SetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, TEXT(""));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExitCleanup:
|
|
|
|
if (pAttrs)
|
|
{
|
|
FreeADsMem(pAttrs);
|
|
}
|
|
|
|
delete [] rgpwszAttrNames;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnAttrChanged
|
|
//
|
|
// Synopsis: Attribute Change notification for inter-page syncronization.
|
|
// Handles the private DSPROP_ATTRCHANGED_MSG message.
|
|
//
|
|
// Arguments: wParam - contains a pointer to an ADS_ATTR_INFO that contains
|
|
// the changed attribute value. The attribute is named
|
|
// in this struct, so it is self-describing.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnAttrChanged(WPARAM wParam)
|
|
{
|
|
if (m_fInInit)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (DWORD i = 0; i < m_cAttrs; i++)
|
|
{
|
|
// Call attr functions.
|
|
//
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
(*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
|
|
(PADS_ATTR_INFO)wParam, 0,
|
|
&m_rgAttrData[i], fAttrChange);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnQuerySibs
|
|
//
|
|
// Synopsis: Inter-page communication. Handles the PSM_QUERYSIBLINGS msg.
|
|
//
|
|
// Arguments: wParam - pointer to the name of the attribute in question.
|
|
// lParam - HWND of the page that wants to know if the attr has
|
|
// changed.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnQuerySibs(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (m_fInInit)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
LRESULT ret = 0;
|
|
HRESULT hr;
|
|
|
|
for (DWORD i = 0; i < m_cAttrs; i++)
|
|
{
|
|
// Call attr functions.
|
|
//
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
|
|
(PADS_ATTR_INFO)wParam, lParam,
|
|
&m_rgAttrData[i], fQuerySibling);
|
|
if (hr != S_OK)
|
|
{
|
|
ret = hr;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnNotify
|
|
//
|
|
// Synopsis: Handles notification messages
|
|
//
|
|
// Arguments: [lParam] - a pointer to a NMHDR structure.
|
|
// [wParam] - the control ID.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnNotify(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
DWORD i;
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (((LPNMHDR)lParam)->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
case PSN_KILLACTIVE:
|
|
if (m_fInInit)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < m_cAttrs; i++)
|
|
{
|
|
// Call attr functions.
|
|
//
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
|
|
lParam,
|
|
&m_rgAttrData[i],
|
|
(PSN_SETACTIVE == ((LPNMHDR)lParam)->code) ?
|
|
fOnSetActive : fOnKillActive);
|
|
|
|
if (PSNRET_INVALID_NOCHANGEPAGE == HRESULT_CODE(hr))
|
|
{
|
|
SetWindowLongPtr(m_hPage, DWLP_MSGRESULT,
|
|
(LONG_PTR)PSNRET_INVALID_NOCHANGEPAGE);
|
|
return PSNRET_INVALID_NOCHANGEPAGE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (!m_fInInit)
|
|
{
|
|
for (i = 0; i < m_cAttrs; i++)
|
|
{
|
|
// Call attr functions.
|
|
//
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
(*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
|
|
lParam,
|
|
&m_rgAttrData[i], fOnNotify);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return CDsPropPageBase::OnNotify(wParam, lParam);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::OnDestroy
|
|
//
|
|
// Synopsis: Exit cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsTableDrivenPage::OnDestroy(void)
|
|
{
|
|
if (FAILED(m_hrInit))
|
|
{
|
|
return 0;
|
|
}
|
|
//
|
|
// Allow attr functions to do control cleanup.
|
|
//
|
|
for (DWORD i = 0; i < m_cAttrs; i++)
|
|
{
|
|
if (m_rgpAttrMap[i]->pAttrFcn)
|
|
{
|
|
(*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
|
|
0, &m_rgAttrData[i], fOnDestroy);
|
|
}
|
|
}
|
|
// If an application processes this message, it should return zero.
|
|
return 0;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsTableDrivenPage::SetNamedAttrDirty
|
|
//
|
|
// Synopsis: Set a specific attribute dirty
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CDsTableDrivenPage::SetNamedAttrDirty( LPCWSTR pszAttrName )
|
|
{
|
|
for (DWORD i = 0; i < m_cAttrs; i++)
|
|
{
|
|
if ( NULL != m_rgpAttrMap[i]->AttrInfo.pszAttrName
|
|
&& !_wcsicmp(pszAttrName, m_rgpAttrMap[i]->AttrInfo.pszAttrName)
|
|
&& !m_rgpAttrMap[i]->fIsReadOnly
|
|
)
|
|
{
|
|
SetDirty(i);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GeneralPageIcon
|
|
//
|
|
// Synopsis: Fetches the icon for the object class from the display spec
|
|
// cache and draws it on the page. The GenIcon ATTR_MAP uses the
|
|
// control ID IDC_DS_ICON. To use this, add an icon control to
|
|
// your page sized appropriately (20 x 20) and labeled
|
|
// IDC_DS_ICON, then add GenIcon to your ATTR_MAP array.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT GeneralPageIcon(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
|
|
PADS_ATTR_INFO, LPARAM, PATTR_DATA pAttrData,
|
|
DLG_OP DlgOp)
|
|
{
|
|
HRESULT hr;
|
|
HICON hIcon;
|
|
HWND hIconCtrl;
|
|
CDsIconCtrl * pIconCtrl;
|
|
|
|
switch (DlgOp)
|
|
{
|
|
case fInit:
|
|
IDsDisplaySpecifier * pDispSpec;
|
|
|
|
hr = pPage->GetIDispSpec(&pDispSpec);
|
|
|
|
CHECK_HRESULT(hr, return hr);
|
|
|
|
hIconCtrl = GetDlgItem(pPage->GetHWnd(), pAttrMap->nCtrlID);
|
|
|
|
hIcon = pDispSpec->GetIcon(pPage->GetObjClass(),
|
|
DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON,
|
|
32, 32);
|
|
|
|
// NULL return puts up a default icon
|
|
CHECK_NULL(hIcon, return S_OK);
|
|
|
|
pIconCtrl = new CDsIconCtrl(hIconCtrl, hIcon);
|
|
|
|
CHECK_NULL_REPORT(pIconCtrl, pPage->GetHWnd(), return E_OUTOFMEMORY);
|
|
|
|
pAttrData->pVoid = reinterpret_cast<LPARAM>(pIconCtrl);
|
|
|
|
break;
|
|
|
|
case fOnDestroy:
|
|
if (pAttrData->pVoid)
|
|
{
|
|
pIconCtrl = (CDsIconCtrl *)pAttrData->pVoid;
|
|
DO_DEL(pIconCtrl);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Class: CDsIconCtrl
|
|
//
|
|
// Synopsis: Icon control window subclass object, so we can paint a class-
|
|
// specific icon.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CDsIconCtrl::CDsIconCtrl(HWND hCtrl, HICON hIcon) :
|
|
m_hCtrl(hCtrl),
|
|
m_hIcon(hIcon),
|
|
m_pOldProc(NULL)
|
|
{
|
|
SetWindowLongPtr(hCtrl, GWLP_USERDATA, (LONG_PTR)this);
|
|
m_pOldProc = (WNDPROC)SetWindowLongPtr(hCtrl, GWLP_WNDPROC, (LONG_PTR)StaticCtrlProc);
|
|
m_hDlg = GetParent(hCtrl);
|
|
}
|
|
|
|
CDsIconCtrl::~CDsIconCtrl(void)
|
|
{
|
|
SetWindowLongPtr(m_hCtrl, GWLP_WNDPROC, (LONG_PTR)m_pOldProc);
|
|
DestroyIcon(m_hIcon);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsIconCtrl::StaticCtrlProc
|
|
//
|
|
// Synopsis: control sub-proc
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT CALLBACK
|
|
CDsIconCtrl::StaticCtrlProc(HWND hCtrl, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CDsIconCtrl * pCCtrl = (CDsIconCtrl*)GetWindowLongPtr(hCtrl, GWLP_USERDATA);
|
|
|
|
if (pCCtrl != NULL)
|
|
{
|
|
if (uMsg == WM_PAINT)
|
|
{
|
|
if (!pCCtrl->OnPaint())
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
return CallWindowProc(pCCtrl->m_pOldProc, hCtrl, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
return DefWindowProc(hCtrl, uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CDsIconCtrl::OnPaint
|
|
//
|
|
// Synopsis: Paint the DS specified icon.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LRESULT
|
|
CDsIconCtrl::OnPaint(void)
|
|
{
|
|
HDC hDC;
|
|
PAINTSTRUCT ps;
|
|
|
|
hDC = BeginPaint(m_hCtrl, &ps);
|
|
|
|
CHECK_NULL_REPORT(hDC, m_hDlg, return FALSE);
|
|
|
|
if (!DrawIcon(hDC, 0, 0, m_hIcon))
|
|
{
|
|
REPORT_ERROR(GetLastError(), m_hDlg);
|
|
return FALSE;
|
|
}
|
|
|
|
EndPaint(m_hCtrl, &ps);
|
|
|
|
return TRUE;
|
|
}
|