//+---------------------------------------------------------------------------- // // DS Administration MMC snapin. // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: queryui.cpp // //-------------------------------------------------------------------------- #include "stdafx.h" #include "resource.h" #include "queryui.h" #include "dssnap.h" #include "uiutil.h" #include // DSFind #include // DSFind #include // BrowseForContainer #include // COLUMNINFO and QueryParamsAddQueryString, QueryParamsAlloc helpers #include // CQFF_ISNEVERLISTED #include // UF_ACCOUNTDISABLE and UF_DONT_EXPIRE_PASSWD #include // LDAP_MATCHING_RULE_BIT_AND_W #include "ldaputil.h" // LdapEscape(). #define DSQF_LAST_LOGON_QUERY 0x00000001 #define DSQF_NON_EXPIRING_PWD_QUERY 0x00000004 // // Used to set the maximum text length on fields in the new query dialog // #define MAX_QUERY_NAME_LENGTH 259 #define MAX_QUERY_DESC_LENGTH 1024 typedef struct { UINT nDisplayStringID; PWSTR pszFormatString; } QUERYSTRINGS, * PQUERYSTRINGS; QUERYSTRINGS g_pQueryStrings[] = { { IDS_STARTSWITH, L"(%s=%s*)" }, { IDS_ENDSWITH, L"(%s=*%s)" }, { IDS_ISEXACTLY, L"(%s=%s)" }, { IDS_ISNOT, L"(!%s=%s)" }, { IDS_PRESENT, L"(%s=%s*)" }, // NOTE: the second string needs to be NULL here { IDS_NOTPRESENT, L"(!%s=%s*)" }, // NOTE: the second string needs to be NULL here { 0, NULL } }; static const CString g_szUserAccountCtrlQuery = L"(userAccountControl:" + CString(LDAP_MATCHING_RULE_BIT_AND_W) + L":=%u)"; /*----------------------------------------------------------------------------- / QueryParamsAlloc / ---------------- / Construct a block we can pass to the DS query handler which contains / all the parameters for the query. / / In: / ppDsQueryParams -> receives the parameter block / pQuery -> LDAP query string to be used / iColumns = number of columns / pColumnInfo -> column info structure to use / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT QueryParamsAlloc(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery, LONG iColumns, LPCOLUMNINFO aColumnInfo) { HRESULT hr = S_OK; LPDSQUERYPARAMS pDsQueryParams = NULL; size_t cbStruct; LONG i; ASSERT(!*ppDsQueryParams); TRACE(L"QueryParamsAlloc"); AFX_MANAGE_STATE(AfxGetStaticModuleState()); if ( !pQuery || !iColumns || !ppDsQueryParams ) { return E_INVALIDARG; } // // Compute the size of the structure we need to be using // cbStruct = sizeof(DSQUERYPARAMS) + (sizeof(DSCOLUMN)*iColumns); cbStruct += (wcslen(pQuery) + 1) * sizeof(WCHAR); for (i = 0; i < iColumns; i++) { if (aColumnInfo[i].pPropertyName) { cbStruct += (wcslen(aColumnInfo[i].pPropertyName) + 1) * sizeof(WCHAR); } } pDsQueryParams = (LPDSQUERYPARAMS)CoTaskMemAlloc(cbStruct); if (!pDsQueryParams) { return E_OUTOFMEMORY; } // // Structure allocated so lets fill it with data // pDsQueryParams->cbStruct = static_cast(cbStruct); pDsQueryParams->dwFlags = 0; pDsQueryParams->hInstance = _Module.m_hInst; pDsQueryParams->iColumns = iColumns; pDsQueryParams->dwReserved = 0; cbStruct = sizeof(DSQUERYPARAMS) + (sizeof(DSCOLUMN)*iColumns); pDsQueryParams->offsetQuery = static_cast(cbStruct); CopyMemory(&(((LPBYTE)pDsQueryParams)[cbStruct]), pQuery, (wcslen(pQuery) + 1) * sizeof(WCHAR)); cbStruct += (wcslen(pQuery) + 1) * sizeof(WCHAR); for ( i = 0 ; i < iColumns ; i++ ) { pDsQueryParams->aColumns[i].dwFlags = 0; pDsQueryParams->aColumns[i].fmt = aColumnInfo[i].fmt; pDsQueryParams->aColumns[i].cx = aColumnInfo[i].cx; pDsQueryParams->aColumns[i].idsName = aColumnInfo[i].idsName; pDsQueryParams->aColumns[i].dwReserved = 0; if ( aColumnInfo[i].pPropertyName ) { pDsQueryParams->aColumns[i].offsetProperty = static_cast(cbStruct); CopyMemory(&(((LPBYTE)pDsQueryParams)[cbStruct]), aColumnInfo[i].pPropertyName, (wcslen(aColumnInfo[i].pPropertyName) + 1) * sizeof(WCHAR)); cbStruct += (wcslen(aColumnInfo[i].pPropertyName) + 1) * sizeof(WCHAR); } else { pDsQueryParams->aColumns[i].offsetProperty = aColumnInfo[i].iPropertyIndex; } } *ppDsQueryParams = pDsQueryParams; return hr; } /*----------------------------------------------------------------------------- / QueryParamsAddQueryString / ------------------------- / Given an existing DS query block appened the given LDAP query string into / it. We assume that the query block has been allocated by IMalloc (or CoTaskMemAlloc). / / In: / ppDsQueryParams -> receives the parameter block / pQuery -> LDAP query string to be appended / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT QueryParamsAddQueryString(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery) { HRESULT hr = S_OK; LPWSTR pOriginalQuery = NULL; LPDSQUERYPARAMS pDsQuery = *ppDsQueryParams; size_t cbQuery; LONG i; LPVOID pv; //NTRAID#NTBUG9-567482-2002/03/10-jmessec Assertion not backed up by code (well, sorta is below in checking pDsQuery, but not obvious) ASSERT(*ppDsQueryParams); TRACE(_T("QueryParamsAddQueryString")); if ( pQuery ) { if (!pDsQuery) { return E_INVALIDARG; } // Work out the size of the bits we are adding, take a copy of the // query string and finally re-alloc the query block (which may cause it // to move). cbQuery = ((wcslen(pQuery) + 1) * sizeof(WCHAR)); TRACE(_T("DSQUERYPARAMS being resized by %d bytes")); i = static_cast((wcslen((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery)) + 1) * sizeof(WCHAR)); pOriginalQuery = (WCHAR*) new BYTE[i]; if (!pOriginalQuery) { return E_OUTOFMEMORY; } lstrcpyW(pOriginalQuery, (LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery)); pv = CoTaskMemRealloc(*ppDsQueryParams, pDsQuery->cbStruct+cbQuery); if ( pv == NULL ) { delete[] pOriginalQuery; pOriginalQuery = 0; return E_OUTOFMEMORY; } *ppDsQueryParams = (LPDSQUERYPARAMS) pv; pDsQuery = *ppDsQueryParams; // if may have moved // Now move everything above the query string up, and fix all the // offsets that reference those items (probably the property table), // finally adjust the size to reflect the change MoveMemory(ByteOffset(pDsQuery, pDsQuery->offsetQuery+cbQuery), ByteOffset(pDsQuery, pDsQuery->offsetQuery), (pDsQuery->cbStruct - pDsQuery->offsetQuery)); for ( i = 0 ; i < pDsQuery->iColumns ; i++ ) { if ( pDsQuery->aColumns[i].offsetProperty > pDsQuery->offsetQuery ) { pDsQuery->aColumns[i].offsetProperty += static_cast(cbQuery); } } //NTRAID#NTBUG9-572009-2002/03/10-jmessec It appears that your struct is one sizeof(WCHAR) too large now, since //you allocated enough extra for a whole other string, including terminating NULL, //but you are appending the strings, thus eating a NULL; could this fowl up later //struct size calculations and offsets? wcscpy((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), pOriginalQuery); wcscat((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), pQuery); pDsQuery->cbStruct += static_cast(cbQuery); delete[] pOriginalQuery; pOriginalQuery = 0; } return hr; } /////////////////////////////////////////////////////////////////////////////// // AddQueryUnitWithModifier HRESULT AddQueryUnitWithModifier(UINT nModifierStringID, PCWSTR pszAttrName, PCWSTR pszValue, CString& szFilter) { HRESULT hr = S_OK; ASSERT(pszAttrName != NULL); if (pszAttrName == NULL) { return E_INVALIDARG; } // Escape special characters used in LDAP from the value the // user entered. wstring escapedValue; LdapEscape( pszValue != NULL ? pszValue : L"", escapedValue); CString szNewFilter; PQUERYSTRINGS pQueryStrings = g_pQueryStrings; PWSTR pszFormatString = NULL; while (pQueryStrings->nDisplayStringID != 0) { if (nModifierStringID == pQueryStrings->nDisplayStringID) { pszFormatString = pQueryStrings->pszFormatString; break; } pQueryStrings++; } if (pszFormatString != NULL) { szNewFilter.Format(pszFormatString, pszAttrName, escapedValue.c_str()); szFilter += szNewFilter; } else { hr = E_INVALIDARG; } return hr; } /////////////////////////////////////////////////////////////////////////////// // CQueryPageBase BEGIN_MESSAGE_MAP(CQueryPageBase, CHelpDialog) END_MESSAGE_MAP() /////////////////////////////////////////////////////////////////////////////// // CStdQueryPage #define FILTER_PREFIX_USER L"(objectCategory=person)(objectClass=user)" #define FILTER_PREFIX_COMPUTER L"(objectCategory=computer)" #define FILTER_PREFIX_GROUP L"(objectCategory=group)" #define ATTR_COL_NAME L"name" #define ATTR_COL_DESC L"description" COLUMNINFO UserColumn[] = { { 0, 40, IDS_QUERY_COL_NAME, 0, ATTR_COL_NAME }, { 0, 40, IDS_QUERY_COL_DESC, 0, ATTR_COL_DESC } }; int cUserColumns = 2; BEGIN_MESSAGE_MAP(CStdQueryPage, CQueryPageBase) ON_CBN_SELCHANGE(IDC_NAME_COMBO, OnNameComboChange) ON_CBN_SELCHANGE(IDC_DESCRIPTION_COMBO, OnDescriptionComboChange) END_MESSAGE_MAP() void CStdQueryPage::DoContextHelp(HWND hWndControl) { if (hWndControl) { ::WinHelp(hWndControl, DSADMIN_CONTEXT_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_QUERY_STD_PAGE); } } BOOL CStdQueryPage::OnInitDialog() { CHelpDialog::OnInitDialog(); PQUERYSTRINGS pQueryStrings = g_pQueryStrings; ASSERT(pQueryStrings != NULL); // // Fill in the combo boxes // while (pQueryStrings->nDisplayStringID != 0) { CString szComboString; VERIFY(szComboString.LoadString(pQueryStrings->nDisplayStringID)); // // Fill in the Name combo // LRESULT lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_ADDSTRING, 0, (LPARAM)(PCWSTR)szComboString); if (lRes != CB_ERR) { lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_SETITEMDATA, (WPARAM)lRes, (LPARAM)pQueryStrings->nDisplayStringID); ASSERT(lRes != CB_ERR); } // // Fill in the Description combo // lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_ADDSTRING, 0, (LPARAM)(PCWSTR)szComboString); if (lRes != CB_ERR) { lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_SETITEMDATA, (WPARAM)lRes, (LPARAM)pQueryStrings->nDisplayStringID); ASSERT(lRes != CB_ERR); } pQueryStrings++; } // // Insert an empty so that there is a way to undo changes // LRESULT lBlankName = SendDlgItemMessage(IDC_NAME_COMBO, CB_ADDSTRING, 0, (LPARAM)L""); if (lBlankName != CB_ERR) { SendDlgItemMessage(IDC_NAME_COMBO, CB_SETITEMDATA, (WPARAM)lBlankName, (LPARAM)0); } // // Insert an empty so that there is a way to undo changes // LRESULT lBlankDesc = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_ADDSTRING, 0, (LPARAM)L""); if (lBlankDesc != CB_ERR) { SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_SETITEMDATA, (WPARAM)lBlankDesc, (LPARAM)0); } // // Force the UI to enable and disable controls related to the combo boxes // OnNameComboChange(); OnDescriptionComboChange(); return FALSE; } void CStdQueryPage::OnNameComboChange() { LRESULT lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETCURSEL, 0, 0); if (lRes != CB_ERR) { LRESULT lData = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETITEMDATA, lRes, 0); if (lData != CB_ERR) { if (lData == IDS_PRESENT || lData == IDS_NOTPRESENT || lData == 0) { GetDlgItem(IDC_NAME_EDIT)->EnableWindow(FALSE); SetDlgItemText(IDC_NAME_EDIT, L""); } else { GetDlgItem(IDC_NAME_EDIT)->EnableWindow(TRUE); } } } else { GetDlgItem(IDC_NAME_EDIT)->EnableWindow(FALSE); } } void CStdQueryPage::OnDescriptionComboChange() { LRESULT lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETCURSEL, 0, 0); if (lRes != CB_ERR) { LRESULT lData = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETITEMDATA, lRes, 0); if (lData != CB_ERR) { if (lData == IDS_PRESENT || lData == IDS_NOTPRESENT || lData == 0) { GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(FALSE); SetDlgItemText(IDC_DESCRIPTION_EDIT, L""); } else { GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(TRUE); } } } else { GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(FALSE); } } void CStdQueryPage::Init() { // // Clear all controls // SetDlgItemText(IDC_NAME_EDIT, L""); SetDlgItemText(IDC_DESCRIPTION_EDIT, L""); // // Reselect the blank string in the combo boxes // LRESULT lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)L""); if (lRes != CB_ERR) { SendDlgItemMessage(IDC_NAME_COMBO, CB_SETCURSEL, lRes, 0); } lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)L""); if (lRes != CB_ERR) { SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_SETCURSEL, lRes, 0); } } HRESULT CStdQueryPage::GetQueryParams(LPDSQUERYPARAMS* ppDsQueryParams) { HRESULT hr = S_OK; // // Build the filter string here // CString szFilter; CString szName; CString szDescription; GetDlgItemText(IDC_NAME_EDIT, szName); GetDlgItemText(IDC_DESCRIPTION_EDIT, szDescription); // // Get the selection of the modifier combo // LRESULT lSel = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETCURSEL, 0, 0); if (lSel != CB_ERR) { // // Retrieve the associated string ID // LRESULT lData = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETITEMDATA, lSel, 0); if (lData != CB_ERR) { if (!szName.IsEmpty() || lData == IDS_PRESENT || lData == IDS_NOTPRESENT) { AddQueryUnitWithModifier(static_cast(lData), ATTR_COL_NAME, szName, szFilter); } } } // // Get the selection of the modifier combo // lSel = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETCURSEL, 0, 0); if (lSel != CB_ERR) { // // Retrieve the associated string ID // LRESULT lData = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETITEMDATA, lSel, 0); if (lData != CB_ERR) { if (!szDescription.IsEmpty() || lData == IDS_PRESENT || lData == IDS_NOTPRESENT) { AddQueryUnitWithModifier(static_cast(lData), ATTR_COL_DESC, szDescription, szFilter); } } } if (!szFilter.IsEmpty()) { szFilter = m_szFilterPrefix + szFilter; hr = BuildQueryParams(ppDsQueryParams, (LPWSTR)(LPCWSTR)szFilter); } return hr; } HRESULT CStdQueryPage::BuildQueryParams(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery) { ASSERT(pQuery); if(*ppDsQueryParams) { return QueryParamsAddQueryString(ppDsQueryParams, pQuery); } return QueryParamsAlloc(ppDsQueryParams, pQuery, cUserColumns, UserColumn); } HRESULT CStdQueryPage::Persist(IPersistQuery* pPersistQuery, BOOL fRead) { HRESULT hr = S_OK; if (pPersistQuery == NULL) { ASSERT(FALSE); return E_INVALIDARG; } if (fRead) { // // Read the Name combo value // int iData = 0; hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"NameCombo", &iData); if (FAILED(hr)) { TRACE(_T("Failed to read int \"NameCombo\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } // // Select the appropriate list box item // SelectComboAssociatedWithData(IDC_NAME_COMBO, iData); if (iData != 0 && iData != IDS_PRESENT && iData != IDS_NOTPRESENT) { // // Read the name edit value // WCHAR szBuf[MAX_PATH] = {0}; hr = pPersistQuery->ReadString(m_szFilterPrefix, L"NameEdit", szBuf, MAX_PATH); if (FAILED(hr)) { TRACE(_T("Failed to read string \"NameEdit\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } if (szBuf != NULL) { SetDlgItemText(IDC_NAME_EDIT, szBuf); } } else { GetDlgItem(IDC_NAME_EDIT)->EnableWindow(FALSE); } // // Read the Description combo value // iData = 0; hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"DescCombo", &iData); if (FAILED(hr)) { TRACE(_T("Failed to read int \"DescCombo\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } // // Select the appropriate list box item // SelectComboAssociatedWithData(IDC_DESCRIPTION_COMBO, iData); if (iData != 0 && iData != IDS_PRESENT && iData != IDS_NOTPRESENT) { // // Read the name edit value // WCHAR szBuf[MAX_PATH] = {0}; hr = pPersistQuery->ReadString(m_szFilterPrefix, L"DescEdit", szBuf, MAX_PATH); if (FAILED(hr)) { TRACE(_T("Failed to read string \"DescEdit\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } if (szBuf != NULL) { SetDlgItemText(IDC_DESCRIPTION_EDIT, szBuf); } } else { GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(FALSE); } OnNameComboChange(); OnDescriptionComboChange(); } else // write { // // Write out the name info // LRESULT lSel = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETCURSEL, 0, 0); if (lSel != CB_ERR) { // // Retrieve the associated string ID // LRESULT lData = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETITEMDATA, lSel, 0); if (lData != CB_ERR) { hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"NameCombo", static_cast(lData)); if (FAILED(hr)) { ASSERT(FALSE); return hr; } if (lData != 0 && lData != IDS_PRESENT && lData != IDS_NOTPRESENT) { CString szName; GetDlgItemText(IDC_NAME_EDIT, szName); hr = pPersistQuery->WriteString(m_szFilterPrefix, L"NameEdit", szName); if (FAILED(hr)) { ASSERT(FALSE); return hr; } } } } else { // // If there hasn't been a selection, write in the empty string value // hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"NameCombo", 0); } // // Write out the description info // lSel = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETCURSEL, 0, 0); if (lSel != CB_ERR) { // // Retrieve the associated string ID // LRESULT lData = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETITEMDATA, lSel, 0); if (lData != CB_ERR) { hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"DescCombo", static_cast(lData)); if (FAILED(hr)) { ASSERT(FALSE); return hr; } if (lData != 0 && lData != IDS_PRESENT && lData != IDS_NOTPRESENT) { CString szDescription; GetDlgItemText(IDC_DESCRIPTION_EDIT, szDescription); hr = pPersistQuery->WriteString(m_szFilterPrefix, L"DescEdit", szDescription); if (FAILED(hr)) { ASSERT(FALSE); return hr; } } } } else { // // If there hasn't been a selection, write in the empty string value // hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"DescCombo", 0); } } return hr; } void CStdQueryPage::SelectComboAssociatedWithData(UINT nCtrlID, LRESULT lData) { // // Selects the item with the associated data in a combo box // LRESULT lRes = SendDlgItemMessage(nCtrlID, CB_GETCOUNT, 0, 0); if (lRes != CB_ERR) { for (int idx = 0; idx < static_cast(lRes); idx++) { LRESULT lRetData = SendDlgItemMessage(nCtrlID, CB_GETITEMDATA, (WPARAM)idx, 0); if (lRetData != CB_ERR) { if (lRetData == lData) { SendDlgItemMessage(nCtrlID, CB_SETCURSEL, (WPARAM)idx, 0); break; } } } } } /////////////////////////////////////////////////////////////////////////////// // CUserComputerQueryPage BEGIN_MESSAGE_MAP(CUserComputerQueryPage, CStdQueryPage) END_MESSAGE_MAP() BOOL CUserComputerQueryPage::OnInitDialog() { return CStdQueryPage::OnInitDialog(); } void CUserComputerQueryPage::DoContextHelp(HWND hWndControl) { if (hWndControl) { ::WinHelp(hWndControl, DSADMIN_CONTEXT_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_QUERY_USER_PAGE); } } void CUserComputerQueryPage::Init() { // // Clear all controls // CStdQueryPage::Init(); } HRESULT CUserComputerQueryPage::GetQueryParams(LPDSQUERYPARAMS* ppDsQueryParams) { HRESULT hr = S_OK; // // Build the filter string here // hr = CStdQueryPage::GetQueryParams(ppDsQueryParams); CString szFilter; BOOL bDisabledAccounts = FALSE; // // Get disabled accounts check // LRESULT lRes = SendDlgItemMessage(IDC_DISABLED_ACCOUNTS_CHECK, BM_GETCHECK, 0, 0); if (lRes == BST_CHECKED) { bDisabledAccounts = TRUE; } if (bDisabledAccounts) { szFilter.Format(g_szUserAccountCtrlQuery, UF_ACCOUNTDISABLE); szFilter = m_szFilterPrefix + szFilter; hr = BuildQueryParams(ppDsQueryParams, (LPWSTR)(LPCWSTR)szFilter); } return hr; } HRESULT CUserComputerQueryPage::Persist(IPersistQuery* pPersistQuery, BOOL fRead) { HRESULT hr = CStdQueryPage::Persist(pPersistQuery, fRead); if (FAILED(hr)) { return hr; } if (pPersistQuery == NULL) { ASSERT(FALSE); return E_INVALIDARG; } if (fRead) { // // Read disabled accounts flag // int iData = 0; hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"DisableCheck", &iData); if (FAILED(hr)) { TRACE(_T("Failed to read int \"DisableCheck\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } SendDlgItemMessage(IDC_DISABLED_ACCOUNTS_CHECK, BM_SETCHECK, (iData > 0) ? BST_CHECKED : BST_UNCHECKED, 0); } else { // // Write disabled accounts flag // LRESULT lRes = SendDlgItemMessage(IDC_DISABLED_ACCOUNTS_CHECK, BM_GETCHECK, 0, 0); if (lRes != -1) { int iRes = (lRes == BST_CHECKED) ? 1 : 0; hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"DisableCheck", iRes); if (FAILED(hr)) { ASSERT(FALSE); return hr; } } } return hr; } /////////////////////////////////////////////////////////////////////////////// // CUserQueryPage BEGIN_MESSAGE_MAP(CUserQueryPage, CStdQueryPage) END_MESSAGE_MAP() BOOL CUserQueryPage::OnInitDialog() { return CUserComputerQueryPage::OnInitDialog(); } void CUserQueryPage::DoContextHelp(HWND hWndControl) { if (hWndControl) { ::WinHelp(hWndControl, DSADMIN_CONTEXT_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_QUERY_USER_PAGE); } } void CUserQueryPage::Init() { // // Clear all controls // CUserComputerQueryPage::Init(); } HRESULT CUserQueryPage::GetQueryParams(LPDSQUERYPARAMS* ppDsQueryParams) { HRESULT hr = S_OK; // // Build the filter string here // hr = CUserComputerQueryPage::GetQueryParams(ppDsQueryParams); CString szFilter; BOOL bNonExpPwds = FALSE; BOOL bLastLogon = FALSE; DWORD dwLastLogonData = 0; // // Get non expiring password check // LRESULT lRes = SendDlgItemMessage(IDC_NON_EXPIRING_PWD_CHECK, BM_GETCHECK, 0, 0); if (lRes == BST_CHECKED) { bNonExpPwds = TRUE; } // // Get stale acccounts check // lRes = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETCURSEL, 0, 0); if (lRes == CB_ERR) { lRes = m_lLogonSelection; } if (lRes != CB_ERR) { LRESULT lTextLen = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETLBTEXTLEN, (WPARAM)lRes, 0); if (lTextLen != CB_ERR) { if (lTextLen > 0) { bLastLogon = TRUE; WCHAR* pszData = new WCHAR[lTextLen + 1]; if (pszData != NULL) { LRESULT lData = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETLBTEXT, (WPARAM)lRes, (LPARAM)pszData); if (lData != CB_ERR) { dwLastLogonData = static_cast(_wtol(pszData)); // NTRAID#NTBUG9-449871-2001/09/20-lucios // Adding the appropriate filter. LARGE_INTEGER li; GetCurrentTimeStampMinusInterval(dwLastLogonData, &li); CString szTimeStamp; litow(li, szTimeStamp); CString szTempFilter; szTempFilter.Format ( L"%s(lastLogonTimestamp<=%s)", szTempFilter, szTimeStamp ); szFilter = szTempFilter + szFilter; } delete[] pszData; pszData = NULL; } } } } if (bNonExpPwds || bLastLogon) { if (bNonExpPwds) { szFilter.Format(g_szUserAccountCtrlQuery, UF_DONT_EXPIRE_PASSWD); } szFilter = m_szFilterPrefix + szFilter; hr = BuildQueryParams(ppDsQueryParams, (LPWSTR)(LPCWSTR)szFilter); if (SUCCEEDED(hr)) { if (bLastLogon) { (*ppDsQueryParams)->dwFlags |= DSQF_LAST_LOGON_QUERY; (*ppDsQueryParams)->dwReserved = dwLastLogonData; } } } return hr; } HRESULT CUserQueryPage::Persist(IPersistQuery* pPersistQuery, BOOL fRead) { HRESULT hr = CUserComputerQueryPage::Persist(pPersistQuery, fRead); if (FAILED(hr)) { return hr; } if (pPersistQuery == NULL) { ASSERT(FALSE); return E_INVALIDARG; } if (fRead) { // // Read non expiring pwds flag // int iData = 0; hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"NonExpPwdCheck", &iData); if (FAILED(hr)) { TRACE(_T("Failed to read int \"NonExpPwdCheck\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } SendDlgItemMessage(IDC_NON_EXPIRING_PWD_CHECK, BM_SETCHECK, (iData > 0) ? BST_CHECKED : BST_UNCHECKED, 0); iData = 0; hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"LastLogonCombo", &iData); if (FAILED(hr)) { TRACE(_T("Failed to read int \"LastLogonCombo\" from stream: 0x%x\n"), hr); ASSERT(FALSE); return hr; } SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_SETCURSEL, (WPARAM)iData, 0); m_lLogonSelection = iData; } else { // // Write non expiring pwd flag // LRESULT lRes = SendDlgItemMessage(IDC_NON_EXPIRING_PWD_CHECK, BM_GETCHECK, 0, 0); if (lRes != -1) { int iRes = (lRes == BST_CHECKED) ? 1 : 0; hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"NonExpPwdCheck", iRes); if (FAILED(hr)) { ASSERT(FALSE); return hr; } } // // Write last logon combo index // lRes = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETCURSEL, 0, 0); if (lRes == CB_ERR) { if (m_lLogonSelection != -1) { lRes = m_lLogonSelection; } else { lRes = 0; } } hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"LastLogonCombo", static_cast(lRes)); if (FAILED(hr)) { ASSERT(FALSE); return hr; } } return hr; } /////////////////////////////////////////////////////////////////////////////// // CQueryFormBase HRESULT PageProc(LPCQPAGE pPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); HRESULT GetQueryParams(HWND hWnd, LPDSQUERYPARAMS* ppDsQueryParams); STDMETHODIMP CQueryFormBase::Initialize(HKEY) { // This method is called to initialize the query form object, it is called before // any pages are added. hkForm should be ignored, in the future however it // will be a way to persist form state. HRESULT hr = S_OK; return hr; } STDMETHODIMP CQueryFormBase::AddForms(LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam) { CQFORM cqf; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // This method is called to allow the form handler to register its query form(s), // each form is identifiered by a CLSID and registered via the pAddFormProc. Here // we are going to register a test form. // When registering a form which is only applicable to a specific task, eg. Find a Domain // object, it is advised that the form be marked as hidden (CQFF_ISNEVERLISTED) which // will cause it not to appear in the form picker control. Then when the // client wants to use this form, they specify the form identifier and ask for the // picker control to be hidden. if ( !pAddFormsProc ) { return E_INVALIDARG; } cqf.cbStruct = sizeof(cqf); cqf.dwFlags = CQFF_NOGLOBALPAGES; cqf.clsid = CLSID_DSAdminQueryUIForm; cqf.hIcon = NULL; CString title; title.LoadString(IDS_QUERY_TITLE_SAVEDQUERYFORM); cqf.pszTitle = (LPCTSTR)title; return pAddFormsProc(lParam, &cqf); } STDMETHODIMP CQueryFormBase::AddPages(LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam) { HRESULT hr = S_OK; CQPAGE cqp; AFX_MANAGE_STATE(AfxGetStaticModuleState()); CThemeContextActivator activator; // AddPages is called after AddForms, it allows us to add the pages for the // forms we have registered. Each page is presented on a seperate tab within // the dialog. A form is a dialog with a DlgProc and a PageProc. // // When registering a page the entire structure passed to the callback is copied, // the amount of data to be copied is defined by the cbStruct field, therefore // a page implementation can grow this structure to store extra information. When // the page dialog is constructed via CreateDialog the CQPAGE strucuture is passed // as the create param. if ( !pAddPagesProc ) return E_INVALIDARG; cqp.cbStruct = sizeof(cqp); cqp.dwFlags = 0x0; cqp.pPageProc = PageProc; cqp.hInstance = _Module.GetModuleInstance(); cqp.pDlgProc = DlgProc; // // Add the user page // cqp.idPageName = IDS_QUERY_TITLE_USERPAGE; cqp.idPageTemplate = IDD_QUERY_USER_PAGE; cqp.lParam = (LPARAM)new CUserQueryPage(FILTER_PREFIX_USER); hr = pAddPagesProc(lParam, CLSID_DSAdminQueryUIForm, &cqp); // // Add the computer page (this is just a std page) // cqp.idPageName = IDS_QUERY_TITLE_COMPUTER_PAGE; cqp.idPageTemplate = IDD_QUERY_COMPUTER_PAGE; cqp.lParam = (LPARAM)new CUserComputerQueryPage(IDD_QUERY_COMPUTER_PAGE, FILTER_PREFIX_COMPUTER); hr = pAddPagesProc(lParam, CLSID_DSAdminQueryUIForm, &cqp); // // Add the group page (this is just a std page) // cqp.idPageName = IDS_QUERY_TITLE_GROUP_PAGE; cqp.idPageTemplate = IDD_QUERY_STD_PAGE; cqp.lParam = (LPARAM)new CStdQueryPage(IDD_QUERY_STD_PAGE, FILTER_PREFIX_GROUP); hr = pAddPagesProc(lParam, CLSID_DSAdminQueryUIForm, &cqp); // // Add more pages here if needed // return hr; } #define ExitGracefully(hr, result, text) \ { hr = result; goto exit_gracefully; } #define StringByteSizeW(sz) ((sz) ? ((lstrlenW(sz)+1)*sizeof(WCHAR)):0) //NTRAID#NTBUG9-572010-2002/03/10-jmessec Unsafe wrapper for CopyMemory; what if string is longer than destination buffer? #define StringByteCopyW(pDest, iOffset, sz) \ { CopyMemory(&(((LPBYTE)pDest)[iOffset]), sz, StringByteSizeW(sz)); } STDAPI ClassListAlloc(LPDSQUERYCLASSLIST* ppDsQueryClassList, LPWSTR* aClassNames, INT cClassNames) { HRESULT hres; DWORD cbStruct, offset; LPDSQUERYCLASSLIST pDsQueryClassList = NULL; INT i; USES_CONVERSION; if ( !ppDsQueryClassList || !aClassNames || !cClassNames ) ExitGracefully(hres, E_FAIL, "Bad parameters (no class list etc)"); // Walk the list of classes working out the size of the structure // we are going to generate, this consists of the array of // classes. cbStruct = sizeof(DSQUERYCLASSLIST)+(cClassNames*sizeof(DWORD)); offset = cbStruct; for ( i = 0 ; i < cClassNames ; i++ ) { ASSERT(aClassNames[i]); cbStruct += StringByteSizeW(aClassNames[i]); } // Allocate the structure using the task allocator, then fill // it in copying all the strings into the data blob. pDsQueryClassList = (LPDSQUERYCLASSLIST)CoTaskMemAlloc(cbStruct); ASSERT(pDsQueryClassList); if ( !pDsQueryClassList ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate class list structure"); pDsQueryClassList->cbStruct = cbStruct; pDsQueryClassList->cClasses = cClassNames; for ( i = 0 ; i < cClassNames ; i++ ) { pDsQueryClassList->offsetClass[i] = offset; StringByteCopyW(pDsQueryClassList, offset, aClassNames[i]); offset += StringByteSizeW(aClassNames[i]); } hres = S_OK; exit_gracefully: ASSERT(pDsQueryClassList); if (ppDsQueryClassList) *ppDsQueryClassList = pDsQueryClassList; return hres; } /*---------------------------------------------------------------------------*/ // The PageProc is used to perform general house keeping and communicate between // the frame and the page. // // All un-handled, or unknown reasons should result in an E_NOIMPL response // from the proc. // // In: // pPage -> CQPAGE structure (copied from the original passed to pAddPagesProc) // hwnd = handle of the dialog for the page // uMsg, wParam, lParam = message parameters for this event // // Out: // HRESULT // // uMsg reasons: // ------------ // CQPM_INIIIALIZE // CQPM_RELEASE // These are issued as a result of the page being declared or freed, they // allow the caller to AddRef, Release or perform basic initialization // of the form object. // // CQPM_ENABLE // Enable is when the query form needs to enable or disable the controls // on its page. wParam contains TRUE/FALSE indicating the state that // is required. // // CQPM_GETPARAMETERS // To collect the parameters for the query each page on the active form // receives this event. lParam is an LPVOID* which is set to point to the // parameter block to pass to the handler, if the pointer is non-NULL // on entry the form needs to appened its query information to it. The // parameter block is handler specific. // // Returning S_FALSE from this event causes the query to be canceled. // // CQPM_CLEARFORM // When the page window is created for the first time, or the user clicks // the clear search the page receives a CQPM_CLEARFORM notification, at // which point it needs to clear out the edit controls it has and // return to a default state. // // CQPM_PERSIST: // When loading of saving a query, each page is called with an IPersistQuery // interface which allows them to read or write the configuration information // to save or restore their state. lParam is a pointer to the IPersistQuery object, // and wParam is TRUE/FALSE indicating read or write accordingly. HRESULT PageProc(LPCQPAGE pQueryPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; AFX_MANAGE_STATE(AfxGetStaticModuleState()); CQueryPageBase* pDialog = (CQueryPageBase*)pQueryPage->lParam; ASSERT(pDialog); switch ( uMsg ) { // Initialize so AddRef the object we are associated with so that // we don't get unloaded. case CQPM_INITIALIZE: break; case DSQPM_GETCLASSLIST: { LPWSTR classes[]={L"user",L"computer",L"group"}; hr = ClassListAlloc((LPDSQUERYCLASSLIST*)lParam, classes, sizeof(classes)/sizeof(*classes)); break; } case DSQPM_HELPTOPICS: { HWND hwndFrame = (HWND)lParam; HtmlHelp(hwndFrame, TEXT("omc.chm"), HH_HELP_FINDER, 0); break; } // Changed from qform sample to detach the hwnd, and delete the CDialog // ensure correct destruction etc. case CQPM_RELEASE: pDialog->Detach(); SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)0); delete pDialog; break; // Enable so fix the state of our two controls within the window. case CQPM_ENABLE: SetFocus(GetDlgItem(hwnd, IDC_NAME_COMBO)); break; // Fill out the parameter structure to return to the caller, this is // handler specific. In our case we constructure a query of the CN // and objectClass properties, and we show a columns displaying both // of these. For further information about the DSQUERYPARAMs structure // see dsquery.h case CQPM_GETPARAMETERS: hr = pDialog->GetQueryParams((LPDSQUERYPARAMS*)lParam); break; // Clear form, therefore set the window text for these two controls // to zero. case CQPM_CLEARFORM: hr = pDialog->ClearForm(); break; // persistance is not currently supported by this form. case CQPM_PERSIST: { BOOL fRead = (BOOL)wParam; IPersistQuery* pPersistQuery = (IPersistQuery*)lParam; if ( !pPersistQuery ) { return E_INVALIDARG; } hr = pDialog->Persist(pPersistQuery, fRead); break; } default: hr = E_NOTIMPL; break; } return hr; } /*---------------------------------------------------------------------------*/ // The DlgProc is a standard Win32 dialog proc associated with the form // window. INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPCQPAGE pQueryPage; CQueryPageBase* pDialog; AFX_MANAGE_STATE(AfxGetStaticModuleState()); if ( uMsg == WM_INITDIALOG ) { // changed from qForm sample to save CDialog pointer // in the DWL_USER field of the dialog box instance. pQueryPage = (LPCQPAGE)lParam; pDialog = (CQueryPageBase*)pQueryPage->lParam; pDialog->Attach(hwnd); SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)pDialog); return pDialog->OnInitDialog(); } else { // CDialog pointer is stored in DWL_USER // dialog structure, note however that in some cases this will // be NULL as it is set on WM_INITDIALOG. pDialog = (CQueryPageBase*)GetWindowLongPtr(hwnd, DWLP_USER); } if(!pDialog) { return FALSE; } else { return AfxCallWndProc(pDialog, hwnd, uMsg, wParam, lParam); } } /////////////////////////////////////////////////////////////////////// // CQueryDialog CQueryDialog::CQueryDialog(CSavedQueryNode* pQueryNode, CFavoritesNode* pFavNode, CDSComponentData* pComponentData, BOOL bNewQuery, BOOL bImportQuery) : CHelpDialog(IDD_CREATE_NEW_QUERY) { m_bInit = FALSE; m_bNewQuery = bNewQuery; m_bImportQuery = bImportQuery; m_pComponentData = pComponentData; m_pQueryNode = pQueryNode; m_pFavNode = pFavNode; m_szName = pQueryNode->GetName(); m_szOriginalName = pQueryNode->GetName(); m_szDescription = pQueryNode->GetDesc(); m_szQueryRoot = pQueryNode->GetRootPath(); m_szQueryFilter = pQueryNode->GetQueryString(); m_bMultiLevel = !pQueryNode->IsOneLevel(); m_bLastLogonFilter = pQueryNode->IsFilterLastLogon(); m_dwLastLogonData = pQueryNode->GetLastLogonDays(); m_pPersistQueryImpl = pQueryNode->GetQueryPersist(); if (m_pPersistQueryImpl != NULL) { m_pPersistQueryImpl->AddRef(); } else { // // Create the IPersistQuery object // CComObject::CreateInstance(&m_pPersistQueryImpl); ASSERT(m_pPersistQueryImpl != NULL); // // created with zero refcount,need to AddRef() to one // m_pPersistQueryImpl->AddRef(); } } CQueryDialog::~CQueryDialog() { if (m_pPersistQueryImpl != NULL) { // // go to refcount of zero, to destroy object // m_pPersistQueryImpl->Release(); } } BEGIN_MESSAGE_MAP(CQueryDialog, CHelpDialog) ON_BN_CLICKED(IDC_BROWSE_BUTTON, OnBrowse) ON_BN_CLICKED(IDC_EDIT_BUTTON, OnEditQuery) ON_BN_CLICKED(IDC_MULTI_LEVEL_CHECK, OnMultiLevelChange) ON_EN_CHANGE(IDC_NAME_EDIT, OnNameChange) ON_EN_CHANGE(IDC_DESCRIPTION_EDIT, OnDescriptionChange) ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnNeedToolTipText) END_MESSAGE_MAP() void CQueryDialog::DoContextHelp(HWND hWndControl) { if (hWndControl) { ::WinHelp(hWndControl, DSADMIN_CONTEXT_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_CREATE_NEW_QUERY); } } BOOL CQueryDialog::OnInitDialog() { CHelpDialog::OnInitDialog(); if (m_pQueryNode == NULL) { ASSERT(FALSE); EndDialog(IDCANCEL); } // // Change the title for editing queries // if (!m_bNewQuery) { CString szTitle; VERIFY(szTitle.LoadString(IDS_SAVED_QUERIES_EDIT_TITLE)); SetWindowText(szTitle); } // // Initialize the controls with data // SetDlgItemText(IDC_NAME_EDIT, m_szName); SendDlgItemMessage(IDC_NAME_EDIT, EM_SETLIMITTEXT, MAX_QUERY_NAME_LENGTH, 0); SetDlgItemText(IDC_DESCRIPTION_EDIT, m_szDescription); SendDlgItemMessage(IDC_DESCRIPTION_EDIT, EM_SETLIMITTEXT, MAX_QUERY_DESC_LENGTH, 0); SendDlgItemMessage(IDC_MULTI_LEVEL_CHECK, BM_SETCHECK, (m_bMultiLevel) ? BST_CHECKED : BST_UNCHECKED, 0); SetQueryFilterDisplay(); EnableToolTips(TRUE); SetQueryRoot(m_szQueryRoot); SetDirty(); m_bInit = TRUE; return TRUE; } void CQueryDialog::SetDirty(BOOL bDirty) { if (m_bInit || m_bImportQuery) { m_szName.TrimLeft(); m_szName.TrimRight(); if (m_szName.IsEmpty() || m_szQueryRoot.IsEmpty() || m_szQueryFilter.IsEmpty()) { m_bDirty = FALSE; } else { m_bDirty = bDirty; } GetDlgItem(IDOK)->EnableWindow(m_bDirty); } } void CQueryDialog::OnOK() { CThemeContextActivator activator; if (m_bDirty) { if (m_pQueryNode != NULL) { GetDlgItemText(IDC_NAME_EDIT, m_szName); GetDlgItemText(IDC_DESCRIPTION_EDIT, m_szDescription); LRESULT lRes = SendDlgItemMessage(IDC_MULTI_LEVEL_CHECK, BM_GETCHECK, 0, 0); if (lRes == BST_CHECKED) { m_bMultiLevel = TRUE; } else { m_bMultiLevel = FALSE; } // // Trim white space // m_szName.TrimLeft(); m_szName.TrimRight(); if (wcscmp(m_szOriginalName, m_szName) != 0 || m_bImportQuery) { CUINode* pDupNode = NULL; if (!m_pFavNode->IsUniqueName(m_szName, &pDupNode)) { CString szFormatMsg; VERIFY(szFormatMsg.LoadString(IDS_ERRMSG_NOT_UNIQUE_QUERY_NAME)); CString szErrMsg; szErrMsg.Format(szFormatMsg, m_szName); CString szTitle; VERIFY(szTitle.LoadString(IDS_DSSNAPINNAME)); MessageBox(szErrMsg, szTitle, MB_OK | MB_ICONSTOP); // // Set the focus to the name field and select all the text // GetDlgItem(IDC_NAME_EDIT)->SetFocus(); SendDlgItemMessage(IDC_NAME_EDIT, EM_SETSEL, 0, -1); return; } } if (m_bLastLogonFilter) { m_pQueryNode->SetLastLogonQuery(m_dwLastLogonData); } else { m_pQueryNode->SetLastLogonQuery(static_cast(-1)); } m_pQueryNode->SetQueryString(m_szQueryFilter); m_pQueryNode->SetName(m_szName); m_pQueryNode->SetDesc(m_szDescription); m_pQueryNode->SetRootPath(m_szQueryRoot); m_pQueryNode->SetOneLevel((m_bMultiLevel == BST_CHECKED) ? FALSE : TRUE); m_pQueryNode->SetQueryPersist(m_pPersistQueryImpl); } } CHelpDialog::OnOK(); } BOOL CQueryDialog::OnNeedToolTipText(UINT, NMHDR* pTTTStruct, LRESULT* /*ignored*/) { BOOL bRes = FALSE; TOOLTIPTEXT* pTTText = reinterpret_cast(pTTTStruct); if (pTTText != NULL) { if (pTTText->uFlags & TTF_IDISHWND) { UINT nCtrlID = ::GetDlgCtrlID((HWND)pTTText->hdr.idFrom); if (nCtrlID == IDC_ROOT_EDIT) { pTTText->lpszText = (LPWSTR)(LPCWSTR)m_szQueryRoot; bRes = TRUE; } } } return bRes; } void CQueryDialog::OnEditQuery() { CWaitCursor wait; CLIPFORMAT cfDsQueryParams = (CLIPFORMAT)::RegisterClipboardFormat(CFSTR_DSQUERYPARAMS); // // create a query object // HRESULT hr; CComPtr spCommonQuery; hr = ::CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (PVOID *)&spCommonQuery); if (FAILED(hr)) { ReportMessageEx(GetSafeHwnd(), IDS_ERRMSG_NO_DSQUERYUI); return; } // // setup structs to make the query // DSQUERYINITPARAMS dqip; OPENQUERYWINDOW oqw; ZeroMemory(&dqip, sizeof(DSQUERYINITPARAMS)); ZeroMemory(&oqw, sizeof(OPENQUERYWINDOW)); dqip.cbStruct = sizeof(dqip); dqip.dwFlags = DSQPF_NOSAVE | DSQPF_SHOWHIDDENOBJECTS | DSQPF_ENABLEADMINFEATURES; dqip.pDefaultScope = NULL; CString szServerName = m_pComponentData->GetBasePathsInfo()->GetServerName(); if (!szServerName.IsEmpty()) { dqip.dwFlags |= DSQPF_HASCREDENTIALS; dqip.pServer = (PWSTR)(PCWSTR)szServerName; } oqw.cbStruct = sizeof(oqw); oqw.dwFlags = OQWF_OKCANCEL | OQWF_DEFAULTFORM | OQWF_SHOWOPTIONAL | /*OQWF_REMOVEFORMS |*/ OQWF_REMOVESCOPES | OQWF_SAVEQUERYONOK | OQWF_HIDEMENUS | OQWF_HIDESEARCHUI; if (!m_pPersistQueryImpl->IsEmpty()) { oqw.dwFlags |= OQWF_LOADQUERY; } oqw.clsidHandler = CLSID_DsQuery; oqw.pHandlerParameters = &dqip; oqw.clsidDefaultForm = CLSID_DSAdminQueryUIForm; // // set the IPersistQuery pointer (smart pointer) // CComPtr spIPersistQuery; hr = m_pPersistQueryImpl->QueryInterface(IID_IPersistQuery, (void**)&spIPersistQuery); if (FAILED(hr)) { int iRes = ReportMessageEx(GetSafeHwnd(), IDS_ERRMSG_NO_PERSIST_QUERYUI, MB_OKCANCEL | MB_ICONINFORMATION); if (iRes == IDCANCEL) { return; } } // // now smart pointer has refcount=1 for it lifetime // oqw.pPersistQuery = spIPersistQuery; // // Get the HWND of the current dialog // HWND hWnd = GetSafeHwnd(); // // make the call to get the query displayed // CComPtr spQueryResultDataObject; hr = spCommonQuery->OpenQueryWindow(hWnd, &oqw, &spQueryResultDataObject); if (SUCCEEDED(hr) && spQueryResultDataObject != NULL) { // // retrieve the query string from the data object // FORMATETC fmte = {cfDsQueryParams, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM medium = {TYMED_NULL, NULL, NULL}; hr = spQueryResultDataObject->GetData(&fmte, &medium); if (SUCCEEDED(hr)) // we have data { // // get the query string // LPDSQUERYPARAMS pDsQueryParams = (LPDSQUERYPARAMS)medium.hGlobal; LPWSTR pwszFilter = (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->offsetQuery); CString szTempFilter = pwszFilter; // // Check to see if we received a "special" query string // if (pDsQueryParams->dwFlags & DSQF_LAST_LOGON_QUERY) { m_bLastLogonFilter = TRUE; m_dwLastLogonData = pDsQueryParams->dwReserved; LARGE_INTEGER li; GetCurrentTimeStampMinusInterval(m_dwLastLogonData, &li); CString szTimeStamp; litow(li, szTimeStamp); szTempFilter.Format(L"%s(lastLogonTimestamp<=%s)", szTempFilter, szTimeStamp); } else { m_bLastLogonFilter = FALSE; m_dwLastLogonData = 0; } ::ReleaseStgMedium(&medium); // REVIEW_MARCOC: this is a hack waiting for Diz to fix it... // the query string should be a well formed expression. Period // the query string is in the form ()()... // if more of one token, need to wrap as (& ()()...) PWSTR pChar = (LPWSTR)(LPCWSTR)szTempFilter; int nLeftPar = 0; while (*pChar != NULL) { if (*pChar == TEXT('(')) { nLeftPar++; if (nLeftPar > 1) break; } pChar++; } if (nLeftPar > 1) { m_szQueryFilter.Format(_T("(&%s)"), (LPCWSTR)szTempFilter); } else { m_szQueryFilter = szTempFilter; } SetDirty(); } else { // // The user removed all query data from DSQUERYUI // // // Remove filter data // m_szQueryFilter = L""; m_bLastLogonFilter = FALSE; m_dwLastLogonData = 0; SetDirty(); } } SetQueryFilterDisplay(); return; } void CQueryDialog::SetQueryFilterDisplay() { if (m_bLastLogonFilter) { CString szTemp; szTemp.LoadString(IDS_HIDE_LASTLOGON_QUERY); SetDlgItemText(IDC_QUERY_STRING_EDIT, szTemp); } else { SetDlgItemText(IDC_QUERY_STRING_EDIT, m_szQueryFilter); } } int SavedQueriesBrowseCallback(HWND, UINT uMsg, LPARAM lParam, LPARAM /*lpData*/) { int ret = 0; switch (uMsg) { case DSBM_HELP: { TRACE(L"Browse Callback: msg is DSBM_HELP.\n"); LPHELPINFO pHelp = (LPHELPINFO) lParam; TRACE(_T("CtrlId = %d, ContextId = 0x%x\n"), pHelp->iCtrlId, pHelp->dwContextId); if (!pHelp || pHelp->iCtrlId != DSBID_CONTAINERLIST) { ret = 0; // not handled break; } ::WinHelp((HWND)pHelp->hItemHandle, DSADMIN_CONTEXT_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_BROWSE_CONTAINER); ret = 1; } break; default: ret = 0; break; } return ret; } void CQueryDialog::OnBrowse() { DWORD result; CString szBrowseTitle; VERIFY(szBrowseTitle.LoadString(IDS_QUERY_BROWSE_TITLE)); CString szBrowseCaption; VERIFY(szBrowseCaption.LoadString(IDS_QUERY_BROWSE_CAPTION)); WCHAR szPath[2 * MAX_PATH+1]; // // Get the root of the console CString szDNC = m_pComponentData->GetBasePathsInfo()->GetDefaultRootNamingContext(); CString szRootPath; m_pComponentData->GetBasePathsInfo()->ComposeADsIPath(szRootPath, szDNC); DSBROWSEINFO dsbi; ::ZeroMemory( &dsbi, sizeof(dsbi) ); dsbi.hwndOwner = GetSafeHwnd(); dsbi.cbStruct = sizeof (DSBROWSEINFO); dsbi.pszCaption = (LPWSTR)((LPCWSTR)szBrowseTitle); dsbi.pszTitle = (LPWSTR)((LPCWSTR)szBrowseCaption); dsbi.pszRoot = szRootPath; dsbi.pszPath = szPath; dsbi.cchPath = ((2 * MAX_PATH + 1) / sizeof(WCHAR)); dsbi.dwFlags = DSBI_INCLUDEHIDDEN | DSBI_RETURN_FORMAT; dsbi.pfnCallback = SavedQueriesBrowseCallback; dsbi.lParam = 0; dsbi.dwReturnFormat = ADS_FORMAT_X500; result = DsBrowseForContainer( &dsbi ); if ( result == IDOK ) { // // returns -1, 0, IDOK or IDCANCEL // get path from BROWSEINFO struct, put in text edit field // TRACE(_T("returned from DS Browse successfully with:\n %s\n"), dsbi.pszPath); CPathCracker pathCracker; HRESULT hr = pathCracker.Set(CComBSTR(dsbi.pszPath), ADS_SETTYPE_FULL); if (SUCCEEDED(hr)) { hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL); if (SUCCEEDED(hr)) { CComBSTR bstrDN; hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrDN); if (SUCCEEDED(hr)) { SetQueryRoot(bstrDN); SetDirty(); } } } } } void CQueryDialog::SetQueryRoot(PCWSTR pszPath) { m_szQueryRoot = pszPath; CPathCracker pathCracker; HRESULT hr = pathCracker.Set(CComBSTR(m_szQueryRoot), ADS_SETTYPE_DN); if (SUCCEEDED(hr)) { hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY); if (SUCCEEDED(hr)) { CComBSTR bstrDisplayPath; hr = pathCracker.GetElement(0, &bstrDisplayPath); if (SUCCEEDED(hr)) { CString szDisplayString; szDisplayString.Format(L"...\\%s", bstrDisplayPath); SetDlgItemText(IDC_ROOT_EDIT, szDisplayString); } else { SetDlgItemText(IDC_ROOT_EDIT, m_szQueryRoot); } } else { SetDlgItemText(IDC_ROOT_EDIT, m_szQueryRoot); } } else { SetDlgItemText(IDC_ROOT_EDIT, m_szQueryRoot); } } void CQueryDialog::OnMultiLevelChange() { SetDirty(); } void CQueryDialog::OnNameChange() { GetDlgItemText(IDC_NAME_EDIT, m_szName); if (m_szName.IsEmpty()) { SetDirty(FALSE); } else { SetDirty(); } } void CQueryDialog::OnDescriptionChange() { SetDirty(); } /////////////////////////////////////////////////////////////////////////// // CFavoritesNodePropertyPage BEGIN_MESSAGE_MAP(CFavoritesNodePropertyPage, CHelpPropertyPage) ON_EN_CHANGE(IDC_DESCRIPTION_EDIT, OnDescriptionChange) ON_WM_DESTROY() END_MESSAGE_MAP() void CFavoritesNodePropertyPage::DoContextHelp(HWND hWndControl) { if (hWndControl) { ::WinHelp(hWndControl, DSADMIN_CONTEXT_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_FAVORITES_PROPERTY_PAGE); } } BOOL CFavoritesNodePropertyPage::OnInitDialog() { CHelpPropertyPage::OnInitDialog(); m_szOldDescription = m_pFavNode->GetDesc(); SetDlgItemText(IDC_CN, m_pFavNode->GetName()); SetDlgItemText(IDC_DESCRIPTION_EDIT, m_szOldDescription); return FALSE; } void CFavoritesNodePropertyPage::OnDescriptionChange() { CString szNewDescription; GetDlgItemText(IDC_DESCRIPTION_EDIT, szNewDescription); if (szNewDescription == m_szOldDescription) { SetModified(FALSE); } else { SetModified(TRUE); } } BOOL CFavoritesNodePropertyPage::OnApply() { BOOL bRet = TRUE; CString szNewDescription; GetDlgItemText(IDC_DESCRIPTION_EDIT, szNewDescription); if (szNewDescription == m_szOldDescription) { return TRUE; } else { m_pFavNode->SetDesc(szNewDescription); if (m_lNotifyHandle != NULL && m_pDataObject != NULL) { MMCPropertyChangeNotify(m_lNotifyHandle, (LPARAM)m_pDataObject); } } m_szOldDescription = szNewDescription; return bRet; } void CFavoritesNodePropertyPage::OnDestroy() { m_pComponentData->SheetUnlockCookie(m_pFavNode); }