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;
}