|
|
#include "pch.h"
#pragma hdrstop
/*-----------------------------------------------------------------------------
/ Local functions / data /----------------------------------------------------------------------------*/
#define CCLV_CHECKED 0x00002000
#define CCLV_UNCHECKED 0x00001000
#define DLU_EDGE 6
#define DLU_SEPERATOR 2
#define DLU_FIXEDELEMENT 80
#define CLID_OTHER 1 // other...
#define CLID_FIRST 2
static TCHAR c_szItems[] = TEXT("Items"); static TCHAR c_szObjectClassN[] = TEXT("ObjectClass%d"); static TCHAR c_szProperty[] = TEXT("Property%d"); static TCHAR c_szCondition[] = TEXT("Condition%d"); static TCHAR c_szValue[] = TEXT("Value%d");
static COLUMNINFO columns[] = { 0, 0, IDS_CN, 0, c_szName, 0, 0, IDS_OBJECTCLASS, DSCOLUMNPROP_OBJECTCLASS, NULL, 0, DEFAULT_WIDTH_DESCRIPTION, IDS_DESCRIPTION, 0, c_szDescription, };
static struct { DWORD dwPropertyType; BOOL fNoValue; INT iFilter; INT idsFilter; }
// NTRAID#NTBUG9-618605-2002/09/17-lucios
// Added PROPERTY_ISDNSTRING entries
conditions[] = { PROPERTY_ISUNKNOWN, 0, FILTER_IS, IDS_IS, PROPERTY_ISUNKNOWN, 0, FILTER_ISNOT, IDS_ISNOT, PROPERTY_ISUNKNOWN, 1, FILTER_DEFINED, IDS_DEFINED, PROPERTY_ISUNKNOWN, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
PROPERTY_ISSTRING, 0, FILTER_STARTSWITH, IDS_STARTSWITH, PROPERTY_ISSTRING, 0, FILTER_ENDSWITH, IDS_ENDSWITH, PROPERTY_ISSTRING, 0, FILTER_IS, IDS_IS, PROPERTY_ISSTRING, 0, FILTER_ISNOT, IDS_ISNOT, PROPERTY_ISSTRING, 1, FILTER_DEFINED, IDS_DEFINED, PROPERTY_ISSTRING, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
PROPERTY_ISDNSTRING, 0, FILTER_IS, IDS_IS, PROPERTY_ISDNSTRING, 0, FILTER_ISNOT, IDS_ISNOT, PROPERTY_ISDNSTRING, 1, FILTER_DEFINED, IDS_DEFINED, PROPERTY_ISDNSTRING, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
PROPERTY_ISNUMBER, 0, FILTER_LESSEQUAL, IDS_LESSTHAN, PROPERTY_ISNUMBER, 0, FILTER_GREATEREQUAL, IDS_GREATERTHAN, PROPERTY_ISNUMBER, 0, FILTER_IS, IDS_IS, PROPERTY_ISNUMBER, 0, FILTER_ISNOT, IDS_ISNOT, PROPERTY_ISNUMBER, 1, FILTER_DEFINED, IDS_DEFINED, PROPERTY_ISNUMBER, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
PROPERTY_ISBOOL, 1, FILTER_ISTRUE, IDS_ISTRUE, PROPERTY_ISBOOL, 1, FILTER_ISFALSE, IDS_ISFALSE, PROPERTY_ISBOOL, 1, FILTER_DEFINED, IDS_DEFINED, PROPERTY_ISBOOL, 1, FILTER_UNDEFINED, IDS_NOTDEFINED, };
static struct { INT cx; INT fmt; } view_columns[] = { 128, LVCFMT_LEFT, 128, LVCFMT_LEFT, 128, LVCFMT_LEFT, };
// Class list used for building the property chooser menu
typedef struct { LPWSTR pName; LPTSTR pDisplayName; INT cReferences; } CLASSENTRY, * LPCLASSENTRY;
// State maintained by the property well view
typedef struct { LPCLASSENTRY pClassEntry; // class entry reference
LPWSTR pProperty; LPWSTR pValue; // can be NULL
INT iCondition; } PROPERTYWELLITEM, * LPPROPERTYWELLITEM;
typedef struct { LPCQPAGE pQueryPage; HDPA hdpaItems; HDSA hdsaClasses;
INT cxEdge; INT cyEdge;
HWND hwnd; HWND hwndProperty; HWND hwndPropertyLabel; HWND hwndCondition; HWND hwndConditionLabel; HWND hwndValue; HWND hwndValueLabel; HWND hwndAdd; HWND hwndRemove; HWND hwndList;
LPCLASSENTRY pClassEntry; LPWSTR pPropertyName;
IDsDisplaySpecifier *pdds; } PROPERTYWELL, * LPPROPERTYWELL;
BOOL PropertyWell_OnInitDialog(HWND hwnd, LPCQPAGE pQueryPage); BOOL PropertyWell_OnNCDestroy(LPPROPERTYWELL ppw); BOOL PropertyWell_OnSize(LPPROPERTYWELL ppw, INT cxWindow, INT cyWindow); VOID PropertyWell_OnDrawItem(LPPROPERTYWELL ppw, LPDRAWITEMSTRUCT pDrawItem); VOID PropertyWell_OnChooseProperty(LPPROPERTYWELL ppw);
HRESULT PropertyWell_GetClassList(LPPROPERTYWELL ppw); VOID PropertyWell_FreeClassList(LPPROPERTYWELL ppw); LPCLASSENTRY PropertyWell_FindClassEntry(LPPROPERTYWELL ppw, LPWSTR pObjectClass);
HRESULT PropertyWell_AddItem(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pProperty, INT iCondition, LPWSTR pValue); VOID PropertyWell_RemoveItem(LPPROPERTYWELL ppw, INT iItem, BOOL fDeleteItem); VOID PropertyWell_EditItem(LPPROPERTYWELL ppw, INT iItem); HRESULT PropertyWell_EditProperty(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pPropertyName, INT iCondition); VOID PropertyWell_ClearControls(LPPROPERTYWELL ppw); BOOL PropertyWell_EnableControls(LPPROPERTYWELL ppw, BOOL fEnable); VOID PropertyWell_SetColumnWidths(LPPROPERTYWELL ppw); HRESULT PropertyWell_GetQuery(LPPROPERTYWELL ppw, LPWSTR* ppQuery); HRESULT PropertyWell_Persist(LPPROPERTYWELL ppw, IPersistQuery* pPersistQuery, BOOL fRead);
#define CONDITION_FROM_COMBO(hwnd) \
(int)ComboBox_GetItemData(hwnd, ComboBox_GetCurSel(hwnd))
//
// Control help meppings
//
static DWORD const aFormHelpIDs[] = { IDC_PROPERTYLABEL, IDH_FIELD, IDC_PROPERTY, IDH_FIELD, IDC_CONDITIONLABEL, IDH_CONDITION, IDC_CONDITION, IDH_CONDITION, IDC_VALUELABEL, IDH_VALUE, IDC_VALUE, IDH_VALUE, IDC_ADD, IDH_ADD, IDC_REMOVE, IDH_REMOVE, IDC_CONDITIONLIST, IDH_CRITERIA, 0, 0, };
/*-----------------------------------------------------------------------------
/ PageProc_PropertyWell / --------------------- / PageProc for handling the messages for this object. / / In: / pPage -> instance data for this form / hwnd = window handle for the form dialog / uMsg, wParam, lParam = message parameters / / Out: / HRESULT (E_NOTIMPL) if not handled /----------------------------------------------------------------------------*/ HRESULT CALLBACK PageProc_PropertyWell(LPCQPAGE pPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; LPPROPERTYWELL ppw = (LPPROPERTYWELL)GetWindowLongPtr(hwnd, DWLP_USER); LPWSTR pQuery = NULL;
TraceEnter(TRACE_FORMS, "PageProc_PropertyWell");
// Only handle page messages if we have a property well object,
// which is created when the PropWell dlg is init'd.
if (ppw) { switch ( uMsg ) { case CQPM_INITIALIZE: case CQPM_RELEASE: break;
case CQPM_GETPARAMETERS: { LPDSQUERYPARAMS* ppDsQueryParams = (LPDSQUERYPARAMS*)lParam;
// if the add button is enabled then we must prompt the user and see if they
// want to add the current criteria to the query
if ( IsWindowEnabled(ppw->hwndAdd) ) { TCHAR szProperty[MAX_PATH]; TCHAR szValue[MAX_PATH]; INT id; LoadString(GLOBAL_HINSTANCE, IDS_WINDOWTITLE, szProperty, ARRAYSIZE(szProperty)); LoadString(GLOBAL_HINSTANCE, IDS_ENTERCRITERIA, szValue, ARRAYSIZE(szValue)); id = MessageBox(hwnd, szValue, szProperty, MB_YESNOCANCEL|MB_ICONWARNING); Trace(TEXT("MessageBox returned %08x"), id);
if ( id == IDCANCEL ) { ExitGracefully(hr, S_FALSE, "*** Aborting query ****"); } else if ( id == IDYES ) { GetWindowText(ppw->hwndValue, szValue, ARRAYSIZE(szValue)); id = CONDITION_FROM_COMBO(ppw->hwndCondition);
hr = PropertyWell_AddItem(ppw, ppw->pClassEntry, ppw->pPropertyName, id, szValue); FailGracefully(hr, "Failed to add the item to the current query"); } }
// zap anything in these fields and ensure the controls reflect the new state
PropertyWell_ClearControls(ppw);
if ( SUCCEEDED(PropertyWell_GetQuery(ppw, &pQuery)) && pQuery ) { if ( !*ppDsQueryParams ) hr = QueryParamsAlloc(ppDsQueryParams, pQuery, GLOBAL_HINSTANCE, ARRAYSIZE(columns), columns); else hr = QueryParamsAddQueryString(ppDsQueryParams, pQuery);
LocalFreeStringW(&pQuery); }
break; }
case CQPM_ENABLE: PropertyWell_EnableControls(ppw, (BOOL)wParam); break;
case CQPM_CLEARFORM: ListView_DeleteAllItems(ppw->hwndList); PropertyWell_ClearControls(ppw); break;
case CQPM_PERSIST: hr = PropertyWell_Persist(ppw, (IPersistQuery*)lParam, (BOOL)wParam); break;
case CQPM_SETDEFAULTPARAMETERS: { LPOPENQUERYWINDOW poqw = (LPOPENQUERYWINDOW)lParam;
//
// if we recieve this message we should ensure that we have the IDsDsiplaySpecifier
// object and then we can set the credential information.
//
if ( ppw && poqw->pHandlerParameters ) { LPDSQUERYINITPARAMS pdqip = (LPDSQUERYINITPARAMS)poqw->pHandlerParameters; if ( pdqip->dwFlags & DSQPF_HASCREDENTIALS ) { Trace(TEXT("pUserName : %s"), pdqip->pUserName ? pdqip->pUserName:TEXT("<not specified>")); Trace(TEXT("pServer : %s"), pdqip->pServer ? pdqip->pServer:TEXT("<not specified>"));
hr = ppw->pdds->SetServer(pdqip->pServer, pdqip->pUserName, pdqip->pPassword, DSSSF_DSAVAILABLE); FailGracefully(hr, "Failed to set the server information"); } }
break; }
case DSQPM_GETCLASSLIST: { DWORD cbStruct, offset; LPDSQUERYCLASSLIST pDsQueryClassList = NULL; INT i;
if ( wParam & DSQPM_GCL_FORPROPERTYWELL ) { TraceMsg("Property well calling property well, ignore!"); break; }
if ( !lParam ) ExitGracefully(hr, E_FAIL, "lParam == NULL, not supported");
// Get the list of classes that the user can/has selected properties from,
// having done this we can then can then generate a suitable query.
hr = PropertyWell_GetClassList(ppw); FailGracefully(hr, "Failed to get the class list");
cbStruct = SIZEOF(DSQUERYCLASSLIST) + (DSA_GetItemCount(ppw->hdsaClasses)*SIZEOF(DWORD)); offset = cbStruct;
for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses) ; i++ ) { LPCLASSENTRY pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i); TraceAssert(pCE);
cbStruct += StringByteSizeW(pCE->pName); }
// Allocate the blob we need to pass out and fill it.
Trace(TEXT("Allocating class structure %d"), cbStruct);
pDsQueryClassList = (LPDSQUERYCLASSLIST)CoTaskMemAlloc(cbStruct); TraceAssert(pDsQueryClassList);
if ( !pDsQueryClassList ) ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate class list structure");
Trace(TEXT("pDsQueryClassList %08x"), pDsQueryClassList);
pDsQueryClassList->cbStruct = cbStruct; pDsQueryClassList->cClasses = DSA_GetItemCount(ppw->hdsaClasses);
for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses) ; i++ ) { LPCLASSENTRY pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i); TraceAssert(pCE);
Trace(TEXT("Adding class: %s"), pCE->pName);
pDsQueryClassList->offsetClass[i] = offset; StringByteCopyW(pDsQueryClassList, offset, pCE->pName); offset += StringByteSizeW(pCE->pName); }
TraceAssert(pDsQueryClassList); *((LPDSQUERYCLASSLIST*)lParam) = pDsQueryClassList;
break; }
case CQPM_HELP: { LPHELPINFO pHelpInfo = (LPHELPINFO)lParam; WinHelp((HWND)pHelpInfo->hItemHandle, DSQUERY_HELPFILE, HELP_WM_HELP, (DWORD_PTR)aFormHelpIDs); break; }
case DSQPM_HELPTOPICS: { HWND hwndFrame = (HWND)lParam; HtmlHelp(hwndFrame, TEXT("omc.chm"), HH_HELP_FINDER, 0); break; }
default: hr = E_NOTIMPL; break; } }
exit_gracefully:
TraceLeaveResult(hr); }
/*-----------------------------------------------------------------------------
/ Dialog helper functions /----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ DlgProc_PropertyWell / -------------------- / Standard dialog proc for the form, handle any special buttons and other / such nastyness we must here. / / In: / hwnd, uMsg, wParam, lParam = standard parameters / / Out: / INT_PTR /----------------------------------------------------------------------------*/ INT_PTR CALLBACK DlgProc_PropertyWell(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { INT_PTR fResult = FALSE; LPPROPERTYWELL ppw = NULL;
if ( uMsg == WM_INITDIALOG ) { fResult = PropertyWell_OnInitDialog(hwnd, (LPCQPAGE)lParam); } else { ppw = (LPPROPERTYWELL)GetWindowLongPtr(hwnd, DWLP_USER);
switch ( uMsg ) { case WM_NCDESTROY: PropertyWell_OnNCDestroy(ppw); break;
case WM_COMMAND: { switch ( LOWORD(wParam) ) { case IDC_PROPERTYLABEL: { if ( HIWORD(wParam) == BN_CLICKED ) PropertyWell_OnChooseProperty(ppw);
break; } case IDC_PROPERTY: case IDC_CONDITION: case IDC_VALUE: { if ( (HIWORD(wParam) == EN_CHANGE) || (HIWORD(wParam) == CBN_SELCHANGE) ) PropertyWell_EnableControls(ppw, TRUE);
break; }
case IDC_ADD: { TCHAR szProperty[MAX_PATH] = { TEXT('\0') }; TCHAR szValue[MAX_PATH] = { TEXT('\0') }; INT iCondition;
iCondition = CONDITION_FROM_COMBO(ppw->hwndCondition);
if ( IsWindowEnabled(ppw->hwndValue) ) GetWindowText(ppw->hwndValue, szValue, ARRAYSIZE(szValue));
PropertyWell_AddItem(ppw, ppw->pClassEntry, ppw->pPropertyName, iCondition, szValue);
break; } case IDC_REMOVE: { INT item = ListView_GetNextItem(ppw->hwndList, -1, LVNI_ALL|LVNI_SELECTED); PropertyWell_RemoveItem(ppw, item, TRUE); } }
break; }
case WM_DRAWITEM: PropertyWell_OnDrawItem(ppw, (LPDRAWITEMSTRUCT)lParam); break;
case WM_NOTIFY: { LPNMHDR pNotifyGeneric = (LPNMHDR)lParam;
switch ( pNotifyGeneric->code ) { case LVN_DELETEITEM: { NM_LISTVIEW* pNotifyLVDel = (NM_LISTVIEW*)lParam; PropertyWell_RemoveItem(ppw, pNotifyLVDel->iItem, FALSE); break; }
case LVN_ITEMCHANGED: { PropertyWell_EnableControls(ppw, TRUE); break; }
case NM_DBLCLK: { INT item = ListView_GetNextItem(ppw->hwndList, -1, LVNI_ALL|LVNI_SELECTED); PropertyWell_EditItem(ppw, item); break; }
case LVN_GETEMPTYTEXT: { NMLVDISPINFO* pNotifyLVGetText = (NMLVDISPINFO*)lParam; if ( pNotifyLVGetText->item.mask & LVIF_TEXT ) { LoadString( GLOBAL_HINSTANCE, IDS_CRITERIAEMPTY, pNotifyLVGetText->item.pszText, pNotifyLVGetText->item.cchTextMax ); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); fResult = TRUE; } break; } }
break; }
case WM_SIZE: return PropertyWell_OnSize(ppw, LOWORD(lParam), HIWORD(lParam)); case WM_CONTEXTMENU: WinHelp((HWND)wParam, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aFormHelpIDs); fResult = TRUE; break; } } return fResult; }
/*-----------------------------------------------------------------------------
/ PropertyWell_OnInitDlg / ---------------------- / Initialize the dialog, constructing the property DPA so that we can / build the store the query. / / In: / hwnd = window handle being initialized / pDsQuery -> CDsQuery object to associate with / / Out: / BOOL /----------------------------------------------------------------------------*/ BOOL PropertyWell_OnInitDialog(HWND hwnd, LPCQPAGE pQueryPage) { HRESULT hr; LPPROPERTYWELL ppw; TCHAR szBuffer[MAX_PATH]; LV_COLUMN lvc; INT i;
TraceEnter(TRACE_PWELL, "PropertyWell_OnInitDialog");
// Allocate the state structure and fill it
ppw = (LPPROPERTYWELL)LocalAlloc(LPTR, SIZEOF(PROPERTYWELL));
if ( !ppw ) ExitGracefully(hr, E_OUTOFMEMORY, "Failed to alloc PROPERTYWELL struct");
Trace(TEXT("ppw = %08x"), ppw); SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)ppw); // now initialize the structure
ppw->pQueryPage = pQueryPage; //ppw->hdpaItems = NULL;
//ppw->hdsaClasses = NULL;
ppw->cxEdge = GetSystemMetrics(SM_CXEDGE); ppw->cyEdge = GetSystemMetrics(SM_CYEDGE);
ppw->hwnd = hwnd; ppw->hwndProperty = GetDlgItem(hwnd, IDC_PROPERTY); ppw->hwndPropertyLabel = GetDlgItem(hwnd, IDC_PROPERTYLABEL); ppw->hwndCondition = GetDlgItem(hwnd, IDC_CONDITION); ppw->hwndConditionLabel = GetDlgItem(hwnd, IDC_CONDITIONLABEL); ppw->hwndValue = GetDlgItem(hwnd, IDC_VALUE); ppw->hwndValueLabel = GetDlgItem(hwnd, IDC_VALUELABEL); ppw->hwndAdd = GetDlgItem(hwnd, IDC_ADD); ppw->hwndRemove = GetDlgItem(hwnd, IDC_REMOVE); ppw->hwndList = GetDlgItem(hwnd, IDC_CONDITIONLIST);
ppw->hdpaItems = DPA_Create(16);
if ( !ppw->hdpaItems ) ExitGracefully(hr, E_FAIL, "Failed to create DPA");
// ppw->pClassItem = NULL;
// ppw->pPropertyName = NULL;
hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&ppw->pdds); FailGracefully(hr, "Failed to CoCreate the IDsDisplaySpecifier object"); ListView_SetExtendedListViewStyle(ppw->hwndList, LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP);
// Add the conditions to the condition picker, then add the columns to the
// condition list.
for ( i = 0 ; i < ARRAYSIZE(view_columns) ; i++ ) { lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT; lvc.fmt = view_columns[i].fmt; lvc.cx = view_columns[i].cx; lvc.pszText = TEXT("Bla"); ListView_InsertColumn(ppw->hwndList, i, &lvc); }
Edit_LimitText(ppw->hwndValue, MAX_PATH);
PropertyWell_EnableControls(ppw, TRUE);
exit_gracefully:
TraceLeaveValue(TRUE); }
/*-----------------------------------------------------------------------------
/ PropertyWell_OnNCDestroy / ------------------------ / The dialog is being nuked, therefore remove our reference to the CDsQuery / and free any allocations we have with this window. / / In: / ppw -> window defn to use / / Out: / BOOL /----------------------------------------------------------------------------*/ BOOL PropertyWell_OnNCDestroy(LPPROPERTYWELL ppw) { BOOL fResult = TRUE;
TraceEnter(TRACE_PWELL, "PropertyWell_OnNCDestroy");
if ( ppw ) { if ( ppw->hdpaItems ) { TraceAssert(0 == DPA_GetPtrCount(ppw->hdpaItems)); DPA_Destroy(ppw->hdpaItems); }
PropertyWell_FreeClassList(ppw); LocalFreeStringW(&ppw->pPropertyName); DoRelease(ppw->pdds);
SetWindowLongPtr(ppw->hwnd, DWLP_USER, (LONG_PTR)NULL); LocalFree((HLOCAL)ppw); }
TraceLeaveValue(fResult); }
/*-----------------------------------------------------------------------------
/ PropertyWell_OnSize / ------------------- / The property well dialog is being sized, therefore lets move the / controls around within it to reflect the new size. / / In: / ppw -> property well to size / cx, cy = new size / / Out: / BOOL /----------------------------------------------------------------------------*/ BOOL PropertyWell_OnSize(LPPROPERTYWELL ppw, INT cxWindow, INT cyWindow) { RECT rect; SIZE size; INT x, cx; INT xProperty, xCondition, xValue; INT iSeperator, iEdge, iElement, iFixedElement;
TraceEnter(TRACE_PWELL, "PropertyWell_OnSize"); Trace(TEXT("New size cxWindow %d, cyWindow %d"), cxWindow, cyWindow);
iSeperator = (DLU_SEPERATOR * LOWORD(GetDialogBaseUnits())) / 4; iEdge = (DLU_EDGE * LOWORD(GetDialogBaseUnits())) / 4; iFixedElement = (DLU_FIXEDELEMENT * LOWORD(GetDialogBaseUnits())) / 4; x = cxWindow - (iEdge*2) - (iSeperator*2); iElement = x / 3; iFixedElement = min(iElement, iFixedElement); iElement = x - (iFixedElement*2);
// Move the controls around accordingly
xProperty = iEdge; GetRealWindowInfo(ppw->hwndProperty, &rect, &size); SetWindowPos(ppw->hwndProperty, NULL, xProperty, rect.top, iFixedElement, size.cy, SWP_NOZORDER); GetRealWindowInfo(ppw->hwndPropertyLabel, &rect, &size); SetWindowPos(ppw->hwndPropertyLabel, NULL, xProperty, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
xCondition = iEdge + iFixedElement + iSeperator; GetRealWindowInfo(ppw->hwndCondition, &rect, &size); SetWindowPos(ppw->hwndCondition, NULL, xCondition, rect.top, iFixedElement, size.cy, SWP_NOZORDER); GetRealWindowInfo(ppw->hwndConditionLabel, &rect, &size); SetWindowPos(ppw->hwndConditionLabel, NULL, xCondition, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
xValue = cxWindow - iEdge - iElement; GetRealWindowInfo(ppw->hwndValue, &rect, &size); SetWindowPos(ppw->hwndValue, NULL, xValue, rect.top, iElement, size.cy, SWP_NOZORDER); GetRealWindowInfo(ppw->hwndValueLabel, &rect, &size); SetWindowPos(ppw->hwndValueLabel, NULL, xValue, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE); // Move the add / remove buttons
GetRealWindowInfo(ppw->hwndRemove, &rect, &size); x = cxWindow - iEdge - size.cx; SetWindowPos(ppw->hwndRemove, NULL, x, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
GetRealWindowInfo(ppw->hwndAdd, &rect, &size); x -= size.cx + iSeperator; SetWindowPos(ppw->hwndAdd, NULL, x, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
// Move the list view control + size accordingly
GetRealWindowInfo(ppw->hwndList, &rect, &size); SetWindowPos(ppw->hwndList, NULL, iEdge, rect.top, cxWindow - (iEdge*2), size.cy, SWP_NOZORDER);
PropertyWell_SetColumnWidths(ppw);
TraceLeaveValue(FALSE); }
/*-----------------------------------------------------------------------------
/ PropertyWell_OnDrawItem / ----------------------- / The property button is owner drawn, therefore lets handle rendering that / we assume that the base implementation (eg. the button control) is / handling storing the text, font and other interesting information we / will just render the face as required. / / In: / ppw -> property well to size / pDrawItem -> DRAWITEMSTRUCT used for rendering / / Out: / void /----------------------------------------------------------------------------*/ VOID PropertyWell_OnDrawItem(LPPROPERTYWELL ppw, LPDRAWITEMSTRUCT pDrawItem) { SIZE thin = { ppw->cxEdge / 2, ppw->cyEdge / 2 }; RECT rc = pDrawItem->rcItem; HDC hdc = pDrawItem->hDC; BOOL fDisabled = pDrawItem->itemState & ODS_DISABLED; BOOL fSelected = pDrawItem->itemState & ODS_SELECTED; BOOL fFocus = (pDrawItem->itemState & ODS_FOCUS) #if (_WIN32_WINNT >= 0x0500)
&& !(pDrawItem->itemState & ODS_NOFOCUSRECT) #endif
&& !(pDrawItem->itemState & ODS_DISABLED); TCHAR szBuffer[64]; HBRUSH hbr; INT i, x, y; SIZE sz; UINT fuFlags = DST_PREFIXTEXT;
TraceEnter(TRACE_PWELL, "PropertyWell_OnDrawItem");
if ( pDrawItem->CtlID != IDC_PROPERTYLABEL ) goto exit_gracefully;
// render the button edges (assumes that we have an NT4 look)
thin.cx = max(thin.cx, 1); thin.cy = max(thin.cy, 1);
if ( fSelected ) { DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT|BF_ADJUST); OffsetRect(&rc, 1, 1); } else { DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT|BF_ADJUST); }
FillRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
// put the focus rect in if we are focused...
if ( fFocus ) { InflateRect(&rc, -thin.cx, -thin.cy); DrawFocusRect(hdc, &rc); InflateRect(&rc, thin.cx, thin.cy); }
InflateRect(&rc, 1-thin.cx, -ppw->cyEdge); rc.left += ppw->cxEdge*2;
// paint the arrow to the right of the control
x = rc.right - ppw->cxEdge - 13; y = rc.top + ((rc.bottom - rc.top)/2) - 2;
if ( fDisabled ) { hbr = (HBRUSH)GetSysColorBrush(COLOR_3DHILIGHT); hbr = (HBRUSH)SelectObject(hdc, hbr);
x++; y++; PatBlt(hdc, x+1, y, 7, 1, PATCOPY); PatBlt(hdc, x+2, y+1, 5, 1, PATCOPY); PatBlt(hdc, x+3, y+2, 3, 1, PATCOPY); PatBlt(hdc, x+4, y+3, 1, 1, PATCOPY);
SelectObject(hdc, hbr); x--; y--; }
hbr = (HBRUSH)GetSysColorBrush(fDisabled ? COLOR_3DSHADOW : COLOR_BTNTEXT); hbr = (HBRUSH)SelectObject(hdc, hbr);
PatBlt(hdc, x, y+1, 7, 1, PATCOPY); PatBlt(hdc, x+1, y+2, 5, 1, PATCOPY); PatBlt(hdc, x+2, y+3, 3, 1, PATCOPY); PatBlt(hdc, x+3, y+4, 1, 1, PATCOPY);
SelectObject(hdc, hbr); rc.right = x;
// render the label in the remaining area (clipped accordingly)
i = GetWindowText(ppw->hwndPropertyLabel, szBuffer, ARRAYSIZE(szBuffer)); GetTextExtentPoint(hdc, szBuffer, i, &sz);
x = rc.left+(((rc.right-rc.left)-sz.cx)/2);
if ( fDisabled ) fuFlags |= DSS_DISABLED;
#if (_WIN32_WINNT >= 0x0500)
if ( pDrawItem->itemState & ODS_NOACCEL ) fuFlags |= DSS_HIDEPREFIX; #endif
DrawState(hdc, NULL, NULL, (LPARAM)szBuffer, (WPARAM)0, x, rc.top, sz.cx, sz.cy, fuFlags); exit_gracefully:
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ PropertyWell_OnChooseProperty / ----------------------------- / Display the class / property list and build the menu from it, this calls on / several helper functions. / / In: / ppw -> property well to size / / Out: / void /----------------------------------------------------------------------------*/
//
// call the property enumerator and populate the our DPA
//
typedef struct { UINT wID; HDPA hdpaAttributes; INT iClass; HMENU hMenu; } PROPENUMSTRUCT, * LPPROPENUMSTRUCT;
HRESULT CALLBACK _FillMenuCB(LPARAM lParam, LPCWSTR pAttributeName, LPCWSTR pDisplayName, DWORD dwFlags) { HRESULT hres = S_OK; PROPENUMSTRUCT *ppes = (PROPENUMSTRUCT *)lParam; MENUITEMINFO mii = { 0 }; UINT_PTR iProperty = 0;
TraceEnter(TRACE_PWELL, "_FillMenuCB");
if ( !(dwFlags & DSECAF_NOTLISTED) ) { hres = StringDPA_AppendStringW(ppes->hdpaAttributes, pAttributeName, &iProperty); FailGracefully(hres, "Failed to add the attribute to the DPA");
mii.cbSize = SIZEOF(mii); mii.fMask = MIIM_TYPE|MIIM_ID|MIIM_DATA; mii.dwItemData = MAKELPARAM(ppes->iClass, iProperty); mii.fType = MFT_STRING; mii.wID = ppes->wID++; mii.dwTypeData = (LPTSTR)pDisplayName; // why this takes as non-const is beyond me
mii.cch = lstrlenW(pDisplayName); if ( !InsertMenuItem(ppes->hMenu, 0x7fff, TRUE, &mii) ) ExitGracefully(hres, E_FAIL, "Failed to add the item to the menu"); } else { TraceMsg("Property marked as hidden, so not appending to the DPA"); } hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres); }
VOID PropertyWell_OnChooseProperty(LPPROPERTYWELL ppw) { HRESULT hr; HMENU hMenuToTrack, hMenu = NULL; PROPENUMSTRUCT pes = { 0 }; RECT rcItem; LPCLASSENTRY pCE; LPWSTR pszAttribute; UINT uID; INT iItem, iClass; MENUITEMINFO mii = { 0 }; DECLAREWAITCURSOR;
TraceEnter(TRACE_PWELL, "PropertyWell_OnChooseProperty");
SetWaitCursor();
// construct a menu, and populate with the elements from teh class list,
// which we store in a DSA assocaited with this query form
hr = PropertyWell_GetClassList(ppw); FailGracefully(hr, "Failed to get the class list");
pes.wID = CLID_FIRST; pes.hdpaAttributes = DPA_Create(4); if ( !pes.hdpaAttributes ) ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate string DPA");
hMenuToTrack = hMenu = CreatePopupMenu(); TraceAssert(hMenu);
if ( !hMenu ) ExitGracefully(hr, E_FAIL, "Failed to create class menu");
for ( pes.iClass = 0; pes.iClass < DSA_GetItemCount(ppw->hdsaClasses); pes.iClass++ ) { pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, pes.iClass); TraceAssert(pCE);
// Create the sub-menu for this entry in the cache and populate it with the list of
// properties we picked from the schema.
pes.hMenu = CreatePopupMenu(); TraceAssert(pes.hMenu);
if ( !pes.hMenu ) ExitGracefully(hr, E_FAIL, "Failed when creating the sub menu for the property list");
if ( FAILED(EnumClassAttributes(ppw->pdds, pCE->pName, _FillMenuCB, (LPARAM)&pes)) ) { DestroyMenu(pes.hMenu); ExitGracefully(hr, E_FAIL, "Failed when building the property menu"); } // Now add that sub-menu to the main menu with a caption that reflects the name of
// the class we are picking from.
mii.cbSize = SIZEOF(mii); mii.fMask = MIIM_SUBMENU|MIIM_TYPE; mii.fType = MFT_STRING; mii.hSubMenu = pes.hMenu; mii.dwTypeData = pCE->pDisplayName; mii.cch = MAX_PATH;
if ( !InsertMenuItem(hMenu, 0x7fff, TRUE, &mii) ) { DestroyMenu(pes.hMenu); ExitGracefully(hr, E_FAIL, "Failed when building the class menu"); } }
ResetWaitCursor();
// having constructed the menu lets display it just below the button
// we are invoked from, if the user selects something then lets put
// it into the edit line which will enable the rest of the UI.
GetWindowRect(ppw->hwndPropertyLabel, &rcItem);
if ( GetMenuItemCount(hMenu) == 1 ) { TraceMsg("Single class in menu, therefore just showing properties"); hMenuToTrack = GetSubMenu(hMenu, 0); TraceAssert(hMenuToTrack); } uID = TrackPopupMenu(hMenuToTrack, TPM_TOPALIGN|TPM_RETURNCMD, rcItem.left, rcItem.bottom, 0, ppw->hwnd, NULL); if ( !uID ) { TraceMsg("Menu canceled nothing selected"); } else { mii.cbSize = SIZEOF(mii); mii.fMask = MIIM_DATA;
if ( !GetMenuItemInfo(hMenu, uID, FALSE, &mii) ) ExitGracefully(hr, E_FAIL, "Failed to get item data");
// unpick the item data and get the iClass and iProperty of the item
// we have selected, that way we can then populate the control
// with the property name.
pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, LOWORD(mii.dwItemData)); TraceAssert(pCE);
pszAttribute = StringDPA_GetStringW(pes.hdpaAttributes, HIWORD(mii.dwItemData)); Trace(TEXT("Attribute selected : %s"), pszAttribute);
hr = PropertyWell_EditProperty(ppw, pCE, pszAttribute, -1); FailGracefully(hr, "Failed to set edit property"); } hr = S_OK; // success
exit_gracefully:
if ( hMenu ) DestroyMenu(hMenu);
StringDPA_Destroy(&pes.hdpaAttributes);
ResetWaitCursor();
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ Class/Property maps /----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ PropertyWell_GetClassList / ------------------------- / Obtain the list of visible classes for the for this user. If the / list is already present then just return S_OK. / / In: / ppw -> property well structure / / Out: / HRESULT /----------------------------------------------------------------------------*/
//
// Return all display specifiers who have a class display name and a list of
// attributes to be displayed in the UI.
//
WCHAR c_szQuery[] = L"(&(classDisplayName=*)(attributeDisplayNames=*))";
LPWSTR pProperties[] = { L"name", L"classDisplayName", };
#define PAGE_SIZE 128
HRESULT PropertyWell_GetClassList(LPPROPERTYWELL ppw) { HRESULT hr; IQueryFrame* pQueryFrame = NULL; IDirectorySearch* pds = NULL; ADS_SEARCH_COLUMN column; ADS_SEARCHPREF_INFO prefInfo[3]; ADS_SEARCH_HANDLE hSearch = NULL; CLASSENTRY ce; LPDSQUERYCLASSLIST pDsQueryClassList = NULL; LPWSTR pName = NULL; LPWSTR pDisplayName = NULL; WCHAR szBufferW[MAX_PATH]; INT i; DECLAREWAITCURSOR;
TraceEnter(TRACE_PWELL, "PropertyWell_GetClassList");
SetWaitCursor();
if ( !ppw->hdsaClasses ) { // Construct a DSA for us to store the class information we need.
ppw->hdsaClasses = DSA_Create(SIZEOF(CLASSENTRY), 4); TraceAssert(ppw->hdsaClasses);
if ( !ppw->hdsaClasses ) ExitGracefully(hr, E_OUTOFMEMORY, "Failed to create class DSA");
// Call the query form we are part of to see if they want to declare any classes
// for us to show in the drop down. We use the CQFWM_GETFRAME to get the
// IQueryFrame interface from the form and then call all the forms
// with a magic bit so we (the property well) ignore the
// request for the class list.
if ( SendMessage(GetParent(ppw->hwnd), CQFWM_GETFRAME, 0, (LPARAM)&pQueryFrame) ) { if ( SUCCEEDED(pQueryFrame->CallForm(NULL, DSQPM_GETCLASSLIST, DSQPM_GCL_FORPROPERTYWELL, (LPARAM)&pDsQueryClassList)) ) { if ( pDsQueryClassList ) { for ( i = 0 ; i < pDsQueryClassList->cClasses ; i++ ) { LPWSTR pObjectClass = (LPWSTR)ByteOffset(pDsQueryClassList, pDsQueryClassList->offsetClass[i]); TraceAssert(pObjectClass);
TraceAssert(ppw->pdds != NULL); ppw->pdds->GetFriendlyClassName(pObjectClass, szBufferW, ARRAYSIZE(szBufferW));
ce.pName = NULL; ce.pDisplayName = NULL; ce.cReferences = 0;
if ( FAILED(LocalAllocStringW(&ce.pName, pObjectClass)) || FAILED(LocalAllocStringW(&ce.pDisplayName, szBufferW)) || ( -1 == DSA_AppendItem(ppw->hdsaClasses, &ce)) ) { LocalFreeStringW(&ce.pName); LocalFreeString(&ce.pDisplayName); } } } } }
// if we didn't get anything from the form we are hosted on then let us
// troll around in the display specifier container collecting all the
// objects from there.
if ( DSA_GetItemCount(ppw->hdsaClasses) == 0 ) { // Set the query prefernece to single level scope, and async retrevial rather
// than waiting for all objects
TraceAssert(ppw->pdds); hr = ppw->pdds->GetDisplaySpecifier(NULL, IID_IDirectorySearch, (LPVOID*)&pds); FailGracefully(hr, "Failed to get IDsSearch on the display-spec container");
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; prefInfo[0].vValue.dwType = ADSTYPE_INTEGER; prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS; prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN; prefInfo[1].vValue.Boolean = TRUE;
prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; // paged results
prefInfo[2].vValue.dwType = ADSTYPE_INTEGER; prefInfo[2].vValue.Integer = PAGE_SIZE;
hr = pds->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo)); FailGracefully(hr, "Failed to set search preferences");
hr = pds->ExecuteSearch(c_szQuery, pProperties, ARRAYSIZE(pProperties), &hSearch); FailGracefully(hr, "Failed in ExecuteSearch");
while ( TRUE ) { LocalFreeStringW(&pName); LocalFreeStringW(&pDisplayName);
// Get the next row from the result set, it consists of
// two columns. The first column is the class name of
// the object (<className-Display>) and the second
// is the friendly name of the class we are trying
// to display.
hr = pds->GetNextRow(hSearch); FailGracefully(hr, "Failed to get the next row");
if ( hr == S_ADS_NOMORE_ROWS ) { TraceMsg("No more results, no more rows"); break; }
if ( SUCCEEDED(pds->GetColumn(hSearch, pProperties[0], &column)) ) { hr = StringFromSearchColumn(&column, &pName); pds->FreeColumn(&column); FailGracefully(hr, "Failed to get the name object"); if (!pName) { break; } }
if ( SUCCEEDED(pds->GetColumn(hSearch, pProperties[1], &column)) ) { hr = StringFromSearchColumn(&column, &pDisplayName); pds->FreeColumn(&column); FailGracefully(hr, "Failed to get the display name from the object"); }
Trace(TEXT("Display name %s for class %s"), pDisplayName, pName);
// now allocate an item and put it into the menu so we can
// allow the user to select an object from the class.
TraceAssert(pName); // NTRAID#NTBUG9-344860-2001/10/16-lucios
wchar_t *tailString=L"-Display"; int tailLen=wcslen(tailString); int pNameLen=wcslen(pName);
TraceAssert(pNameLen >= tailLen); TraceAssert(lstrcmpi(pName+pNameLen-tailLen,tailString)==0);
if ( (pNameLen < tailLen) || lstrcmpi(pName+pNameLen-tailLen,tailString)!=0 ) { hr=E_FAIL; FailGracefully ( hr, "Display name from the object is not terminated by -Display" ); }
pName[pNameLen-tailLen]=0;
ce.pName = NULL; ce.pDisplayName = NULL; ce.cReferences = 0;
if ( *pName ) { if ( FAILED(LocalAllocStringW(&ce.pName, pName)) || FAILED(LocalAllocStringW(&ce.pDisplayName, pDisplayName)) || ( -1 == DSA_AppendItem(ppw->hdsaClasses, &ce)) ) { LocalFreeStringW(&ce.pName); LocalFreeString(&ce.pDisplayName); } } } } }
hr = S_OK;
exit_gracefully:
LocalFreeStringW(&pName); LocalFreeStringW(&pDisplayName);
if ( pDsQueryClassList ) CoTaskMemFree(pDsQueryClassList);
if ( hSearch ) pds->CloseSearchHandle(hSearch);
DoRelease(pQueryFrame); DoRelease(pds);
PropertyWell_EnableControls(ppw, TRUE);
ResetWaitCursor();
TraceLeaveResult(hr); }
/*-----------------------------------------------------------------------------
/ PropertyWell_FreeClassList / -------------------------- / Tidy up the class list by walking the DSA if we have one allocated / and release all dangling elements. / / In: / ppw -> property well structure / / Out: / HRESULT /----------------------------------------------------------------------------*/
INT _FreeClassListCB(LPVOID pItem, LPVOID pData) { LPCLASSENTRY pCE = (LPCLASSENTRY)pItem;
LocalFreeStringW(&pCE->pName); LocalFreeString(&pCE->pDisplayName);
return 1; }
VOID PropertyWell_FreeClassList(LPPROPERTYWELL ppw) { HRESULT hr;
TraceEnter(TRACE_PWELL, "PropertyWell_FreeClassList");
if ( ppw->hdsaClasses ) DSA_DestroyCallback(ppw->hdsaClasses, _FreeClassListCB, NULL);
ppw->hdsaClasses = NULL;
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ PropertyWell_FindClass / ---------------------- / Find the class the caller wants. They give us a property well / and a class name, we return them a class entry structure or NULL. / / In: / ppw -> property well structure / pObjectClass = class to locate / / Out: / LPCLASSETNRY /----------------------------------------------------------------------------*/ LPCLASSENTRY PropertyWell_FindClassEntry(LPPROPERTYWELL ppw, LPWSTR pObjectClass) { LPCLASSENTRY pResult = NULL; INT i;
TraceEnter(TRACE_PWELL, "PropertyWell_FindClass");
if ( SUCCEEDED(PropertyWell_GetClassList(ppw)) ) { for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses) ; i++ ) { LPCLASSENTRY pClassEntry = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i); TraceAssert(pClassEntry);
if ( !StrCmpIW(pClassEntry->pName, pObjectClass) ) { pResult = pClassEntry; break; } } }
TraceLeaveValue(pResult); }
/*-----------------------------------------------------------------------------
/ Rule list helper functions /----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ PropertyWell_AddItem / -------------------- / Add an item to the list of rules. / / In: / ppw -> window defn to use / pProperty = property name / iCondition = id of condition to apply / pValue = string value to compare against / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT PropertyWell_AddItem(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pProperty, INT iCondition, LPWSTR pValue) { HRESULT hr; INT item = -1; LV_ITEM lvi; LPPROPERTYWELLITEM pItem = NULL; TCHAR szBuffer[80]; WCHAR szBufferW[80];
TraceEnter(TRACE_PWELL, "PropertyWell_AddItem"); Trace(TEXT("Property: %s, Condition: %d, Value: %s"), pProperty, iCondition, pValue);
// Allocate an item structure to be stored into the list view DPA.
pItem = (LPPROPERTYWELLITEM)LocalAlloc(LPTR, SIZEOF(PROPERTYWELLITEM)); TraceAssert(pItem);
Trace(TEXT("pItem %0x8"), pItem);
if ( !pItem ) ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate item");
pItem->pClassEntry = pClassEntry; pClassEntry->cReferences += 1;
// pItem->pProperty = NULL;
// pItem->pValue = NULL;
pItem->iCondition = iCondition;
hr = LocalAllocStringW(&pItem->pProperty, pProperty); FailGracefully(hr, "Failed to add property to DPA item");
if ( pValue && pValue[0] ) { hr = LocalAllocStringW(&pItem->pValue, pValue); FailGracefully(hr, "Failed to add value to DPA item"); }
// Add the item to the list view, lParam pItem structure we just allocated,
// therefore when calling delete we can tidy up accordingly
TraceAssert(ppw->pdds); hr = GetFriendlyAttributeName(ppw->pdds, pClassEntry->pName, pProperty, szBufferW, ARRAYSIZE(szBufferW));
lvi.mask = LVIF_TEXT|LVIF_STATE|LVIF_PARAM; lvi.iItem = 0x7fffffff; lvi.iSubItem = 0; lvi.state = LVIS_SELECTED; lvi.stateMask = LVIS_SELECTED; lvi.pszText = szBufferW; lvi.lParam = (LPARAM)pItem;
item = ListView_InsertItem(ppw->hwndList, &lvi); Trace(TEXT("item %d"), item);
if ( item < 0 ) ExitGracefully(hr, E_FAIL, "Failed to put item into list view");
LoadString(GLOBAL_HINSTANCE, conditions[iCondition].idsFilter, szBuffer, ARRAYSIZE(szBuffer)); ListView_SetItemText(ppw->hwndList, item, 1, szBuffer); if ( pValue ) ListView_SetItemText(ppw->hwndList, item, 2, pValue);
DPA_InsertPtr(ppw->hdpaItems, item, pItem);
hr = S_OK; // succeeeded
exit_gracefully:
if ( FAILED(hr) && (item == -1) && pItem ) { LocalFreeStringW(&pItem->pProperty); LocalFreeStringW(&pItem->pValue); LocalFree((HLOCAL)pItem); }
if ( SUCCEEDED(hr) ) { PropertyWell_ClearControls(ppw); ListView_EnsureVisible(ppw->hwndList, item, FALSE); PropertyWell_SetColumnWidths(ppw); } TraceLeaveResult(hr); }
/*-----------------------------------------------------------------------------
/ PropertyWell_RemoveItem / ----------------------- / Remvoe the given item from the list. If fDeleteItem is true then we / delete the list view entry, which in turn will call us again to / remove the actual data from our DPA. / / In: / ppw -> window defn to use / iItem = item to be removed / fDelelete = call ListView_DeleteItem / / Out: / BOOL /----------------------------------------------------------------------------*/ void PropertyWell_RemoveItem(LPPROPERTYWELL ppw, INT iItem, BOOL fDeleteItem) { INT item; LV_ITEM lvi; LPPROPERTYWELLITEM pItem;
TraceEnter(TRACE_PWELL, "PropertyWell_RemoveItem"); Trace(TEXT("iItem %d, fDeleteItem %s"), iItem, fDeleteItem ? TEXT("TRUE"):TEXT("FALSE"));
if ( ppw && (iItem >= 0) ) { if ( fDeleteItem ) { // Now delete the item from the view, note that as a result of this we will
// be called again (from the WM_NOTIFY handler) to tidy up the structure.
item = ListView_GetNextItem(ppw->hwndList, iItem, LVNI_BELOW);
if ( item == -1 ) item = ListView_GetNextItem(ppw->hwndList, iItem, LVNI_ABOVE);
if ( item != -1 ) { ListView_SetItemState(ppw->hwndList, item, LVIS_SELECTED, LVIS_SELECTED); ListView_EnsureVisible(ppw->hwndList, item, FALSE); }
ListView_DeleteItem(ppw->hwndList, iItem); PropertyWell_SetColumnWidths(ppw); PropertyWell_EnableControls(ppw, TRUE); } else { // Get the item from that index in the DPA, release the memory that it
// owns and then release it.
pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, iItem); TraceAssert(pItem);
if ( pItem ) { pItem->pClassEntry->cReferences -= 1; TraceAssert(pItem->pClassEntry->cReferences >= 0); LocalFreeStringW(&pItem->pProperty); LocalFreeStringW(&pItem->pValue); LocalFree((HLOCAL)pItem);
DPA_DeletePtr(ppw->hdpaItems, iItem); } } }
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ PropertyWell_EditItem / --------------------- / Edit the given item in the list. In doing so we remove from the list / and populate the edit controls with data that represents this / rule. / / In: / ppw -> window defn to use / iItem = item to edit / / Out: / - /----------------------------------------------------------------------------*/ void PropertyWell_EditItem(LPPROPERTYWELL ppw, INT iItem) { TraceEnter(TRACE_PWELL, "PropertyWell_EditItem");
if ( ppw && (iItem >= 0) ) { LPPROPERTYWELLITEM pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, iItem); TraceAssert(pItem);
PropertyWell_EditProperty(ppw, pItem->pClassEntry, pItem->pProperty, pItem->iCondition); if ( pItem->pValue ) SetWindowText(ppw->hwndValue, pItem->pValue);
PropertyWell_RemoveItem(ppw, iItem, TRUE); PropertyWell_EnableControls(ppw, TRUE); }
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ PropertyWell_EditProperty / ------------------------- / Set the property edit control and reflect that change into the / other controls in the dialog (the conditions and editor). / / In: / ppw -> property well / pClassEntry -> class entry structure / pPropertyName -> property name to edit / iCondition = condition to select / / Out: / void /----------------------------------------------------------------------------*/ HRESULT PropertyWell_EditProperty(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pPropertyName, INT iCondition) { HRESULT hr; TCHAR szBuffer[MAX_PATH]; WCHAR szBufferW[MAX_PATH]; INT i, iItem, iCurSel = 0; DWORD dwPropertyType;
TraceEnter(TRACE_PWELL, "PropertyWell_EditProperty"); Trace(TEXT("Property name '%s', iCondition %d"), pPropertyName, iCondition);
// set the property name for this value, then look it up in the cache to get
// information about the operators we can apply.
ppw->pClassEntry = pClassEntry; // set state for the item we are editing
LocalFreeStringW(&ppw->pPropertyName); hr = LocalAllocStringW(&ppw->pPropertyName, pPropertyName); FailGracefully(hr, "Failed to alloc the property name"); TraceAssert(ppw->pdds); GetFriendlyAttributeName(ppw->pdds, pClassEntry->pName, pPropertyName, szBufferW, ARRAYSIZE(szBufferW)); SetWindowText(ppw->hwndProperty, szBufferW);
ComboBox_ResetContent(ppw->hwndCondition); SetWindowText(ppw->hwndValue, TEXT(""));
dwPropertyType = PropertyIsFromAttribute(pPropertyName, ppw->pdds);
for ( i = 0 ; i < ARRAYSIZE(conditions); i++ ) { if ( conditions[i].dwPropertyType == dwPropertyType ) { LoadString(GLOBAL_HINSTANCE, conditions[i].idsFilter, szBuffer, ARRAYSIZE(szBuffer)); iItem = ComboBox_AddString(ppw->hwndCondition, szBuffer);
if ( iItem >= 0 ) { ComboBox_SetItemData(ppw->hwndCondition, iItem, i); // i == condition index
if ( i == iCondition ) { Trace(TEXT("Setting current selection to %d"), iItem); iCurSel = iItem; } } } }
ComboBox_SetCurSel(ppw->hwndCondition, iCurSel); SetWindowText(ppw->hwndValue, TEXT(""));
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
/*-----------------------------------------------------------------------------
/ PropertyWell_EnableControls / --------------------------- / Check the controls within the view and determine what controls / should be enabled within it. If fDisable == TRUE then disable all the / controls in the dialog regardless of the dependancies on other controls. / / The return value indicates if the control sare in a state whereby / we can add the criteria to the query. / / In: / ppw -> window defn to use / fEnable = FALSE then disable all controls in dialog / / Out: / BOOL /----------------------------------------------------------------------------*/
// NTRAID#NTBUG9-650930-2002/07/30-artm
// Factored out common code and fixed focus bug.
//
// PropertyWell_ShiftFocus() : helper fctn for PropertyWell_EnableControls
//
// Sets the focus to the control whose ID == first_choice, but only if that
// control can be retrieved. If not, tries to set the focus to the control whose
// ID == second_choice.
//
HRESULT PropertyWell_ShiftFocus(LPPROPERTYWELL ppw, int first_choice, int second_choice) { HRESULT hr = S_OK;
do // false loop
{ if (!ppw) { hr = E_INVALIDARG; break; }
HWND hWndParent = GetParent(ppw->hwnd); if (!hWndParent) { hr = S_FALSE; break; }
HWND focusControl = GetDlgItem(hWndParent, first_choice); int control_id = first_choice; if (!focusControl) { focusControl = GetDlgItem(hWndParent, second_choice); control_id = second_choice; }
if (focusControl) { SendDlgItemMessage( hWndParent, control_id, BM_SETSTYLE, MAKEWPARAM(BS_DEFPUSHBUTTON, 0), MAKELPARAM(TRUE, 0) );
SendMessage(hWndParent, WM_NEXTDLGCTL, (WPARAM)focusControl, TRUE); SetFocus(focusControl); } else { hr = E_FAIL; } } while (false);
return hr; }
BOOL PropertyWell_EnableControls(LPPROPERTYWELL ppw, BOOL fEnable) { BOOL fEnableCondition = FALSE; BOOL fEnableValue = FALSE; BOOL fEnableAdd = FALSE; BOOL fEnableRemove = FALSE; INT iCondition; DWORD dwButtonStyle; HWND hWndParent;
TraceEnter(TRACE_PWELL, "PropertyWell_EnableControls");
EnableWindow(ppw->hwndPropertyLabel, fEnable); EnableWindow(ppw->hwndProperty, fEnable); EnableWindow(ppw->hwndList, fEnable);
if ( fEnable ) { fEnableCondition = (ppw->pPropertyName != NULL);
if ( fEnableCondition ) { iCondition = CONDITION_FROM_COMBO(ppw->hwndCondition); fEnableValue = !conditions[iCondition].fNoValue;
if ( !fEnableValue || GetWindowTextLength(ppw->hwndValue) ) fEnableAdd = TRUE; }
if ( ListView_GetSelectedCount(ppw->hwndList) && ( -1 != ListView_GetNextItem(ppw->hwndList, -1, LVNI_SELECTED|LVNI_ALL)) ) { fEnableRemove = TRUE; } }
if ( !fEnableAdd && !fEnableValue ) { dwButtonStyle = (DWORD) GetWindowLong(ppw->hwndAdd, GWL_STYLE); if (dwButtonStyle & BS_DEFPUSHBUTTON) { SendMessage(ppw->hwndAdd, BM_SETSTYLE, MAKEWPARAM(BS_PUSHBUTTON, 0), MAKELPARAM(TRUE, 0));
// NTRAID#NTBUG9-650930-2002/07/30-artm
HRESULT hr = PropertyWell_ShiftFocus( ppw, CQID_FINDNOW, // 1st choice for new focus
IDOK); // 2nd choice for new focus
} }
if (!fEnableRemove) {
dwButtonStyle = (DWORD) GetWindowLong(ppw->hwndRemove, GWL_STYLE);
if (dwButtonStyle & BS_DEFPUSHBUTTON) { SendMessage( ppw->hwndRemove, BM_SETSTYLE, MAKEWPARAM(BS_PUSHBUTTON, 0), MAKELPARAM(TRUE, 0) );
// NTRAID#NTBUG9-650930-2002/07/30-artm
HRESULT hr = PropertyWell_ShiftFocus( ppw, CQID_FINDNOW, // 1st choice for new focus
IDOK); // 2nd choice for new focus
}
}
// If disabling control that has focus, we need to move the focus to
// avoid losing it.
EnableWindow(ppw->hwndConditionLabel, fEnableCondition); EnableWindow(ppw->hwndCondition, fEnableCondition); EnableWindow(ppw->hwndValueLabel, fEnableValue); EnableWindow(ppw->hwndValue, fEnableValue); EnableWindow(ppw->hwndAdd, fEnableAdd); EnableWindow(ppw->hwndRemove, fEnableRemove);
if ( fEnableAdd ) SetDefButton(ppw->hwnd, IDC_ADD);
TraceLeaveValue(fEnableAdd); }
/*-----------------------------------------------------------------------------
/ PropertyWell_ClearControls / -------------------------- / Zap the contents of the edit controls. / / In: / ppw -> window defn to use / / Out: / BOOL /----------------------------------------------------------------------------*/ VOID PropertyWell_ClearControls(LPPROPERTYWELL ppw) { TraceEnter(TRACE_PWELL, "PropertyWell_ClearControls");
LocalFreeStringW(&ppw->pPropertyName); SetWindowText(ppw->hwndProperty, TEXT(""));
ComboBox_ResetContent(ppw->hwndCondition); SetWindowText(ppw->hwndValue, TEXT("")); PropertyWell_EnableControls(ppw, TRUE);
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ PropertyWell_SetColumnWidths / ---------------------------- / Fix the widths of the columns in the list view section of the property / well so that the most is visible. / / In: / ppw -> window defn to use / / Out: / - /----------------------------------------------------------------------------*/ VOID PropertyWell_SetColumnWidths(LPPROPERTYWELL ppw) { RECT rect2; INT cx;
TraceEnter(TRACE_PWELL, "PropertyWell_SetColumnWidths");
GetClientRect(ppw->hwndList, &rect2); InflateRect(&rect2, -GetSystemMetrics(SM_CXBORDER)*2, 0);
cx = MulDiv((rect2.right - rect2.left), 20, 100);
ListView_SetColumnWidth(ppw->hwndList, 0, cx); ListView_SetColumnWidth(ppw->hwndList, 1, cx); ListView_SetColumnWidth(ppw->hwndList, 2, rect2.right - (cx*2));
TraceLeave(); }
/*-----------------------------------------------------------------------------
/ PropertyWell_GetQuery / --------------------- / Take the items in the property well and construct a query from them, / the query is an AND of all the fields present in the list. The conditon / table in lists the prefix, condition and postfix for each of the possible / conditions in the combo box. / / In: / ppw -> property well to construct from / ppQuery -> receives the query string / / Out: / HRESULT /----------------------------------------------------------------------------*/
static void _GetQuery(LPPROPERTYWELL ppw, LPWSTR pQuery, UINT* pLen) { INT i; TraceEnter(TRACE_PWELL, "_GetQuery");
if ( pQuery ) *pQuery = TEXT('\0');
TraceAssert(ppw->hdsaClasses); TraceAssert(ppw->hdpaItems);
for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses); i++ ) { LPCLASSENTRY pClassEntry = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i); TraceAssert(pClassEntry);
if ( pClassEntry->cReferences ) { Trace(TEXT("Class %s referenced %d times"), pClassEntry->pName, pClassEntry->cReferences); GetFilterString(pQuery, pLen, FILTER_IS, L"objectCategory", pClassEntry->pName); } }
for ( i = 0 ; i < DPA_GetPtrCount(ppw->hdpaItems); i++ ) { LPPROPERTYWELLITEM pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, i); TraceAssert(pItem); // NTRAID#NTBUG9- 669515-2002/02/20-lucios
// On the very specific case below, when we are searching for a computer
// That has samAccountName being exactly something, we need to search for
// name + "$" because there is a convention that the samAccountName should be
// created with the $ and displayed without it.
// Since this is not necessarily true we still search for name.
// The calls to PutStringElementW inside the if, would normally belong
// inside lower level functions like GetFilterString, but this is the
// most appropriate place for this patch.
// The magic strings "computer" and "samAccountName" should not be
// localized. 9 and 15 are being used for additional safety in memmory
// access provided by wcsncmp as opposed to wcscmp. +2 is for $ and \0.
// Finally, if the 3 first conditions succeed, but the allocation fails
// or newValue is NULL we fallback in the else, which is the code we had
// before the fix.
// After this fix was originally designed it was revisited to include
// ENDSWITH and ISNOT. ISNOT doesn't require the extra or "(|)" inside
// the if, since the default "&" is good enough.
LPWSTR newValue=NULL; if( ( conditions[pItem->iCondition].idsFilter == IDS_IS || conditions[pItem->iCondition].idsFilter == IDS_ENDSWITH || conditions[pItem->iCondition].idsFilter == IDS_ISNOT ) && _wcsnicmp(pItem->pClassEntry->pName,L"computer",9)==0 && _wcsnicmp(pItem->pProperty,L"samAccountName",15)==0 && SUCCEEDED(LocalAllocStringLenW(&newValue, wcslen(pItem->pValue)+2)) && newValue!=NULL ) { if(conditions[pItem->iCondition].idsFilter != IDS_ISNOT) PutStringElementW( pQuery, pLen, L"(|" ); GetFilterString(pQuery, pLen, conditions[pItem->iCondition].iFilter, pItem->pProperty, pItem->pValue); wcscpy(newValue,pItem->pValue); wcscat(newValue,L"$"); GetFilterString(pQuery, pLen, conditions[pItem->iCondition].iFilter, pItem->pProperty, newValue); if(conditions[pItem->iCondition].idsFilter != IDS_ISNOT) PutStringElementW( pQuery, pLen, L")" ); } else { GetFilterString(pQuery, pLen, conditions[pItem->iCondition].iFilter, pItem->pProperty, pItem->pValue); } }
TraceLeave(); }
HRESULT PropertyWell_GetQuery(LPPROPERTYWELL ppw, LPWSTR* ppQuery) { HRESULT hr; UINT cchQuery = 0;
TraceEnter(TRACE_PWELL, "PropertyWell_GetQuery"); *ppQuery = NULL;
hr = PropertyWell_GetClassList(ppw); FailGracefully(hr, "Failed to get the class list");
_GetQuery(ppw, NULL, &cchQuery); Trace(TEXT("cchQuery %d"), cchQuery);
if ( cchQuery ) { hr = LocalAllocStringLenW(ppQuery, cchQuery); FailGracefully(hr, "Failed to allocate buffer for query string");
_GetQuery(ppw, *ppQuery, NULL); Trace(TEXT("Resulting query is %s"), *ppQuery); }
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
/*-----------------------------------------------------------------------------
/ PropertyWell_Persist / -------------------- / Persist the contents of the property well, either read them or write / them depending on the given flag. / / In: / ppw -> property well to work with / pPersistQuery -> IPersistQuery structure to work with / fRead = read or write / / Out: / HRESULT /----------------------------------------------------------------------------*/ HRESULT PropertyWell_Persist(LPPROPERTYWELL ppw, IPersistQuery* pPersistQuery, BOOL fRead) { HRESULT hr; LPPROPERTYWELLITEM pItem; TCHAR szBuffer[80]; INT iItems; INT i;
TraceEnter(TRACE_PWELL, "PropertyWell_Persist");
if ( !pPersistQuery ) ExitGracefully(hr, E_INVALIDARG, "No persist object");
if ( fRead ) { // Read the items from the IPersistQuery object, first get the number of items
// we need to get back. Then loop through them all getting the property, condition
// and value.
hr = pPersistQuery->ReadInt(c_szMsPropertyWell, c_szItems, &iItems); FailGracefully(hr, "Failed to get item count");
Trace(TEXT("Attempting to read %d items"), iItems);
for ( i = 0 ; i < iItems ; i++ ) { LPCLASSENTRY pClassEntry; TCHAR szObjectClass[MAX_PATH]; TCHAR szProperty[MAX_PATH]; TCHAR szValue[MAX_PATH]; INT iCondition;
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szObjectClassN, i); hr = pPersistQuery->ReadString(c_szMsPropertyWell, szBuffer, szObjectClass, ARRAYSIZE(szObjectClass)); FailGracefully(hr, "Failed to read object class");
pClassEntry = PropertyWell_FindClassEntry(ppw, szObjectClass); TraceAssert(pClassEntry);
if ( !pClassEntry ) ExitGracefully(hr, E_FAIL, "Failed to get objectClass / map to available class");
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szProperty, i); hr = pPersistQuery->ReadString(c_szMsPropertyWell, szBuffer, szProperty, ARRAYSIZE(szProperty)); FailGracefully(hr, "Failed to read property");
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szCondition, i); hr = pPersistQuery->ReadInt(c_szMsPropertyWell, szBuffer, &iCondition); FailGracefully(hr, "Failed to write condition");
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szValue, i); if ( FAILED(pPersistQuery->ReadString(c_szMsPropertyWell, szBuffer, szValue, ARRAYSIZE(szValue))) ) { TraceMsg("No value defined in incoming stream"); szValue[0] = TEXT('\0'); }
hr = PropertyWell_AddItem(ppw, pClassEntry, szProperty, iCondition, szValue); FailGracefully(hr, "Failed to add search criteria to query"); } } else { // Write the content of the property well out, store the items then for
// each store Condition%d, Value%d, Property%d.
iItems = DPA_GetPtrCount(ppw->hdpaItems);
Trace(TEXT("Attempting to store %d items"), iItems);
hr = pPersistQuery->WriteInt(c_szMsPropertyWell, c_szItems, iItems); FailGracefully(hr, "Failed to write item count");
for ( i = 0 ; i < iItems ; i++ ) { pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, i);
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szObjectClassN, i); hr = pPersistQuery->WriteString(c_szMsPropertyWell, szBuffer, pItem->pClassEntry->pName); FailGracefully(hr, "Failed to write property");
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szProperty, i); hr = pPersistQuery->WriteString(c_szMsPropertyWell, szBuffer, pItem->pProperty); FailGracefully(hr, "Failed to write property");
// NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szCondition, i); hr = pPersistQuery->WriteInt(c_szMsPropertyWell, szBuffer, pItem->iCondition); FailGracefully(hr, "Failed to write condition");
if ( pItem->pValue ) { // NTRAID#NTBUG9-554458-2002/02/20-lucios. Pending fix.
wsprintf(szBuffer, c_szValue, i); hr = pPersistQuery->WriteString(c_szMsPropertyWell, szBuffer, pItem->pValue); FailGracefully(hr, "Failed to write value"); } } }
hr = S_OK;
exit_gracefully:
TraceLeaveResult(hr); }
|