ABSEARCH.C
/*********************************************************************** 
 * 
 *  ABSEARCH.C 
 * 
 *  Sample AB directory container Search object 
 * 
 *  This file contains the code for implementing the Sample AB 
 *  directory container search object.  Also known as advanced 
 *  search. 
 * 
 *  This search object was retrieved by OpenProperty on PR_SEARCH on the 
 *  AB directory found in ABCONT.C. 
 * 
 *  The following routines are implemented in this file: 
 * 
 *      HrNewSearch 
 *      ABSRCH_Release 
 *      ABSRCH_SaveChanges 
 *      ABSRCH_OpenProperty 
 *      ABSRCH_GetSearchCriteria 
 * 
 *      HrGetSearchDialog 
 * 
 *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved. 
 * 
 ***********************************************************************/ 
 
#include "abp.h" 
#include "sampabp.rh" 
#include <smpab.h> 
 
 
/* 
 *  Proptags used only in this module 
 */ 
#define PR_ANR_STRING               PROP_TAG(PT_STRING8,0x6602) 
 
 
/* 
 *  Structure for the 'this' 
 */ 
 
typedef struct _ABSRCH 
{ 
    const ABSRCH_Vtbl FAR * lpVtbl; 
 
    SAB_Wrapped; 
 
    /*  Private data */ 
 
    LPSPropValue lpRestrictData; 
     
} ABSRCH, *LPABSRCH; 
 
 
 
/* Display table control structures for the Search property sheet. */ 
 
/* 
 *  The Sample AB exposes an 'advanced' search dialog.  The following 
 *  structures define it's layout. 
 */ 
 
/* 
 *  The edit control that will have the name to be search for on it. 
 */ 
#define MAX_SEARCH_NAME                 50 
 
DTBLEDIT editSearchName = 
{ 
    sizeof(DTBLEDIT), 
    0, 
    MAX_SEARCH_NAME, 
    PR_ANR_STRING 
}; 
 
/* 
 *  Display table pages for Search property sheet 
 */ 
DTCTL rgdtctlSearchGeneral[] = 
{ 
 
    /* 
     *  Defines the name of this Pane. 
     */ 
    {DTCT_PAGE, 0, NULL, 0, NULL, 0, &dtblpage}, 
 
    /* group box control */ 
    {DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, 
        &dtblgroupbox}, 
 
    /* control and edit control */ 
    {DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC_CONTROL, 
        &dtbllabel}, 
    {DTCT_EDIT, DT_EDITABLE, NULL, 0, szNoFilter, IDC_SEARCH_NAME, 
        &editSearchName}, 
}; 
 
/* 
 *  Actual definition of the set of pages that make up this advanced search 
 *  dialog.  Note that there's no limit to the number of pages that can be 
 *  displayed.  This sample AB, however, only exposes on page. 
 */ 
DTPAGE rgdtpageSearch[] = 
{ 
    { 
        sizeof(rgdtctlSearchGeneral) / sizeof(DTCTL), 
        (LPTSTR) MAKEINTRESOURCE(SearchGeneralPage), 
        "", 
        rgdtctlSearchGeneral 
    } 
}; 
 
/* 
 *  ABSearch vtbl is filled in here. 
 */ 
ABSRCH_Vtbl vtblABSRCH = 
{ 
    (ABSRCH_QueryInterface_METHOD *)        ROOT_QueryInterface, 
    (ABSRCH_AddRef_METHOD *)                ROOT_AddRef,     
    ABSRCH_Release, 
    (ABSRCH_GetLastError_METHOD *)          ROOT_GetLastError, 
    ABSRCH_SaveChanges, 
    (ABSRCH_GetProps_METHOD *)              WRAP_GetProps, 
    (ABSRCH_GetPropList_METHOD *)           WRAP_GetPropList, 
    ABSRCH_OpenProperty, 
    (ABSRCH_SetProps_METHOD *)              WRAP_SetProps, 
    (ABSRCH_DeleteProps_METHOD *)           WRAP_DeleteProps, 
    (ABSRCH_CopyTo_METHOD *)                WRAP_CopyTo, 
    (ABSRCH_CopyProps_METHOD *)             WRAP_CopyProps, 
    (ABSRCH_GetNamesFromIDs_METHOD *)       WRAP_GetNamesFromIDs, 
    (ABSRCH_GetIDsFromNames_METHOD *)       WRAP_GetIDsFromNames, 
    (ABSRCH_GetContentsTable_METHOD *)      ROOT_GetContentsTable, 
    (ABSRCH_GetHierarchyTable_METHOD *)     ABC_GetHierarchyTable, 
    (ABSRCH_OpenEntry_METHOD *)             ROOT_OpenEntry, 
    (ABSRCH_SetSearchCriteria_METHOD *)     ROOT_SetSearchCriteria, 
    ABSRCH_GetSearchCriteria, 
}; 
 
 
 
