STATUS.C
/*********************************************************************** 
 * 
 *  STATUS.C 
 * 
 * 
 *  The Sample Address Book Provider. 
 *  This file contains the methods that implement the status object. 
 * 
 *  The following routines are implemented in this file: 
 * 
 *      HrNewStatusObject() 
 *      ABS_QueryInterface() 
 *      ABS_Release() 
 *      ABS_ValidateState() 
 *      ABS_SettingsDialog() 
 *      ABS_ChangePassword() 
 *      ABS_FlushQueues() 
 * 
 *  Copyright 1992-1995 Microsoft Corporation.  All Rights Reserved. 
 * 
 ***********************************************************************/ 
 
 
#include "abp.h" 
#include "sampabp.rh" 
 
 
/* 
 *  Declaration of IMAPIStatus object implementation 
 */ 
#undef  INTERFACE 
#define INTERFACE   struct _ABSTATUS 
 
#undef  MAPIMETHOD_ 
#define MAPIMETHOD_(type, method)   MAPIMETHOD_DECLARE(type, method, ABS_) 
        MAPI_IUNKNOWN_METHODS(IMPL) 
        MAPI_IMAPIPROP_METHODS(IMPL) 
        MAPI_IMAPISTATUS_METHODS(IMPL) 
#undef  MAPIMETHOD_ 
#define MAPIMETHOD_(type, method)   MAPIMETHOD_TYPEDEF(type, method, ABS_) 
        MAPI_IUNKNOWN_METHODS(IMPL) 
        MAPI_IMAPIPROP_METHODS(IMPL) 
        MAPI_IMAPISTATUS_METHODS(IMPL) 
#undef  MAPIMETHOD_ 
#define MAPIMETHOD_(type, method)   STDMETHOD_(type, method) 
 
DECLARE_MAPI_INTERFACE(ABS_) 
{ 
    MAPI_IUNKNOWN_METHODS(IMPL) 
    MAPI_IMAPIPROP_METHODS(IMPL) 
    MAPI_IMAPISTATUS_METHODS(IMPL) 
}; 
 
 
/* 
 *  The actual definition of the structure behind the 'this' pointer for this object 
 */ 
typedef struct _ABSTATUS 
{ 
    const ABS_Vtbl FAR * lpVtbl; 
 
    SAB_Wrapped; 
     
} ABSTATUS, *LPABSTATUS; 
 
 
/* 
 *  AB Status vtbl filled in here 
 */ 
 
static const ABS_Vtbl vtblABS = 
{ 
 
    ABS_QueryInterface, 
    (ABS_AddRef_METHOD *)           ROOT_AddRef, 
    ABS_Release, 
    (ABS_GetLastError_METHOD *)     ROOT_GetLastError, 
    (ABS_SaveChanges_METHOD *)      WRAP_SaveChanges, 
    (ABS_GetProps_METHOD *)         WRAP_GetProps, 
    (ABS_GetPropList_METHOD *)      WRAP_GetPropList, 
    (ABS_OpenProperty_METHOD *)     WRAP_OpenProperty, 
    (ABS_SetProps_METHOD *)         WRAP_SetProps, 
    (ABS_DeleteProps_METHOD *)      WRAP_DeleteProps, 
    (ABS_CopyTo_METHOD *)           WRAP_CopyTo, 
    (ABS_CopyProps_METHOD *)        WRAP_CopyProps, 
    (ABS_GetNamesFromIDs_METHOD *)  WRAP_GetNamesFromIDs, 
    (ABS_GetIDsFromNames_METHOD *)  WRAP_GetIDsFromNames, 
    ABS_ValidateState, 
    ABS_SettingsDialog, 
    ABS_ChangePassword, 
    ABS_FlushQueues 
}; 
 
/************************************************************************* 
 * 
 -  HrNewStatusObject 
 - 
 *  Creates the Status object associated with a particular SAB logon object 
 * 
 * 
 */ 
