windows-nt/Source/XPSP1/NT/shell/ext/dsui/dsquery/params.cpp
2020-09-26 16:20:57 +08:00

724 lines
22 KiB
C++

#include "pch.h"
#pragma hdrstop
/*-----------------------------------------------------------------------------
/ Helper functions
/----------------------------------------------------------------------------*/
HRESULT _GetQueryString(LPWSTR pQuery, UINT* pLen, LPWSTR pPrefixQuery, HWND hDlg, LPPAGECTRL aCtrl, INT iCtrls);
HRESULT _GetFilterQueryString(LPWSTR pFilter, UINT* pLen, HWND hwndFilter, HDSA hdsaColumns);
/*-----------------------------------------------------------------------------
/ Query paremeter helpers
/----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ ClassListAlloc
/ --------------
/ Construct a class list allocation based on the list of classes
/ we are given.
/
/ In:
/ ppClassList -> receives a class list
/ cClassList / cClassList = array of classes to allocat from
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
STDAPI ClassListAlloc(LPDSQUERYCLASSLIST* ppDsQueryClassList, LPWSTR* aClassNames, INT cClassNames)
{
HRESULT hres;
DWORD cbStruct, offset;
LPDSQUERYCLASSLIST pDsQueryClassList = NULL;
INT i;
USES_CONVERSION;
TraceEnter(TRACE_FORMS, "ClassListAlloc");
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++ )
{
TraceAssert(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.
Trace(TEXT("Allocating class structure %d"), cbStruct);
pDsQueryClassList = (LPDSQUERYCLASSLIST)CoTaskMemAlloc(cbStruct);
TraceAssert(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++ )
{
Trace(TEXT("Adding class: %s"), W2T(aClassNames[i]));
pDsQueryClassList->offsetClass[i] = offset;
StringByteCopyW(pDsQueryClassList, offset, aClassNames[i]);
offset += StringByteSizeW(aClassNames[i]);
}
hres = S_OK;
exit_gracefully:
TraceAssert(pDsQueryClassList);
if (ppDsQueryClassList)
*ppDsQueryClassList = pDsQueryClassList;
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ 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
/ hInstance = hInstance to write into parameter block
/ iColumns = number of columns
/ pColumnInfo -> column info structure to use
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
STDAPI QueryParamsAlloc(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery, HINSTANCE hInstance, LONG iColumns, LPCOLUMNINFO aColumnInfo)
{
HRESULT hres;
LPDSQUERYPARAMS pDsQueryParams = NULL;
LONG cbStruct;
LONG i;
TraceEnter(TRACE_FORMS, "QueryParamsAlloc");
if ( !pQuery || !iColumns || !ppDsQueryParams )
ExitGracefully(hres, E_INVALIDARG, "Failed to build query parameter block");
// Compute the size of the structure we need to be using
cbStruct = SIZEOF(DSQUERYPARAMS) + (SIZEOF(DSCOLUMN)*iColumns);
cbStruct += StringByteSizeW(pQuery);
for ( i = 0 ; i < iColumns ; i++ )
{
if ( aColumnInfo[i].pPropertyName )
cbStruct += StringByteSizeW(aColumnInfo[i].pPropertyName);
}
pDsQueryParams = (LPDSQUERYPARAMS)CoTaskMemAlloc(cbStruct);
if ( !pDsQueryParams )
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate parameter block");
// Structure allocated so lets fill it with data
pDsQueryParams->cbStruct = cbStruct;
pDsQueryParams->dwFlags = 0;
pDsQueryParams->hInstance = hInstance;
pDsQueryParams->iColumns = iColumns;
pDsQueryParams->dwReserved = 0;
cbStruct = SIZEOF(DSQUERYPARAMS) + (SIZEOF(DSCOLUMN)*iColumns);
pDsQueryParams->offsetQuery = cbStruct;
StringByteCopyW(pDsQueryParams, cbStruct, pQuery);
cbStruct += StringByteSizeW(pQuery);
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 = cbStruct;
StringByteCopyW(pDsQueryParams, cbStruct, aColumnInfo[i].pPropertyName);
cbStruct += StringByteSizeW(aColumnInfo[i].pPropertyName);
}
else
{
pDsQueryParams->aColumns[i].offsetProperty = aColumnInfo[i].iPropertyIndex;
}
}
hres = S_OK; // success
exit_gracefully:
if ( FAILED(hres) && pDsQueryParams )
{
CoTaskMemFree(pDsQueryParams);
pDsQueryParams = NULL;
}
if (ppDsQueryParams)
*ppDsQueryParams = pDsQueryParams;
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ 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
/----------------------------------------------------------------------------*/
STDAPI QueryParamsAddQueryString(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery)
{
HRESULT hres;
LPWSTR pOriginalQuery = NULL;
LPDSQUERYPARAMS pDsQuery = *ppDsQueryParams;
INT cbQuery, i;
TraceEnter(TRACE_FORMS, "QueryParamsAddQueryString");
if ( pQuery )
{
if ( !pDsQuery )
ExitGracefully(hres, E_INVALIDARG, "No query to append to");
// 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 = StringByteSizeW(pQuery) + StringByteSizeW(L"(&)");
Trace(TEXT("DSQUERYPARAMS being resized by %d bytes"), cbQuery);
hres = LocalAllocStringW(&pOriginalQuery, (LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery));
FailGracefully(hres, "Failed to take copy of original query string");
pDsQuery = (LPDSQUERYPARAMS)CoTaskMemRealloc(pDsQuery, pDsQuery->cbStruct+cbQuery);
if ( !pDsQuery )
ExitGracefully(hres, E_OUTOFMEMORY, "Failed to re-alloc control block");
*ppDsQueryParams = pDsQuery;
// 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 )
{
Trace(TEXT("Fixing offset of property at index %d"), i);
pDsQuery->aColumns[i].offsetProperty += cbQuery;
}
}
StrCpyW((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), L"(&");
StrCatW((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), pOriginalQuery);
StrCatW((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), pQuery);
StrCatW((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), L")");
pDsQuery->cbStruct += cbQuery;
}
hres = S_OK;
exit_gracefully:
LocalFreeStringW(&pOriginalQuery);
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ Form to query string helper functions
/----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ GetQueryString
/ --------------
/ Build the form parmaeters into a LDAP query string using the given table.
/
/ In:
/ ppQuery -> receives the string pointer
/ pPrefixQuery -> string placed at head of query / = NULL if none
/ hDlg = handle for the dialog to get the data from
/ aCtrls / iCtrls = control information for the window
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
STDAPI GetQueryString(LPWSTR* ppQuery, LPWSTR pPrefixQuery, HWND hDlg, LPPAGECTRL aCtrls, INT iCtrls)
{
HRESULT hres;
UINT cLen = 0;
TraceEnter(TRACE_FORMS, "GetQueryString");
hres = _GetQueryString(NULL, &cLen, pPrefixQuery, hDlg, aCtrls, iCtrls);
FailGracefully(hres, "Failed 1st pass (compute string length)");
if ( cLen )
{
hres = LocalAllocStringLenW(ppQuery, cLen);
FailGracefully(hres, "Failed to alloc buffer for query string");
hres = _GetQueryString(*ppQuery, &cLen, pPrefixQuery, hDlg, aCtrls, iCtrls);
FailGracefully(hres, "Failed 2nd pass (fill buffer)");
}
hres = cLen ? S_OK:S_FALSE;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ _GetQueryString
/ ---------------
/ Build the string from the controls or just return the buffer size required.
/
/ In:
/ pQuery -> filled with query string / = NULL
/ pLen = updated to reflect the required string length
/ pPrefixQuery -> string placed at head of query / = NULL if none
/ hDlg = handle for the dialog to get the data from
/ aCtrls / iCtrls = control information for the window
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
HRESULT _GetQueryString(LPWSTR pQuery, UINT* pLen, LPWSTR pPrefixQuery, HWND hDlg, LPPAGECTRL aCtrl, INT iCtrls)
{
HRESULT hres;
INT i;
TCHAR szBuffer[MAX_PATH];
USES_CONVERSION;
TraceEnter(TRACE_FORMS, "_GetQueryString");
if ( !hDlg || (!aCtrl && iCtrls) )
ExitGracefully(hres, E_INVALIDARG, "No dialog or controls list");
Trace(TEXT("Checking %d controls"), iCtrls);
PutStringElementW(pQuery, pLen, pPrefixQuery);
for ( i = 0 ; i < iCtrls; i++ )
{
if ( GetDlgItemText(hDlg, aCtrl[i].nIDDlgItem, szBuffer, ARRAYSIZE(szBuffer)) )
{
Trace(TEXT("Property %s, value %s"), W2T(aCtrl[i].pPropertyName), szBuffer);
GetFilterString(pQuery, pLen, aCtrl[i].iFilter, aCtrl[i].pPropertyName, T2W(szBuffer));
}
}
Trace(TEXT("Resulting query is -%s- (%d)"), pQuery ? W2T(pQuery):TEXT("<no buffer>"), pLen ? *pLen:0);
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ GetFilterString
/ ---------------
/ Given a property, a property and its filter generate a suitable filter
/ string that map returning it into the given buffer via PutStringElement.
/
/ In:
/ pFilter, pLen = buffer information that we are returning int
/ iFilter = condition to be applied
/ pProperty -> property name
/ pValue -> value
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
struct
{
BOOL fNoValue;
BOOL fFixWildcard;
LPWSTR pPrefix;
LPWSTR pOperator;
LPWSTR pPostfix;
}
filter_info[] =
{
//
// The server today does not support contains searches, therefore
// for consistency map that to a STARTSWITH, NOTSTARTSWITH
//
#if 0
0, 1, L"(", L"=*", L"*)", // CONTAIN
0, 1, L"(!", L"=*", L"*)", // NOTCONTAINS
#else
0, 1, L"(", L"=", L"*)", // CONTAINS
0, 1, L"(!", L"=", L"*)", // NOTCONTAINS
#endif
0, 1, L"(", L"=", L"*)", // STARTSWITH
0, 1, L"(", L"=*", L")", // ENDSWITH
0, 0, L"(", L"=", L")", // IS
0, 0, L"(!", L"=", L")", // ISNOT
0, 0, L"(", L">=", L")", // GREATEREQUAL
0, 0, L"(", L"<=", L")", // LESSEQUAL
1, 0, L"(", L"=*)", NULL, // DEFINED
1, 0, L"(!", L"=*)", NULL, // UNDEFINED
1, 0, L"(", L"=TRUE)", NULL, // TRUE
1, 0, L"(!", L"=TRUE)", NULL, // FALSE
};
STDAPI GetFilterString(LPWSTR pFilter, UINT* pLen, INT iFilter, LPWSTR pProperty, LPWSTR pValue)
{
HRESULT hres;
USES_CONVERSION;
TraceEnter(TRACE_VIEW, "GetFilterString");
// Check to see if the value we have contains a wildcard, if it does then just
// make it is exact assuming the user knows what they are doing - ho ho ho!
if ( pValue && filter_info[iFilter-FILTER_FIRST].fFixWildcard )
{
if ( wcschr(pValue, L'*') )
{
TraceMsg("START/ENDS contains wildcards, making is exactly");
iFilter = FILTER_IS;
}
}
// Fix the condition to index into the our array then
// put the string elements down
iFilter -= FILTER_FIRST; // compensate for non-zero index
if ( iFilter >= ARRAYSIZE(filter_info) )
ExitGracefully(hres, E_FAIL, "Bad filter value");
PutStringElementW(pFilter, pLen, filter_info[iFilter].pPrefix);
PutStringElementW(pFilter, pLen, pProperty);
PutStringElementW(pFilter, pLen, filter_info[iFilter].pOperator);
if ( !filter_info[iFilter].fNoValue )
{
LPWSTR pszOutput = pFilter ? (pFilter + lstrlenW(pFilter)) : NULL;
for (; *pValue; pValue++)
{
int cchLen = 1;
switch (*pValue)
{
// case L'*': // do no RFC encode *, if we do then the user cannot do foo* for a wildcarded string
case L'(':
case L')':
case L'\\':
{
if (pszOutput)
{
LPCWSTR pszToHex = L"0123456789abcdef";
*pszOutput++ = L'\\';
*pszOutput++ = pszToHex[(*pValue & 0xf0) >> 4];
*pszOutput++ = pszToHex[(*pValue & 0x0f)];
}
cchLen = 3;
break;
}
default:
if (pszOutput)
{
*pszOutput++ = *pValue;
}
break;
}
if (pLen)
*pLen = (*pLen + cchLen);
}
if (pszOutput)
*pszOutput = L'\0';
}
PutStringElementW(pFilter, pLen, filter_info[iFilter].pPostfix);
Trace(TEXT("Filter is: %s"), pFilter ? W2T(pFilter):TEXT("<none>"));
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ GetPatternString
/ ----------------
/ Given a string wrap in suitable wildcards to do the filtering of
/ results.
/
/ In:
/ pPattern, pLen = buffer information that we are returning int
/ iFilter = condition to be applied
/ pValue -> value
/
/ Out:
/ VOID
/----------------------------------------------------------------------------*/
struct
{
LPTSTR pPrefix;
LPTSTR pPostfix;
}
pattern_info[] =
{
TEXT("*"), TEXT("*"), // CONTAIN
TEXT("*"), TEXT("*"), // NOTCONTAINS
TEXT(""), TEXT("*"), // STARTSWITH
TEXT("*"), TEXT(""), // ENDSWITH
TEXT(""), TEXT(""), // IS
TEXT(""), TEXT(""), // ISNOT
};
STDAPI GetPatternString(LPTSTR pFilter, UINT* pLen, INT iFilter, LPTSTR pValue)
{
HRESULT hres;
TraceEnter(TRACE_VIEW, "GetFilterString");
iFilter -= FILTER_FIRST; // compensate for non-zero index
if ( iFilter >= ARRAYSIZE(pattern_info) )
ExitGracefully(hres, E_FAIL, "Bad filter value");
PutStringElement(pFilter, pLen, pattern_info[iFilter].pPrefix);
PutStringElement(pFilter, pLen, pValue);
PutStringElement(pFilter, pLen, pattern_info[iFilter].pPostfix);
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}
/*-----------------------------------------------------------------------------
/ Dialog helper functions
/----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ EnablePageControls
/ ------------------
/ Enable/Disable the controls on a query form.
/
/ In:
/ hDlg = handle for the dialog to get the data from
/ aCtrls / iCtrls = control information for the window
/ fEnable = TRUE/FALSE to enable disable window controls
/
/ Out:
/ VOID
/----------------------------------------------------------------------------*/
STDAPI_(VOID) EnablePageControls(HWND hDlg, LPPAGECTRL aCtrl, INT iCtrls, BOOL fEnable)
{
HRESULT hres;
INT i;
HWND hwndCtrl;
TraceEnter(TRACE_FORMS, "EnablePageControls");
if ( !hDlg || (!aCtrl && iCtrls) )
ExitGracefully(hres, E_INVALIDARG, "No dialog or controls list");
Trace(TEXT("%s %d controls"), fEnable ? TEXT("Enabling"):TEXT("Disabling"),iCtrls);
for ( i = 0 ; i < iCtrls; i++ )
{
hwndCtrl = GetDlgItem(hDlg, aCtrl[i].nIDDlgItem);
if ( hwndCtrl )
EnableWindow(hwndCtrl, fEnable);
}
exit_gracefully:
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ ResetPageControls
/ ------------------
/ Reset all the form controls back to their default state.
/
/ In:
/ hDlg = handle for the dialog to get the data from
/ aCtrls / iCtrls = control information for the window
/
/ Out:
/ VOID
/----------------------------------------------------------------------------*/
STDAPI_(VOID) ResetPageControls(HWND hDlg, LPPAGECTRL aCtrl, INT iCtrls)
{
HRESULT hres;
INT i;
TraceEnter(TRACE_FORMS, "ResetPageControls");
if ( !hDlg || (!aCtrl && iCtrls) )
ExitGracefully(hres, E_INVALIDARG, "No dialog or controls list");
for ( i = 0 ; i < iCtrls; i++ )
SetDlgItemText(hDlg, aCtrl[i].nIDDlgItem, TEXT(""));
exit_gracefully:
TraceLeave();
}
/*-----------------------------------------------------------------------------
/ SetDlgItemFromProperty
/ ----------------------
/ Given an IPropertyBag interface set the control with the text for
/ that property. We assume the property is a string.
/
/ In:
/ ppb -> IPropertyBag
/ pszProperty -> property to read
/ hwnd, id = control information
/ pszDefault = default text / = NULL if not important
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
STDAPI SetDlgItemFromProperty(IPropertyBag* ppb, LPCWSTR pszProperty, HWND hwnd, INT id, LPCWSTR pszDefault)
{
HRESULT hres;
VARIANT variant;
USES_CONVERSION;
TraceEnter(TRACE_FORMS, "SetDlgItemFromProperty");
VariantInit(&variant);
if ( ppb && SUCCEEDED(ppb->Read(pszProperty, &variant, NULL)) )
{
if ( V_VT(&variant) == VT_BSTR )
{
pszDefault = V_BSTR(&variant);
Trace(TEXT("property contained: %s"), W2CT(pszDefault));
}
}
if ( pszDefault )
SetDlgItemText(hwnd, id, W2CT(pszDefault));
VariantClear(&variant);
TraceLeaveResult(S_OK);
}
/*-----------------------------------------------------------------------------
/ Query Persistance
/----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
/ PersistQuery
/ ------------
/ Persist a query into a IPersistQuery object
/
/ In:
/ pPersistQuery = query to persist into
/ fRead = read?
/ pSectionName = section name to use when persisting
/ hDlg = DLG to persist from
/ aCtrls / iCtrls = ctrls to be persisted
/
/ Out:
/ HRESULT
/----------------------------------------------------------------------------*/
STDAPI PersistQuery(IPersistQuery* pPersistQuery, BOOL fRead, LPCTSTR pSection, HWND hDlg, LPPAGECTRL aCtrl, INT iCtrls)
{
HRESULT hres = S_OK;
TCHAR szBuffer[MAX_PATH];
INT i;
USES_CONVERSION;
TraceEnter(TRACE_IO, "PersistQuery");
if ( !pPersistQuery || !hDlg || (!aCtrl && iCtrls) )
ExitGracefully(hres, E_INVALIDARG, "No data to persist");
for ( i = 0 ; i < iCtrls ; i++ )
{
if ( fRead )
{
if ( SUCCEEDED(pPersistQuery->ReadString(pSection, W2T(aCtrl[i].pPropertyName), szBuffer, ARRAYSIZE(szBuffer))) )
{
Trace(TEXT("Reading property: %s,%s as %s"), pSection, W2T(aCtrl[i].pPropertyName), szBuffer);
SetDlgItemText(hDlg, aCtrl[i].nIDDlgItem, szBuffer);
}
}
else
{
if ( GetDlgItemText(hDlg, aCtrl[i].nIDDlgItem, szBuffer, ARRAYSIZE(szBuffer)) )
{
Trace(TEXT("Writing property: %s,%s as %s"), pSection, W2T(aCtrl[i].pPropertyName), szBuffer);
hres = pPersistQuery->WriteString(pSection, W2T(aCtrl[i].pPropertyName), szBuffer);
FailGracefully(hres, "Failed to write control data");
}
}
}
hres = S_OK;
exit_gracefully:
TraceLeaveResult(hres);
}