HRESULT HrGetSearchDialog(LPABSRCH lpABSearch, LPMAPITABLE * lppSearchTable); 
 
/* 
 -  HrNewSearch 
 - 
 *  Creates an advanced search object 
 * 
 * 
 */ 
 
 
/* 
 *  Properties that are initially set on this object 
 */ 
enum {  ivalabsrchPR_ANR_STRING = 0, 
        cvalabsrchMax }; 
 
HRESULT 
HrNewSearch(LPMAPICONTAINER *   lppABSearch, 
            LPABLOGON           lpABLogon, 
            LPCIID              lpInterface, 
            HINSTANCE           hLibrary, 
            LPALLOCATEBUFFER    lpAllocBuff, 
            LPALLOCATEMORE      lpAllocMore, 
            LPFREEBUFFER        lpFreeBuff, 
            LPMALLOC            lpMalloc ) 
{ 
    HRESULT hResult = hrSuccess; 
    LPABSRCH lpABSearch = NULL; 
    SCODE sc; 
    LPPROPDATA lpPropData = NULL; 
    SPropValue spv[cvalabsrchMax]; 
     
    /*  Do I support this interface?? */ 
    if (lpInterface) 
    { 
        if (memcmp(lpInterface, &IID_IMAPIContainer, sizeof(IID)) && 
            memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID)) && 
            memcmp(lpInterface, &IID_IUnknown, sizeof(IID))) 
        { 
            DebugTraceSc(HrNewSearch, MAPI_E_INTERFACE_NOT_SUPPORTED); 
            return ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED); 
        } 
    } 
 
    /* 
     *  Allocate space for the directory container structure 
     */ 
 
    sc = lpAllocBuff( sizeof(ABSRCH), (LPVOID *) &lpABSearch ); 
 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto err; 
    } 
 
    lpABSearch->lpVtbl = &vtblABSRCH; 
    lpABSearch->lcInit = 1; 
    lpABSearch->hResult = hrSuccess; 
    lpABSearch->idsLastError = 0; 
 
    lpABSearch->hLibrary = hLibrary; 
    lpABSearch->lpAllocBuff = lpAllocBuff; 
    lpABSearch->lpAllocMore = lpAllocMore; 
    lpABSearch->lpFreeBuff = lpFreeBuff; 
    lpABSearch->lpMalloc = lpMalloc; 
 
    lpABSearch->lpABLogon = lpABLogon; 
    lpABSearch->lpRestrictData = NULL; 
 
    /* 
     *  Create property storage object 
     */ 
 
    sc = CreateIProp((LPIID) &IID_IMAPIPropData, 
        lpAllocBuff, 
        lpAllocMore, 
        lpFreeBuff, 
        lpMalloc, 
        &lpPropData); 
 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto err; 
    } 
 
    spv[ivalabsrchPR_ANR_STRING].ulPropTag = PR_ANR_STRING; 
    spv[ivalabsrchPR_ANR_STRING].Value.lpszA = ""; 
 
    /* 
     *   Set the default properties 
     */ 
    hResult = lpPropData->lpVtbl->SetProps(lpPropData, 
        cvalabsrchMax, 
        spv, 
        NULL); 
 
    InitializeCriticalSection(&lpABSearch->cs); 
 
    /*  We must AddRef the lpABLogon object since we will be using it 
     */ 
    lpABLogon->lpVtbl->AddRef(lpABLogon); 
 
    lpABSearch->lpPropData = (LPMAPIPROP) lpPropData; 
    *lppABSearch = (LPMAPICONTAINER) lpABSearch; 
 