HRESULT 
HrNewStatusObject(LPMAPISTATUS *    lppABS, 
                ULONG *             lpulObjType, 
                ULONG               ulFlags, 
                LPABLOGON           lpABLogon, 
                LPCIID              lpIID, 
                HINSTANCE           hLibrary, 
                LPALLOCATEBUFFER    lpAllocBuff, 
                LPALLOCATEMORE      lpAllocMore, 
                LPFREEBUFFER        lpFreeBuff, 
                LPMALLOC            lpMalloc ) 
{ 
    LPABSTATUS lpABS = NULL; 
    SCODE sc; 
    HRESULT hr = hrSuccess; 
    LPPROPDATA lpPropData = NULL; 
    SPropValue spv[6]; 
    LPSTR lpszFileName; 
 
 
    /* 
     * 
     */ 
    if (lpIID && 
        (memcmp(lpIID, &IID_IMAPIStatus, sizeof(IID)) && 
         memcmp(lpIID, &IID_IMAPIProp, sizeof(IID)) && 
         memcmp(lpIID, &IID_IUnknown, sizeof(IID)))) 
    { 
        DebugTraceSc(HrNewStatusObject, E_NOINTERFACE); 
        return ResultFromScode(E_NOINTERFACE); 
    } 
 
    /* 
     *  Allocate space for the ABSTATUS structure 
     */ 
    sc = lpAllocBuff( sizeof(ABSTATUS), (LPVOID *) &lpABS ); 
 
    if (FAILED(sc)) 
    { 
        hr = ResultFromScode(sc); 
        goto err; 
    } 
 
    lpABS->lpVtbl = &vtblABS; 
    lpABS->lcInit = 1; 
    lpABS->hResult = hrSuccess; 
    lpABS->idsLastError = 0; 
 
    lpABS->hLibrary = hLibrary; 
    lpABS->lpAllocBuff = lpAllocBuff; 
    lpABS->lpAllocMore = lpAllocMore; 
    lpABS->lpFreeBuff = lpFreeBuff; 
    lpABS->lpMalloc = lpMalloc; 
 
    lpABS->lpABLogon = lpABLogon; 
 
    /* 
     *  Create lpPropData 
     */ 
 
    sc = CreateIProp((LPIID) &IID_IMAPIPropData, 
        lpAllocBuff, 
        lpAllocMore, 
        lpFreeBuff, 
        lpMalloc, 
        &lpPropData); 
 
    if (FAILED(sc)) 
    { 
        hr = ResultFromScode(sc); 
        goto err; 
    } 
 
    /* 
     *  Set up initial set of properties associated with this 
     *  status object. 
     */ 
 
    /* 
     *  Register my status row... 
     */ 
    hr = HrLpszGetCurrentFileName(lpABLogon, &lpszFileName); 
    if (HR_FAILED(hr)) 
    { 
        goto err; 
    } 
     
    spv[0].ulPropTag = PR_DISPLAY_NAME_A; 
    spv[0].Value.lpszA = lpszFileName; 
 
    spv[1].ulPropTag = PR_RESOURCE_METHODS; 
    spv[1].Value.l = 0; 
 
    spv[2].ulPropTag = PR_RESOURCE_FLAGS; 
    spv[2].Value.l = 0; 
 
    spv[3].ulPropTag = PR_STATUS_CODE; 
    spv[3].Value.l = STATUS_AVAILABLE; 
 
    spv[4].ulPropTag = PR_STATUS_STRING_A; 
    spv[4].Value.lpszA = "Available"; 
 
    spv[5].ulPropTag = PR_PROVIDER_DISPLAY_A; 
    spv[5].Value.lpszA = "Sample Address Book Provider"; 
 
    /* 
     *   Set the default properties 
     */ 
    hr = lpPropData->lpVtbl->SetProps(lpPropData, 
        6, 
        spv, 
        NULL); 
 
    /* 
     *  Done with the current file name 
     */ 
    lpFreeBuff(lpszFileName); 
 
    if (HR_FAILED(hr)) 
    { 
        goto err; 
    } 
 
    /* 
     *  The whole object is set READONLY thus eliminating the need to 
     *  set access rights for the individual properties. 
     */ 
    (void) lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READONLY); 
 
    lpABS->lpPropData = (LPMAPIPROP) lpPropData; 
 
    InitializeCriticalSection(&lpABS->cs); 
 
    /*  We must AddRef the lpABLogon object since we will be using it 
     */ 
    lpABLogon->lpVtbl->AddRef(lpABLogon); 
 
    *lpulObjType = MAPI_STATUS; 
    *lppABS = (LPMAPISTATUS) lpABS; 
 
