//+---------------------------------------------------------------------------- // // 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 #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, CDSBasePathsInfo* pBasePathsInfo, HPROPSHEETPAGE * phPage) { TRACE_FUNCTION(CreateTableDrivenPage); CDsTableDrivenPage * pPageObj = new CDsTableDrivenPage(pDsPage, pDataObj, hNotifyWnd, dwFlags); CHECK_NULL(pPageObj, return E_OUTOFMEMORY); pPageObj->Init(pwzADsPath, pwzClass, pBasePathsInfo); return pPageObj->CreatePage(phPage); } //+---------------------------------------------------------------------------- // // Method: CDsTableDrivenPage::DlgProc // // Synopsis: per-instance dialog proc // //----------------------------------------------------------------------------- LRESULT 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((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((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 && 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(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; }