out: 
 
    DebugTraceResult(HrNewSearch, hResult); 
    return hResult; 
 
err: 
    /* 
     *  free the ABContainer object 
     */ 
    lpFreeBuff( lpABSearch ); 
 
    /* 
     *  free the property storage object 
     */ 
    if (lpPropData) 
        lpPropData->lpVtbl->Release(lpPropData); 
 
    goto out; 
} 
 
 
/* 
 -  ABSRCH_Release 
 - 
 *  Decrement lcInit. 
 *      When lcInit == 0, free up the lpABSearch structure 
 * 
 */ 
 
STDMETHODIMP_(ULONG) 
ABSRCH_Release(LPABSRCH lpABSearch) 
{ 
 
    long lcInit; 
     
    /* 
     *  Check to see if it has a jump table 
     */ 
    if (IsBadReadPtr(lpABSearch, sizeof(ABSRCH))) 
    { 
        /* 
         *  No jump table found 
         */ 
        return 1; 
    } 
 
    /* 
     *  Check to see that it's the correct jump table 
     */ 
    if (lpABSearch->lpVtbl != &vtblABSRCH) 
    { 
        /* 
         *  Not my jump table 
         */ 
        return 1; 
    } 
 
    Validate_IUnknown_Release(lpABSearch); 
 
 
    EnterCriticalSection(&lpABSearch->cs); 
    lcInit = --lpABSearch->lcInit; 
    LeaveCriticalSection(&lpABSearch->cs); 
 
    if (lcInit == 0) 
    { 
 
        /* 
         *  Get rid of the lpPropData 
         */ 
        if (lpABSearch->lpPropData) 
            lpABSearch->lpPropData->lpVtbl->Release(lpABSearch->lpPropData); 
 
        /* 
         *  Free up the restriction data 
         */ 
        lpABSearch->lpFreeBuff(lpABSearch->lpRestrictData); 
 
        /*   
         *  Release our reference to the ABLogon object. 
         */ 
        if (lpABSearch->lpABLogon) 
        { 
            lpABSearch->lpABLogon->lpVtbl->Release(lpABSearch->lpABLogon); 
            lpABSearch->lpABLogon = NULL; 
        } 
 
        /* 
         *  Destroy the critical section for this object 
         */ 
 
        DeleteCriticalSection(&lpABSearch->cs); 
 
        /* 
         *  Set the Jump table to NULL.  This way the client will find out 
         *  real fast if it's calling a method on a released object.  That is, 
         *  the client will crash.  Hopefully, this will happen during the 
         *  development stage of the client. 
         */ 
        lpABSearch->lpVtbl = NULL; 
 
        /* 
         *  Need to free the object 
         */ 
 
        lpABSearch->lpFreeBuff(lpABSearch); 
        return 0; 
    } 
 
    return lpABSearch->lcInit; 
 
} 
 
 
/* 
 -  ABSRCH_SaveChanges 
 - 
 *  This is used to save changes associated with the search dialog 
 *  in order to get the advanced search restriction and to save changes 
 *  associated with the container details dialog. 
 * 
 */ 
SPropTagArray tagaANR_INT = 
{ 
    1, 
    { 
        PR_ANR_STRING 
    } 
}; 
 