out: 
 
    DebugTraceResult(HrNewStatusObject, hr); 
    return hr; 
 
err: 
    if (lpPropData) 
        lpPropData->lpVtbl->Release(lpPropData); 
 
    lpFreeBuff( lpABS ); 
 
    goto out; 
 
} 
 
/************************************************************************* 
 * 
 * 
 -  ABS_QueryInterface 
 - 
 *  This method would allow this object to return a different interface than 
 *  the current one.  This object need only support IMAPIStatus and any interface 
 *  it derives from. 
 * 
 */ 
STDMETHODIMP 
ABS_QueryInterface(LPABSTATUS lpABS, 
    REFIID lpiid, LPVOID FAR * lppNewObj) 
{ 
 
    HRESULT hr = hrSuccess; 
    /* 
     *  Check to see if lpABS is what we expect 
     */ 
    if (IsBadReadPtr(lpABS, sizeof(ABSTATUS)) 
        || lpABS->lpVtbl != &vtblABS ) 
    { 
        hr = ResultFromScode(E_INVALIDARG); 
        goto out; 
    } 
 
    Validate_IUnknown_QueryInterface(lpABS, lpiid, lppNewObj); 
 
 
    /*  See if the requested interface is one of ours */ 
 
    if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) && 
        memcmp(lpiid, &IID_IMAPIProp, sizeof(IID)) && 
        memcmp(lpiid, &IID_IMAPIStatus, sizeof(IID))) 
    { 
        *lppNewObj = NULL;      /* OLE requires zeroing [out] parameter */ 
        hr = ResultFromScode(E_NOINTERFACE); 
        goto out; 
    } 
 
    /*  We'll do this one. Bump the usage count and return a new pointer. */ 
 
    EnterCriticalSection(&lpABS->cs); 
     
    ++lpABS->lcInit; 
     
    LeaveCriticalSection(&lpABS->cs); 
 
    *lppNewObj = lpABS; 
 
out: 
 
    DebugTraceResult(ABS_QueryInterface, hr); 
    return hr; 
} 
 
/************************************************** 
 * 
 -  ABS_Release 
 - 
 *      Decrement lpInit. 
 *      When lcInit == 0, free up the lpABS structure 
 * 
 */ 
STDMETHODIMP_(ULONG) ABS_Release(LPABSTATUS lpABS) 
{ 
    LONG lcInit; 
 
    /* 
     *  Check to see if lpABS is what we expect 
     */ 
    if (IsBadReadPtr(lpABS, sizeof(ABSTATUS))) 
    { 
        /* 
         *  No jump table found 
         */ 
        return 1; 
    } 
 
    /* 
     *  Check to see that it's the correct jump table 
     */ 
    if (lpABS->lpVtbl != &vtblABS) 
    { 
        /* 
         *  Not my jump table 
         */ 
        return 1; 
    } 
 
    Validate_IUnknown_Release(lpABS); 
 
 
    EnterCriticalSection(&lpABS->cs); 
 
    lcInit = --lpABS->lcInit; 
 
    LeaveCriticalSection(&lpABS->cs); 
 
    if (lcInit == 0) 
    { 
 
        /* 
         *  Get rid of the lpPropData 
         */ 
 
        lpABS->lpPropData->lpVtbl->Release(lpABS->lpPropData); 
 
        /* 
         *  Delete the critical section 
         */ 
 
        DeleteCriticalSection(&lpABS->cs); 
 
        /*   
         *  Release our reference to the ABLogon object. 
         */ 
        if (lpABS->lpABLogon) 
        { 
            lpABS->lpABLogon->lpVtbl->Release(lpABS->lpABLogon); 
            lpABS->lpABLogon = NULL; 
        } 
 
        /* 
         *  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. 
         */ 
 
        lpABS->lpVtbl = NULL; 
 
        /* 
         *  Need to free the object 
         */ 
 
        lpABS->lpFreeBuff( lpABS ); 
        return 0; 
    } 
 
    return lcInit; 
 
} 
 
 
/********************************************************************** 
 * 
 -  ABS_ValidateState 
 - 
 *  Since I did not set any flags for the property PR_RESOURCE_METHODS 
 *  I don't have to support this method. 
 * 
 */ 
 
