Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1092 lines
27 KiB

/*
* U N K O B J . C
*
* This is a generic implementation of the IUnknown plus GetLastError)
* "IMAPIUnknown" part of objects that are derived from IUnknown with
* GetLastError.
*
* This also implements several useful utility functions based on
* IMAPIUnknown.
*
* To use this, you must implement your own init function.
*
* Used in:
* IPROP
* ITABLE
*
*/
#include "_apipch.h"
/*
* Per-instance global data for the UNKOBJ Class
*/
typedef struct
{
int cRef; // reference count for instance data
HLH hlh; // Single heap used by UNKOBJ_ScCOxxx
// allocators for all Unkobj's
CRITICAL_SECTION cs; // critical section for data access
} UNKOBJCLASSINST, FAR *LPUNKOBJCLASSINST;
#if defined (WIN32) && !defined (MAC)
CRITICAL_SECTION csUnkobjInit;
extern BOOL fGlobalCSValid;
#endif
// $MAC - Use Mac specific instance global handlers
#ifndef MAC
DefineInstList(UNKOBJ);
#undef PvGetInstanceGlobals
#define PvGetInstanceGlobals() PvGetInstanceGlobalsEx(UNKOBJ)
#undef ScSetInstanceGlobals
#define ScSetInstanceGlobals(pinst) ScSetInstanceGlobalsEx(pinst, UNKOBJ)
#else // MAC
#include <utilmac.h>
#define PvGetInstanceGlobals() PvGetInstanceGlobalsMac(kInstMAPIU)
#define PvGetInstanceGlobalsEx(_x) PvGetInstanceGlobalsMac(kInstMAPIU)
#define ScSetInstanceGlobals(a) ScSetInstanceGlobalsMac(a, kInstMAPIU)
#define ScSetInstanceGlobalsEx(_pinst, _x) ScSetInstanceGlobalsMac(_pinst, kInstMAPIU)
#endif // MAC
// #pragma SEGMENT(Common)
/*============================================================================
* UNKOBJ (IMAPIUnknown) Class
*
* Routines for handling per-process global data for the UNKOBJ Class
*
*/
/*============================================================================
*
* Initializes per-process global data for the UNKOBJ Class
*
*/
IF_WIN32(__inline) SCODE
ScGetUnkClassInst(LPUNKOBJCLASSINST FAR *ppinst)
{
SCODE sc = S_OK;
LPUNKOBJCLASSINST pinst = NULL;
#if defined (WIN32) && !defined (MAC)
if (fGlobalCSValid)
EnterCriticalSection(&csUnkobjInit);
#endif
pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
if (pinst)
{
EnterCriticalSection(&pinst->cs);
pinst->cRef++;
LeaveCriticalSection(&pinst->cs);
goto ret;
}
if (!(pinst = (LPUNKOBJCLASSINST) GlobalAllocPtr(GPTR, sizeof(UNKOBJCLASSINST))))
{
sc = MAPI_E_NOT_ENOUGH_MEMORY;
goto ret;
}
// Initialize the instance structure
// DebugTrace( TEXT("Creating UnkObj Inst: %8x"), pinst);
InitializeCriticalSection(&pinst->cs);
pinst->cRef = 1;
// (the heap will be created when the first allocation is done) ....
pinst->hlh = NULL;
#ifdef NEVER
// Create a Heap for the UNKOBJ Class that will be used by
// all unkobjs in this process.
//$ NOTE: The heap creation can be removed from here and the
//$ code to fault the heap in in UNKOBJ_ScCO(Re)Allocate()
//$ enabled instead - that would *require* users of CreateIProp,
//$ CreateITable etc not to do LH_SetHeapName().
pinst->hlh = LH_Open(0);
if (!pinst->hlh)
{
DebugTrace( TEXT("ScGetUnkClassInst():: Can't create Local Heap\n"));
sc = MAPI_E_NOT_ENOUGH_MEMORY;
goto ret;
}
#endif
// ... and install the instance globals.
if (FAILED(sc = ScSetInstanceGlobals(pinst)))
{
DebugTrace( TEXT("ScGetUnkClassInst():: Failed to install instance globals\n"));
goto ret;
}
ret:
if (FAILED(sc))
{
if (pinst)
{
DeleteCriticalSection(&pinst->cs);
if (pinst->hlh)
LH_Close(pinst->hlh);
GlobalFreePtr(pinst);
pinst = NULL;
}
}
*ppinst = pinst;
#if defined (WIN32) && !defined (MAC)
if (fGlobalCSValid)
LeaveCriticalSection(&csUnkobjInit);
#endif
DebugTraceSc(ScInitInstance, sc);
return sc;
}
/*============================================================================
*
* Cleans up per-process global data for the UNKOBJ Class
*
*/
IF_WIN32(__inline) void
ReleaseUnkClassInst()
{
LPUNKOBJCLASSINST pinst = NULL;
#if defined (WIN32) && !defined (MAC)
if (fGlobalCSValid)
EnterCriticalSection(&csUnkobjInit);
#endif
pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
if (!pinst)
goto out;
EnterCriticalSection(&pinst->cs);
if (--(pinst->cRef) > 0)
{
LeaveCriticalSection(&pinst->cs);
goto out;
}
// The last Unkobj for this process is going away, hence close
// our heap.
// DebugTrace( TEXT("Deleting UnkObj Inst: %8x"), pinst);
if (pinst->hlh)
{
// DebugTrace( TEXT("Destroying hlh (%8x) for Inst: %8x"), pinst->hlh, pinst);
LH_Close(pinst->hlh);
}
pinst->hlh = 0;
LeaveCriticalSection(&pinst->cs);
DeleteCriticalSection(&pinst->cs);
GlobalFreePtr(pinst);
(void)ScSetInstanceGlobals(NULL);
out:
#if defined (WIN32) && !defined (MAC)
if (fGlobalCSValid)
LeaveCriticalSection(&csUnkobjInit);
#endif
return;
}
/*============================================================================
* UNKOBJ (IMAPIUnknown) Class
*
* Object methods.
*/
/*============================================================================
- UNKOBJ::QueryInterface()
-
*/
STDMETHODIMP
UNKOBJ_QueryInterface (LPUNKOBJ lpunkobj,
REFIID riid,
LPVOID FAR * lppUnk)
{
LPIID FAR * lppiidSupported;
ULONG ulcIID;
SCODE sc;
#if !defined(NO_VALIDATION)
/* Validate the object.
*/
if (BAD_STANDARD_OBJ( lpunkobj, UNKOBJ_, QueryInterface, lpvtbl))
{
DebugTrace( TEXT("UNKOBJ::QueryInterface() - Bad object passed\n") );
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
Validate_IUnknown_QueryInterface(lpunkobj, riid, lppUnk);
#endif
for ( lppiidSupported = lpunkobj->rgpiidList, ulcIID = lpunkobj->ulcIID
; ulcIID
; lppiidSupported++, ulcIID--)
{
if (IsEqualGUID(riid, *lppiidSupported))
{
/* We support the interface so break out of the search loop.
*/
break;
}
}
/* Return error if the requested interface was not in our list of
* supported interfaces.
*/
if (!ulcIID)
{
*lppUnk = NULL; // OLE requires zeroing [out] parameters
sc = E_NOINTERFACE;
goto error;
}
/* We found the requested interface so increment the reference count.
*/
UNKOBJ_EnterCriticalSection(lpunkobj);
lpunkobj->ulcRef++;
UNKOBJ_LeaveCriticalSection(lpunkobj);
*lppUnk = lpunkobj;
return hrSuccess;
error:
UNKOBJ_EnterCriticalSection(lpunkobj);
UNKOBJ_SetLastError(lpunkobj, E_NOINTERFACE, 0);
UNKOBJ_LeaveCriticalSection(lpunkobj);
return ResultFromScode(sc);
}
/*============================================================================
- UNKOBJ::AddRef()
-
*/
STDMETHODIMP_(ULONG)
UNKOBJ_AddRef( LPUNKOBJ lpunkobj )
{
ULONG ulcRef;
#if !defined(NO_VALIDATION)
if (BAD_STANDARD_OBJ( lpunkobj, UNKOBJ_, AddRef, lpvtbl))
{
DebugTrace( TEXT("UNKOBJ::AddRef() - Bad object passed\n") );
return 42;
}
#endif
UNKOBJ_EnterCriticalSection(lpunkobj);
ulcRef = ++lpunkobj->ulcRef;
UNKOBJ_LeaveCriticalSection(lpunkobj);
return ulcRef;
}
/*============================================================================
- UNKOBJ::GetLastError()
-
* NOTE!
* An error in GetLastError will NOT cause the objects last error to be
* set again. This will allow the caller to retry the call.
*/
STDMETHODIMP
UNKOBJ_GetLastError( LPUNKOBJ lpunkobj,
HRESULT hrError,
ULONG ulFlags,
LPMAPIERROR FAR * lppMAPIError)
{
SCODE sc = S_OK;
HRESULT hrLastError;
IDS idsLastError;
LPTSTR lpszMessage = NULL;
LPMAPIERROR lpMAPIError = NULL;
#if !defined(NO_VALIDATION)
if (BAD_STANDARD_OBJ( lpunkobj, UNKOBJ_, GetLastError, lpvtbl))
{
DebugTrace( TEXT("UNKOBJ::GetLastError() - Bad object passed\n") );
return ResultFromScode(MAPI_E_INVALID_PARAMETER);
}
Validate_IMAPIProp_GetLastError(lpunkobj, hrError, ulFlags, lppMAPIError);
#endif
/* Verify flags.
*/
if (ulFlags & ~(MAPI_UNICODE))
{
return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
}
*lppMAPIError = NULL;
/* Get a snapshot of the last error.
*/
UNKOBJ_EnterCriticalSection(lpunkobj);
idsLastError = lpunkobj->idsLastError;
hrLastError = lpunkobj->hrLastError;
UNKOBJ_LeaveCriticalSection(lpunkobj);
/* If last error doesn't match parameter or there is no
* provider-context specific error string then just succeed.
*/
if ((hrError != hrLastError) || !idsLastError)
goto out;
/* Generate new lpMAPIError
*/
sc = UNKOBJ_ScAllocate(lpunkobj,
sizeof(MAPIERROR),
&lpMAPIError);
if (FAILED(sc))
{
DebugTrace( TEXT("UNKOBJ::GetLastError() - Unable to allocate memory\n"));
goto err;
}
FillMemory(lpMAPIError, sizeof(MAPIERROR), 0x00);
lpMAPIError->ulVersion = MAPI_ERROR_VERSION;
/* Load a copy of the error string.
*/
if ( FAILED(sc = UNKOBJ_ScSzFromIdsAllocMore(lpunkobj,
idsLastError,
ulFlags,
lpMAPIError,
cchLastError,
&lpszMessage)) )
{
DebugTrace( TEXT("UNKOBJ::GetLastError() - WARNING: Unable to load error string (SCODE = 0x%08lX). Returning hrSuccess.\n"), sc );
return ResultFromScode(sc);
}
lpMAPIError->lpszError = lpszMessage;
*lppMAPIError = lpMAPIError;
out:
DebugTraceSc(UNKOBJ_GetLastError, sc);
return ResultFromScode(sc);
err:
UNKOBJ_Free( lpunkobj, lpMAPIError );
goto out;
}
/*
* UNKOBJ utility functions.
*/
/*============================================================================
- UNKOBJ::ScAllocate()
-
* Utility function to allocate memory using MAPI linked memory.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* ulcb in Count of bytes to allocate.
* lplpv out MAPI-Allocated buffer.
*/
STDAPI_(SCODE)
UNKOBJ_ScAllocate( LPUNKOBJ lpunkobj,
ULONG ulcb,
LPVOID FAR * lplpv )
{
// parameter validation
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
TEXT("lplpv fails address check") );
return lpunkobj->pinst->lpfAllocateBuffer(ulcb, lplpv);
}
/*============================================================================
- UNKOBJ::ScAllocateMore()
-
* Utility function to allocate more memory using MAPI linked memory.
* If the link buffer is null, this function just does a MAPI allocate.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* ulcb in Count of bytes to allocate.
* lpv in Buffer to link to.
* lplpv out New buffer
*/
STDAPI_(SCODE)
UNKOBJ_ScAllocateMore( LPUNKOBJ lpunkobj,
ULONG ulcb,
LPVOID lpv,
LPVOID FAR * lplpv )
{
// validate parameters
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
TEXT("lplpv fails address check") );
return lpv ?
lpunkobj->pinst->lpfAllocateMore(ulcb, lpv, lplpv) :
lpunkobj->pinst->lpfAllocateBuffer(ulcb, lplpv) ;
}
/*============================================================================
- UNKOBJ::Free()
-
* Utility function to free MAPI linked memory. NULL buffers are ignored.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* lpv in Buffer to free.
*/
STDAPI_(VOID)
UNKOBJ_Free( LPUNKOBJ lpunkobj,
LPVOID lpv )
{
// parameter validation
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
if (lpv)
{
if (lpv == lpunkobj)
lpunkobj->lpvtbl = NULL;
(void) lpunkobj->pinst->lpfFreeBuffer(lpv);
}
}
/*============================================================================
- UNKOBJ::FreeRows()
-
* Frees a row set of the form returned from IMAPITable::QueryRows
* (i.e. where the row set and each individual *prop value array*
* in that row set are individually allocated with MAPI linked memory.)
* NULL row sets are ignored.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* lprows in Row set to free.
*/
STDAPI_(VOID)
UNKOBJ_FreeRows( LPUNKOBJ lpunkobj,
LPSRowSet lprows )
{
LPSRow lprow;
// validate parameters
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
AssertSz( !lprows || !FBadRowSet( lprows ), TEXT("lprows fails address check") );
if ( !lprows )
return;
/* Free each row in the set from last to first. UNKOBJ_Free
* handles NULL pointers.
*/
lprow = lprows->aRow + lprows->cRows;
while ( lprow-- > lprows->aRow )
UNKOBJ_Free((LPUNKOBJ) lpunkobj, lprow->lpProps);
UNKOBJ_Free(lpunkobj, lprows);
}
/*============================================================================
- UNKOBJ::ScCOAllocate()
-
* Utility function to allocate memory using CO memory allocators.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* ulcb in Count of bytes to allocate.
* lplpv out Pointer to allocated buffer.
*/
STDAPI_(SCODE)
UNKOBJ_ScCOAllocate( LPUNKOBJ lpunkobj,
ULONG ulcb,
LPVOID FAR * lplpv )
{
HLH lhHeap;
// validate parameters
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
TEXT("lplpv fails address check") );
/* If caller _really_ wants a 0 byte allocation, warn
* them and give them back a NULL pointer so that they
* can't dereference it, but should be able to free it.
*/
if ( ulcb == 0 )
{
DebugTrace( TEXT("LH_Alloc() - WARNING: Caller requested 0 bytes; returning NULL\n") );
*lplpv = NULL;
return S_OK;
}
lhHeap = lpunkobj->lhHeap;
// Enable following section when we fault in the Heap - requires changes
// throughout where CreateIProp/CreateITable calls are
// done followed by LH_SetHeapName(). The LH_SetHeapName
// calls have to be used since we may not have a heap
// at the time. Furthermore, there is only 1 heap, so
// they are unnecessary anyway.
#if 1
if (!lhHeap)
{
LPUNKOBJCLASSINST pinst;
// The UNKOBJ heap *probably* does not exist, make sure
// (to guard against a race) and create it if indeed so.
pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
Assert(pinst);
EnterCriticalSection(&pinst->cs);
if (!pinst->hlh)
{
lhHeap = LH_Open(0);
if (!lhHeap)
{
DebugTrace( TEXT("UNKOBJ_ScCOAllocate() - Can't create Local Heap"));
LeaveCriticalSection(&pinst->cs);
return MAPI_E_NOT_ENOUGH_MEMORY;
}
// DebugTrace( TEXT("Faulting in heap (%8x). UnkObj Inst: %8x"), lhHeap, pinst);
// Install the heap handle in the global data
pinst->hlh = lhHeap;
}
else
{
// The rare event that the heap got created by some other
// object between our UNKOBJ_Init and this (first) allocation ...
// ... Take it and use it.
lhHeap = pinst->hlh;
}
LeaveCriticalSection(&pinst->cs);
// Install the heap handle in this object's internal data too
// so we don't have to access the instance data for subsequent
// allocations. This does not need to be crit-sectioned on lpunkobj
// since an overwrite will be with the same heap!.
lpunkobj->lhHeap = lhHeap;
LH_SetHeapName(lhHeap, TEXT("UNKOBJ Internal Heap"));
}
#endif
/* Allocate the buffer.
*/
*lplpv = LH_Alloc( lhHeap,(UINT) ulcb );
if (!*lplpv)
{
DebugTrace( TEXT("LH_Alloc() - OOM allocating *lppv\n") );
return MAPI_E_NOT_ENOUGH_MEMORY;
}
LH_SetName1(lhHeap, *lplpv, TEXT("UNKOBJ::ScCOAllocate %ld"), *lplpv);
return S_OK;
}
/*============================================================================
- UNKOBJ::ScCOReallocate()
-
* Utility function to reallocate memory using CO memory allocators.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* ulcb in Count of bytes to allocate.
* lplpv in Pointer to buffer to reallocate.
* out Pointer to reallocated buffer.
*/
STDAPI_(SCODE)
UNKOBJ_ScCOReallocate( LPUNKOBJ lpunkobj,
ULONG ulcb,
LPVOID FAR * lplpv )
{
HLH lhHeap;
SCODE sc = S_OK;
LPVOID lpv = NULL;
// validate parameters
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
AssertSz( lplpv && !IsBadWritePtr( lplpv, sizeof( LPVOID ) ),
TEXT("lplpv fails address check") );
lhHeap = lpunkobj->lhHeap;
// Enable following section when we fault in the Heap - requires changes
// throughout where CreateIProp/CreateITable calls are
// done followed by LH_SetHeapName(). The LH_SetHeapName
// calls have to be used since we may not have a heap
// at the time. Furthermore, there is only 1 heap, so
// they are unnecessary anyway.
#if 1
if (!lhHeap)
{
LPUNKOBJCLASSINST pinst;
// The UNKOBJ heap *probably* does not exist, make sure
// (to guard against a race) and create it if indeed so.
pinst = (LPUNKOBJCLASSINST)PvGetInstanceGlobals();
Assert(pinst);
EnterCriticalSection(&pinst->cs);
if (!pinst->hlh)
{
lhHeap = LH_Open(0);
if (!lhHeap)
{
DebugTrace( TEXT("UNKOBJ_ScCOReallocate() - Can't create Local Heap"));
LeaveCriticalSection(&pinst->cs);
return MAPI_E_NOT_ENOUGH_MEMORY;
}
// DebugTrace( TEXT("Faulting in heap (%8x). UnkObj Inst: %8x"), lhHeap, pinst);
// Install the heap handle in the global data
pinst->hlh = lhHeap;
}
else
{
// The rare event that the heap got created by some other
// object between our UNKOBJ_Init and this (first) allocation ...
// ... Take it and use it.
lhHeap = pinst->hlh;
}
LeaveCriticalSection(&pinst->cs);
// Install the heap handle in this object's internal data too
// so we don't have to access the instance data for subsequent
// allocations. This does not need to be crit-sectioned on lpunkobj
// since an overwrite will be with the same heap!.
lpunkobj->lhHeap = lhHeap;
LH_SetHeapName(lhHeap, TEXT("UNKOBJ Internal Heap"));
}
#endif
//$BUG Actually, the CO model is supposed do an Alloc() if
//$BUG the pointer passed in is NULL, but it currently
//$BUG doesn't seem to work that way....
if ( *lplpv == NULL )
{
lpv = LH_Alloc(lhHeap, (UINT) ulcb);
if (lpv)
{
*lplpv = lpv;
LH_SetName1(lhHeap, lpv, TEXT("UNKOBJ::ScCOReallocate %ld"), lpv);
}
else
sc = E_OUTOFMEMORY;
goto out;
}
/* Reallocate the buffer.
*/
lpv = LH_Realloc(lhHeap, *lplpv, (UINT) ulcb );
if (!lpv)
{
DebugTrace( TEXT("UNKOBJ::ScCOReallocate() - OOM reallocating *lplpv\n") );
sc = MAPI_E_NOT_ENOUGH_MEMORY;
goto out;
}
LH_SetName1(lhHeap, lpv, TEXT("UNKOBJ::ScCOReallocate %ld"), lpv);
*lplpv = lpv;
out:
return sc;
}
/*============================================================================
- UNKOBJ::COFree()
-
* Utility function to free memory using CO memory allocators.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* lpv in Buffer to free.
*/
STDAPI_(VOID)
UNKOBJ_COFree( LPUNKOBJ lpunkobj,
LPVOID lpv )
{
HLH lhHeap;
// validate parameters
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
lhHeap = lpunkobj->lhHeap;
/* Free the buffer.
*/
//$??? Don't know if CO properly handles freeing NULL pointers,
//$??? but I assume it doesn't....
if ( lpv != NULL )
LH_Free( lhHeap, lpv );
}
/*============================================================================
- UNKOBJ::ScSzFromIdsAlloc()
-
* Utility function load a resource string into a MAPI-allocated buffer.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* ids in ID of resource string.
* ulFlags in Flags (UNICODE or ANSI)
* cchBuf in Max length, in characters, to read.
* lpszBuf out Pointer to allocated buffer containing string.
*/
STDAPI_(SCODE)
UNKOBJ_ScSzFromIdsAlloc( LPUNKOBJ lpunkobj,
IDS ids,
ULONG ulFlags,
int cchBuf,
LPTSTR FAR * lppszBuf )
{
SCODE sc;
ULONG ulStringMax;
// validate parameters
AssertSz( lpunkobj && !FBadUnknown( (LPUNKNOWN)lpunkobj ), TEXT("lpunkobj fails address check") );
AssertSz( lppszBuf && !IsBadWritePtr( lppszBuf, sizeof( LPVOID ) ),
TEXT("lppszBuf fails address check") );
AssertSz( cchBuf > 0, TEXT("cchBuf can't be less than 1") );
ulStringMax = cchBuf
* ((ulFlags & MAPI_UNICODE) ? sizeof(TCHAR) : sizeof(CHAR));
if ( FAILED(sc = UNKOBJ_ScAllocate(lpunkobj,
ulStringMax,
(LPVOID FAR *) lppszBuf)) )
{
DebugTrace( TEXT("UNKOBJ::ScSzFromIdsAlloc() - Error allocating string (SCODE = 0x%08lX)\n"), sc );
return sc;
}
#if !defined(WIN16) && !defined(MAC)
if ( ulFlags & MAPI_UNICODE )
(void) LoadStringW(hinstMapiX,
(UINT) ids,
(LPWSTR) *lppszBuf,
cchBuf);
else
#endif
(void) LoadStringA(hinstMapiX,
(UINT) ids,
(LPSTR) *lppszBuf,
cchBuf);
return S_OK;
}
/*============================================================================
- UNKOBJ::ScSzFromIdsAllocMore()
-
* Utility function load a resource string into a MAPI-allocated buffer.
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* ids in ID of resource string.
* ulFlags in Flags (UNICODE or ANSI)
* lpvBase in Base allocation
* cchBuf in Max length, in characters, to read.
* lpszBuf out Pointer to allocated buffer containing string.
*/
STDAPI_(SCODE)
UNKOBJ_ScSzFromIdsAllocMore( LPUNKOBJ lpunkobj,
IDS ids,
ULONG ulFlags,
LPVOID lpvBase,
int cchBuf,
LPTSTR FAR * lppszBuf )
{
SCODE sc;
ULONG ulStringMax;
ulStringMax = cchBuf
* ((ulFlags & MAPI_UNICODE) ? sizeof(WCHAR) : sizeof(CHAR));
if ( FAILED(sc = UNKOBJ_ScAllocateMore(lpunkobj,
ulStringMax,
lpvBase,
(LPVOID FAR *) lppszBuf)) )
{
DebugTrace( TEXT("UNKOBJ::ScSzFromIdsAllocMore() - Error allocating string (SCODE = 0x%08lX)\n"), sc );
return sc;
}
#if !defined(WIN16) && !defined(MAC)
if ( ulFlags & MAPI_UNICODE )
(void) LoadStringW(hinstMapiX,
(UINT) ids,
(LPWSTR) *lppszBuf,
cchBuf);
else
#endif
(void) LoadStringA(hinstMapiX,
(UINT) ids,
(LPSTR) *lppszBuf,
cchBuf);
return S_OK;
}
/*============================================================================
- UNKOBJ::Init()
-
* Initialize an object of the UNKOBJ Class
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
* lpvtblUnkobj in the object v-table
* ulcbVtbl in size of the object v-table
* rgpiidList in list of iid's supported by this object
* ulcIID in count of iid's in the list above
* punkinst in pointer to object's private (instance) data
*/
STDAPI_(SCODE)
UNKOBJ_Init( LPUNKOBJ lpunkobj,
UNKOBJ_Vtbl FAR * lpvtblUnkobj,
ULONG ulcbVtbl,
LPIID FAR * rgpiidList,
ULONG ulcIID,
PUNKINST punkinst )
{
SCODE sc = S_OK;
LPUNKOBJCLASSINST pinst = NULL;
// Create/Get per process global data for the Unkobj class
// This gets faulted in the first time UNKOBJ_Init
// is called by the process, i.e., when the process creates
// its first Unkobj. Subsequent calls just Addref
// the instance data. Note that this data is global to all
// UNKOBJ objects (per process) and differs from the per object
// data that *each* Unkobj keeps.
sc = ScGetUnkClassInst(&pinst);
if (FAILED(sc))
{
DebugTrace( TEXT("UNKOBJ_Init() - Can't create Instance Data"));
goto ret;
}
Assert(pinst);
lpunkobj->lpvtbl = lpvtblUnkobj;
lpunkobj->ulcbVtbl = ulcbVtbl;
lpunkobj->ulcRef = 1;
lpunkobj->rgpiidList= rgpiidList;
lpunkobj->ulcIID = ulcIID;
lpunkobj->pinst = punkinst;
lpunkobj->hrLastError = hrSuccess;
lpunkobj->idsLastError = 0;
InitializeCriticalSection(&lpunkobj->csid);
// If we have a heap for this instance, use it;
// otherwise, wait and it'll get faulted in the first time
// and allocation is made on this object.
lpunkobj->lhHeap = pinst->hlh ? pinst->hlh : NULL;
ret:
return sc;
}
/*============================================================================
- UNKOBJ::Deinit()
-
* Deinitialize an object of the UNKOBJ Class
*
*
* Parameters:
* lpunkobj in UNKOBJ with instance variable containing
* allocators.
*/
STDAPI_(VOID)
UNKOBJ_Deinit( LPUNKOBJ lpunkobj )
{
// Cleanup per process global data for the Unkobj class,
// if necessary. Last one out will end up shutting off
// the lights.
ReleaseUnkClassInst();
DeleteCriticalSection(&lpunkobj->csid);
}
#ifdef WIN16
// Win16 version of inline function. These are no longer inline function because
// Watcom WCC doesn't support inline. (WPP(C++ compiler) support inline.
VOID
UNKOBJ_EnterCriticalSection( LPUNKOBJ lpunkobj )
{
EnterCriticalSection(&lpunkobj->csid);
}
VOID
UNKOBJ_LeaveCriticalSection( LPUNKOBJ lpunkobj )
{
LeaveCriticalSection(&lpunkobj->csid);
}
HRESULT
UNKOBJ_HrSetLastResult( LPUNKOBJ lpunkobj,
HRESULT hResult,
IDS idsError )
{
UNKOBJ_EnterCriticalSection(lpunkobj);
lpunkobj->idsLastError = idsError;
lpunkobj->hrLastError = hResult;
UNKOBJ_LeaveCriticalSection(lpunkobj);
return hResult;
}
HRESULT
UNKOBJ_HrSetLastError( LPUNKOBJ lpunkobj,
SCODE sc,
IDS idsError )
{
UNKOBJ_EnterCriticalSection(lpunkobj);
lpunkobj->idsLastError = idsError;
lpunkobj->hrLastError = ResultFromScode(sc);
UNKOBJ_LeaveCriticalSection(lpunkobj);
return ResultFromScode(sc);
}
VOID
UNKOBJ_SetLastError( LPUNKOBJ lpunkobj,
SCODE sc,
IDS idsError )
{
lpunkobj->idsLastError = idsError;
lpunkobj->hrLastError = ResultFromScode(sc);
}
VOID
UNKOBJ_SetLastErrorSc( LPUNKOBJ lpunkobj,
SCODE sc )
{
lpunkobj->hrLastError = ResultFromScode(sc);
}
VOID
UNKOBJ_SetLastErrorIds( LPUNKOBJ lpunkobj,
IDS ids )
{
lpunkobj->idsLastError = ids;
}
#endif // WIN16