STDMETHODIMP 
ABSRCH_SaveChanges(LPABSRCH lpABSearch, ULONG ulFlags) 
{ 
    HRESULT hResult; 
    ULONG ulCount; 
    LPSPropValue lpspv = NULL; 
    LPPROPDATA lpPropData = (LPPROPDATA) lpABSearch->lpPropData; 
 
     
    ABSRCH_ValidateObject(SaveChanges, lpABSearch); 
     
    Validate_IMAPIProp_SaveChanges(lpABSearch, ulFlags); 
 
 
    EnterCriticalSection(&lpABSearch->cs); 
 
    /* 
     *  Is there a PR_ANR_STRING?? 
     */ 
    hResult = lpPropData->lpVtbl->GetProps(lpPropData, 
        &tagaANR_INT, 
        0,      /* ansi */ 
        &ulCount, 
        &lpspv); 
    if (HR_FAILED(hResult)) 
    { 
        goto ret; 
    } 
 
    if ((lpspv->ulPropTag == PR_ANR_STRING) && (lpspv->Value.lpszA[0] != '\0')) 
    { 
        /* 
         * save away the information to build up the new restriction 
         */ 
 
        /*  Free any existing data */ 
        if (lpABSearch->lpRestrictData) 
        { 
            lpABSearch->lpFreeBuff(lpABSearch->lpRestrictData); 
        } 
 
        lpABSearch->lpRestrictData = lpspv; 
        lpspv = NULL; 
    } 
 
ret: 
 
    LeaveCriticalSection(&lpABSearch->cs); 
 
    lpABSearch->lpFreeBuff(lpspv); 
    DebugTraceResult(ABSRCH_SaveChanges, hResult); 
    return hResult; 
} 
 
/************************************************************************* 
 * 
 -  ABSRCH_OpenProperty 
 - 
 * 
 *  This method allows the opening of the following object: 
 * 
 *  PR_DETAILS_TABLE        :-  Gets the display table associated with 
 *                              the advanced search dialog. 
 */ 
STDMETHODIMP 
ABSRCH_OpenProperty(LPABSRCH lpABSearch, 
    ULONG ulPropTag, 
    LPCIID lpiid, 
    ULONG ulInterfaceOptions, 
    ULONG ulFlags, 
    LPUNKNOWN * lppUnk) 
{ 
    HRESULT hResult; 
 
    ABSRCH_ValidateObject(OpenProperty, lpABSearch); 
     
    Validate_IMAPIProp_OpenProperty(lpABSearch, ulPropTag, lpiid, 
                            ulInterfaceOptions, ulFlags, lppUnk); 
 
    /* 
     *  Check for flags we can't support 
     */ 
 
    if (ulFlags & (MAPI_CREATE|MAPI_MODIFY)) 
    { 
        hResult = ResultFromScode(E_ACCESSDENIED); 
        goto out; 
    } 
         
    if (ulInterfaceOptions & ~MAPI_UNICODE) 
    { 
        /* 
         *  Only UNICODE flag should be set for any of the objects that might 
         *  be returned from this object. 
         */ 
         
        hResult = ResultFromScode(MAPI_E_UNKNOWN_FLAGS); 
        goto out; 
    } 
     
    if ( ulInterfaceOptions & MAPI_UNICODE ) 
    { 
        hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH); 
        DebugTraceArg( ABSRCH_OpenProperty, "bad character width" ); 
        goto out; 
         
    } 
 
 
    /* 
     *  Details for this Search object 
     */ 
 
    if (ulPropTag == PR_DETAILS_TABLE) 
    { 
        if (!memcmp(lpiid, &IID_IMAPITable, sizeof(IID))) 
        { 
            hResult = HrGetSearchDialog(lpABSearch, (LPMAPITABLE *) lppUnk); 
 
            goto out; 
        } 
 
    }  
 
    hResult = ResultFromScode(MAPI_E_NO_SUPPORT); 
 
out: 
 
    DebugTraceResult(ABSRCH_OpenProperty, hResult); 
    return hResult; 
 
 
} 
 
/* 
 -  ABSRCH_GetSearchCriteria 
 - 
 *  Generates the restriction associated with the data from 
 *  the advanced search dialog.  This restriction is subsequently 
 *  applied to the contents table retrieved from this container. 
 */ 