STDMETHODIMP 
ABS_ValidateState(LPABSTATUS lpABS, 
                  ULONG ulUIParam, 
                  ULONG ulFlags) 
{ 
    HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT); 
    /* 
     *  Check to see if lpABS is what we expect 
     */ 
    if (IsBadReadPtr(lpABS, sizeof(ABSTATUS)) 
        || lpABS->lpVtbl != &vtblABS ) 
    { 
        hr = ResultFromScode(E_INVALIDARG); 
        goto out; 
    } 
 
    Validate_IMAPIStatus_ValidateState(lpABS, ulUIParam, ulFlags); 
     
out: 
    DebugTraceResult(ABS_ValidateState, hr); 
    return hr; 
} 
 
 
/********************************************************************** 
 * 
 -  ABS_SettingsDialog 
 - 
 *  Since I did not set any flags for the property PR_RESOURCE_METHODS 
 *  I don't have to support this method. 
 * 
 */ 
STDMETHODIMP 
ABS_SettingsDialog( LPABSTATUS lpABS, 
                    ULONG ulUIParam, 
                    ULONG ulFlags) 
{ 
    HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT); 
    /* 
     *  Check to see if lpABS is what we expect 
     */ 
    if (IsBadReadPtr(lpABS, sizeof(ABSTATUS)) 
        || lpABS->lpVtbl != &vtblABS ) 
    { 
        hr = ResultFromScode(E_INVALIDARG); 
        goto out; 
    } 
 
    Validate_IMAPIStatus_SettingsDialog(lpABS, ulUIParam, ulFlags); 
     
out: 
    DebugTraceResult(ABS_SettingsDialog, hr); 
    return hr; 
} 
 
 
/********************************************************************** 
 * 
 -  ABS_ChangePassword 
 - 
 *  Since I did not set any flags for the property PR_RESOURCE_METHODS 
 *  I don't have to support this method. 
 * 
 *  Note:   in the parameter validation below I chose only check the first 15 
 *          characters of the passwords.  This was arbitrary. 
 */ 
STDMETHODIMP 
ABS_ChangePassword(LPABSTATUS lpABS, 
    LPTSTR lpOldPass, 
    LPTSTR lpNewPass, 
    ULONG ulFlags) 
{ 
    HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT); 
    /* 
     *  Check to see if lpABS is what we expect 
     */ 
    if (IsBadReadPtr(lpABS, sizeof(ABSTATUS)) 
        || lpABS->lpVtbl != &vtblABS ) 
    { 
        hr = ResultFromScode(E_INVALIDARG); 
        goto out; 
    } 
 
    Validate_IMAPIStatus_ChangePassword(lpABS, lpOldPass, lpNewPass, ulFlags); 
     
    if ( ulFlags & MAPI_UNICODE ) 
    { 
        // UNICODE is currently not supported by the sample AB 
         
        hr = ResultFromScode( MAPI_E_BAD_CHARWIDTH ); 
        goto out; 
    } 
     
         
 
out: 
    DebugTraceResult(ABS_ChangePassword, hr); 
    return hr; 
} 
 
 
/********************************************************************** 
 * 
 -  ABS_FlushQueues 
 - 
 *  Since I did not set any flags for the property PR_RESOURCE_METHODS 
 *  I don't have to support this method. 
 * 
 */ 
STDMETHODIMP 
ABS_FlushQueues(LPABSTATUS lpABS, 
    ULONG ulUIParam, 
    ULONG cbTargetTransport, 
    LPENTRYID lpTargetTransport, 
    ULONG ulFlags) 
{ 
    HRESULT hr = ResultFromScode(MAPI_E_NO_SUPPORT); 
    /* 
     *  Check to see if lpABS is what we expect 
     */ 
    if (IsBadReadPtr(lpABS, sizeof(ABSTATUS)) || lpABS->lpVtbl != &vtblABS ) 
    { 
        hr = ResultFromScode(E_INVALIDARG); 
        goto out; 
    } 
 
    Validate_IMAPIStatus_FlushQueues(lpABS, ulUIParam, cbTargetTransport, 
                                    lpTargetTransport, ulFlags); 
 
 
out: 
    DebugTraceResult(ABS_FlushQueues, hr); 
    return hr; 
}