STDMETHODIMP 
ABSRCH_GetSearchCriteria(   LPABSRCH lpABSearch, 
                        ULONG   ulFlags, 
                        LPSRestriction FAR * lppRestriction, 
                        LPENTRYLIST FAR * lppContainerList, 
                        ULONG FAR * lpulSearchState) 
{ 
    HRESULT hResult = hrSuccess; 
    SCODE sc; 
    LPSRestriction lpRestriction = NULL; 
    LPSPropValue lpPropANR = NULL; 
    LPSTR lpszPartName; 
    LPSTR lpszRestrName; 
 
    ABSRCH_ValidateObject(GetSearchCriteria, lpABSearch); 
     
    Validate_IMAPIContainer_GetSearchCriteria(lpABSearch, ulFlags, 
                                lppRestriction, lppContainerList,  
                                lpulSearchState); 
 
    if (!lpABSearch->lpRestrictData) 
    { 
        hResult = ResultFromScode(MAPI_E_NOT_INITIALIZED); 
 
        if (lppRestriction) 
            *lppRestriction = NULL; 
 
        if (lppContainerList) 
            *lppContainerList = NULL; 
 
        if (lpulSearchState) 
            *lpulSearchState = 0L; 
 
        DebugTraceResult(ABSRCH_GetSearchCriteria, hResult); 
        return hResult; 
    } 
 
    if (ulFlags & MAPI_UNICODE) 
    { 
        hResult = ResultFromScode(MAPI_E_BAD_CHARWIDTH); 
         
        DebugTraceResult(ABSRCH_GetSearchCriteria, hResult); 
        return hResult; 
    } 
 
 
    /* 
     *  Entering state dependant section 
     */ 
    EnterCriticalSection(&lpABSearch->cs); 
 
    /* 
     *  Ok, now build up a restriction using lpRestrictData (an LPSPropValue) 
     */ 
 
    sc = lpABSearch->lpAllocBuff(sizeof(SRestriction), &lpRestriction); 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto err; 
    } 
 
    sc = lpABSearch->lpAllocMore(sizeof(SPropValue), lpRestriction, &lpPropANR); 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto err; 
 
    } 
 
    lpszRestrName = lpABSearch->lpRestrictData->Value.lpszA; 
 
    sc = lpABSearch->lpAllocMore(lstrlenA(lpszRestrName)+1, 
        lpRestriction, 
        &lpszPartName); 
    if (FAILED(sc)) 
    { 
        hResult = ResultFromScode(sc); 
        goto err; 
    } 
 
    lstrcpyA(lpszPartName, lpszRestrName); 
 
    lpPropANR->ulPropTag = PR_ANR; 
    lpPropANR->Value.LPSZ = lpszPartName; 
 
    lpRestriction->rt = RES_PROPERTY; 
    lpRestriction->res.resProperty.relop = RELOP_EQ; 
    lpRestriction->res.resProperty.ulPropTag = PR_ANR; 
    lpRestriction->res.resProperty.lpProp = lpPropANR; 
 
    *lppRestriction = lpRestriction; 
 
    /* 
     *  The returned SearchState is set to 0 because none 
     *  of the defined states match what's going on. 
     */ 
    if (lpulSearchState) 
        *lpulSearchState = 0; 
 
out: 
    LeaveCriticalSection(&lpABSearch->cs); 
 
    DebugTraceResult(ABSRCH_GetSearchCriteria, hResult); 
    return hResult; 
 
err: 
    lpABSearch->lpFreeBuff(lpRestriction); 
 
    goto out; 
} 
 
/* 
 -  HrGetSearchDialog 
 - 
 * 
 *  Builds a display table for the search dialog. 
 */ 
 
HRESULT 
HrGetSearchDialog(LPABSRCH lpABSearch, LPMAPITABLE * lppSearchTable) 
{ 
    HRESULT hResult; 
 
    /* Create a display table */ 
    hResult = BuildDisplayTable( 
            lpABSearch->lpAllocBuff, 
            lpABSearch->lpAllocMore, 
            lpABSearch->lpFreeBuff, 
            lpABSearch->lpMalloc, 
            lpABSearch->hLibrary, 
            sizeof(rgdtpageSearch) / sizeof(DTPAGE), 
            rgdtpageSearch, 
            0, 
            lppSearchTable, 
            NULL); 
 
    DebugTraceResult(ABSRCH_GetSearchDialog, hResult); 
    return hResult; 
}