windows-nt/Source/XPSP1/NT/ds/adsi/utils/disputil.cxx
2020-09-26 16:20:57 +08:00

1277 lines
31 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: disputil.cxx
//
// Contents: Dispatch Utilities.
//
// Classes:
//
// Functions:
//
// History: 25-Oct-94 KrishnaG appropriated from the ADs project
//
//----------------------------------------------------------------------------
#include "procs.hxx"
#define VT_TYPEMASK 0x3ff
#define BAIL_ON_FAILURE(hr) \
if (FAILED(hr)) { \
goto error; \
}
#define CONTINUE_ON_FAILURE(hr) \
if (FAILED(hr)) { \
continue; \
}
HMODULE g_hActiveDs = NULL; // Module handle of activeds.dll. This should be
// initialized when the provider module is loaded
// into a process' address space. The handle
// is used by FillExcepInfo to retrieve error
// description strings from activeds.dll.
static HRESULT VARIANTARGToCVar(VARIANTARG * pvarg, VARTYPE vt, void* pv);
static void CVarToVARIANTARG(void* pv, VARTYPE vt, VARIANTARG * pvarg);
//+---------------------------------------------------------------------------
//
// Function: FreeEXCEPINFO
//
// Synopsis: Frees resources in an excepinfo. Does not reinitialize
// these fields.
//
//----------------------------------------------------------------------------
void
FreeEXCEPINFO(EXCEPINFO * pEI)
{
if (pEI)
{
ADsFreeString(pEI->bstrSource);
ADsFreeString(pEI->bstrDescription);
ADsFreeString(pEI->bstrHelpFile);
}
}
//+---------------------------------------------------------------------------
//
// Function: ValidateInvoke
//
// Synopsis: Validates arguments to a call of IDispatch::Invoke. A call
// to this function takes less space than the function itself.
//
//----------------------------------------------------------------------------
HRESULT
ValidateInvoke(
DISPPARAMS * pdispparams,
VARIANT * pvarResult,
EXCEPINFO * pexcepinfo,
UINT * puArgErr)
{
if (pvarResult)
VariantInit(pvarResult);
if (pexcepinfo)
InitEXCEPINFO(pexcepinfo);
if (puArgErr)
*puArgErr = 0;
if (!pdispparams)
RRETURN(E_INVALIDARG);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: VARIANTARGToCVar
//
// Synopsis: Converts a VARIANT to a C-language variable.
//
// Arguments: [pvarg] -- Variant to convert.
// [vt] -- Type to convert to.
// [pv] -- Location to place C-language variable.
//
// Modifies: [pv].
//
// Returns: HRESULT.
//
// History: 2-23-94 adams Created
//
// Notes: Supports all variant pointer types, VT_I2, VT_I4, VT_R4,
// VT_R8.
//----------------------------------------------------------------------------
static HRESULT
VARIANTARGToCVar(VARIANT * pvarg, VARTYPE vt, void * pv)
{
HRESULT hr = S_OK;
VARIANTARG vargNew; // variant of new type
ADsAssert(pvarg);
ADsAssert(pv);
ADsAssert((vt & ~VT_TYPEMASK) == 0 || (vt & ~VT_TYPEMASK) == VT_BYREF);
if (vt & VT_BYREF)
{
if (V_VT(pvarg) != vt)
{
hr = DISP_E_TYPEMISMATCH;
goto Cleanup;
}
// Use a supported pointer type for derefencing.
vt = VT_UNKNOWN;
vargNew = *pvarg;
}
else
{
VariantInit(&vargNew);
hr = VariantChangeType(&vargNew, pvarg, 0, vt);
if (hr)
goto Cleanup;
}
switch (vt)
{
case VT_BOOL:
if (V_BOOL(&vargNew) != VB_FALSE && V_BOOL(&vargNew) != VB_TRUE)
{
hr = E_FAIL;
goto Cleanup;
}
// convert VT_TRUE to TRUE
*(BOOL *)pv = - V_BOOL(&vargNew);
break;
case VT_I2:
*(short *)pv = V_I2(&vargNew);
break;
case VT_I4:
*(long *)pv = V_I4(&vargNew);
break;
case VT_R4:
*(float *)pv = V_R4(&vargNew);
break;
case VT_R8:
*(double *)pv = V_R8(&vargNew);
break;
//
// All Pointer types.
//
case VT_BSTR:
case VT_LPSTR:
case VT_LPWSTR:
case VT_DISPATCH:
case VT_UNKNOWN:
*(void **)pv = V_BYREF(&vargNew);
break;
default:
ADsAssert(FALSE && "Unknown type in VARIANTARGToCVar().\n");
break;
}
Cleanup:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
//
// Function: CVarToVARIANTARG
//
// Synopsis: Converts a C-language variable to a VARIANT.
//
// Arguments: [pv] -- Pointer to C-language variable.
// [vt] -- Type of C-language variable.
// [pvarg] -- Resulting VARIANT. Must be initialized by caller.
// Any contents will be freed.
//
// Modifies: [pvarg]
//
// History: 2-23-94 adams Created
//
// Notes: Supports all variant pointer types, VT_UI2, VT_I2, VT_UI4,
// VT_I4, VT_R4, VT_R8.
//
//----------------------------------------------------------------------------
static void
CVarToVARIANTARG(void* pv, VARTYPE vt, VARIANTARG * pvarg)
{
ADsAssert(pv);
ADsAssert(pvarg);
VariantClear(pvarg);
V_VT(pvarg) = vt;
if (V_ISBYREF(pvarg))
{
// Use a supported pointer type for derefencing.
vt = VT_UNKNOWN;
}
switch (vt)
{
case VT_BOOL:
// convert TRUE to VT_TRUE
ADsAssert(*(BOOL *) pv == 1 || *(BOOL *) pv == 0);
V_BOOL(pvarg) = VARIANT_BOOL(-*(BOOL *) pv);
break;
case VT_I2:
V_I2(pvarg) = *(short *) pv;
break;
case VT_I4:
V_I4(pvarg) = *(long *) pv;
break;
case VT_R4:
V_R4(pvarg) = *(float *) pv;
break;
case VT_R8:
V_R8(pvarg) = *(double *) pv;
break;
//
// All Pointer types.
//
case VT_BSTR:
case VT_LPSTR:
case VT_LPWSTR:
case VT_DISPATCH:
case VT_UNKNOWN:
V_BYREF(pvarg) = *(long **)pv;
break;
default:
Assert(FALSE && "Unknown type.");
break;
}
}
//+---------------------------------------------------------------------------
//
// Function: CParamsToDispParams
//
// Synopsis: Converts a C parameter list to a dispatch parameter list.
//
// Arguments: [pDispParams] -- Resulting dispatch parameter list.
// Note that the rgvarg member of pDispParams
// must be initialized with an array of
// EVENTPARAMS_MAX VARIANTs.
//
// [pvt] -- List of C parameter types. May be NULL.
// If not NULL, Last elem in list MUST be
// VT_EMPTY.
//
// [va] -- List of C arguments.
//
// Modifies: [pDispParams]
//
// History: 05-Jan-94 adams Created
// 23-Feb-94 adams Reversed order of disp arguments, added
// support for VT_R4, VT_R8, and pointer
// types.
//
// Notes: Only types VT_I2,VT_I4, and VT_UNKNOWN are supported.
//
//----------------------------------------------------------------------------
void
CParamsToDispParams(
DISPPARAMS * pDispParams,
VARTYPE * pvt,
va_list va)
{
ADsAssert(pDispParams);
ADsAssert(pDispParams->rgvarg);
VARIANTARG * pvargCur; // current variant
VARTYPE * pvtCur; // current vartype
// Assign vals to dispatch param list.
pDispParams->cNamedArgs = 0;
pDispParams->rgdispidNamedArgs = NULL;
// Get count of arguments.
if (!pvt)
{
pDispParams->cArgs = 0;
return;
}
for (pvtCur = pvt; *pvtCur != VT_EMPTY; pvtCur++)
;
pDispParams->cArgs = (DWORD)(pvtCur - pvt);
ADsAssert(pDispParams->cArgs < EVENTPARAMS_MAX);
//
// Convert each C-param to a dispparam. Note that the order of dispatch
// parameters is the reverse of the order of c-params.
//
ADsAssert(pDispParams->rgvarg);
pvargCur = pDispParams->rgvarg + pDispParams->cArgs;
for (pvtCur = pvt; *pvtCur != VT_EMPTY; pvtCur++)
{
pvargCur--;
ADsAssert(pvargCur >= pDispParams->rgvarg);
V_VT(pvargCur) = *pvtCur;
if ((*pvtCur & VT_BYREF) == VT_BYREF)
{
V_BYREF(pvargCur) = va_arg(va, long *);
}
else
{
switch (*pvtCur)
{
case VT_BOOL:
// convert TRUE to VT_TRUE
V_BOOL(pvargCur) = VARIANT_BOOL(-va_arg(va, BOOL));
ADsAssert(V_BOOL(pvargCur) == VB_FALSE ||
V_BOOL(pvargCur) == VB_TRUE);
break;
case VT_I2:
V_I2(pvargCur) = va_arg(va, short);
break;
case VT_I4:
V_I4(pvargCur) = va_arg(va, long);
break;
case VT_R4:
V_R4(pvargCur) = va_arg(va, float);
break;
case VT_R8:
V_R8(pvargCur) = va_arg(va, double);
break;
//
// All Pointer types.
//
case VT_BSTR:
case VT_LPSTR:
case VT_LPWSTR:
case VT_DISPATCH:
case VT_UNKNOWN:
V_BYREF(pvargCur) = va_arg(va, long *);
break;
default:
Assert(FALSE && "Unknown type.\n");
}
}
}
}
//+---------------------------------------------------------------------------
//
// Function: DispParamsToCParams
//
// Synopsis: Converts Dispatch::Invoke method params to C-language params.
//
// Arguments: [pDP] -- Dispatch params to be converted.
// [pvt] -- Array of types of C-params. May be NULL. If
// non-NULL, last element must be VT_EMPTY.
// [...] -- List of pointers to c-params to be converted to.
//
// Returns: HRESULT.
//
// History: 2-23-94 adams Created
//
// Notes: Supports types listed in VARIANTToCParam.
//
//----------------------------------------------------------------------------
STDAPI
DispParamsToCParams(
DISPPARAMS * pDP,
UINT * puArgErr,
VARTYPE * pvt,
...)
{
HRESULT hr;
va_list va; // list of pointers to c-params.
VARTYPE * pvtCur; // current VARTYPE of c-param.
VARIANTARG * pvargCur; // current VARIANT being converted.
void * pv; // current c-param being converted.
int cArgs; // count of arguments.
ADsAssert(pDP);
hr = S_OK;
va_start(va, pvt);
if (!pvt)
{
if (pDP->cArgs > 0)
goto BadParamCountError;
goto Cleanup;
}
pvargCur = pDP->rgvarg + pDP->cArgs - 1;
pvtCur = pvt;
for (cArgs = 0; cArgs < (int)pDP->cArgs; cArgs++)
{
if (*pvtCur == VT_EMPTY)
goto BadParamCountError;
pv = va_arg(va, void *);
hr = VARIANTARGToCVar(pvargCur, *pvtCur, pv);
if (hr)
{
if (puArgErr)
*puArgErr = cArgs;
goto Cleanup;
}
pvargCur--;
pvtCur++;
}
if (*pvtCur != VT_EMPTY)
goto BadParamCountError;
Cleanup:
va_end(va);
RRETURN(hr);
BadParamCountError:
hr = DISP_E_BADPARAMCOUNT;
goto Cleanup;
}
//+---------------------------------------------------------------------------
//
// Function: GetDispProp
//
// Synopsis: Gets a property of an object.
//
// Arguments: [pDisp] -- The object containing the property.
// [dispid] -- The ID of the property.
// [riid] -- interface of object desired
// [lcid] -- The locale of the object.
// [pvar] -- The resulting property. Must be initialized.
//
// Returns: HRESULT.
//
// Modifies: [pvarg].
//
// History: 23-Feb-94 adams Created
// 08-Apr-94 DonCl modified to take REFIID
//
//----------------------------------------------------------------------------
HRESULT
GetDispProp(
IDispatch * pDisp,
DISPID dispid,
REFIID riid,
LCID lcid,
VARIANT * pvar,
EXCEPINFO * pexcepinfo)
{
HRESULT hr;
DISPPARAMS dp; // Params for IDispatch::Invoke.
UINT uiErr; // Argument error.
ADsAssert(pDisp);
ADsAssert(pvar);
dp.rgvarg = NULL;
dp.rgdispidNamedArgs = NULL;
dp.cArgs = 0;
dp.cNamedArgs = 0;
hr = pDisp->Invoke(
dispid,
riid,
lcid,
DISPATCH_PROPERTYGET,
&dp,
pvar,
pexcepinfo,
&uiErr);
RRETURN(hr);
}
//+---------------------------------------------------------------------------
//
// Function: SetDispProp
//
// Synopsis: Sets a property on an object.
//
// Arguments: [pDisp] -- The object to set the property on.
// [dispid] -- The ID of the property.
// [riid] -- interface of object
// [lcid] -- The locale of the property.
// [pvarg] -- The value to set.
//
// Returns: HRESULT.
//
// History: 23-Feb-94 adams Created
// 08-Apr-94 DonCl modified to take REFIID
//
//----------------------------------------------------------------------------
HRESULT
SetDispProp(
IDispatch * pDisp,
DISPID dispid,
REFIID riid,
LCID lcid,
VARIANTARG * pvarg,
EXCEPINFO * pexcepinfo)
{
HRESULT hr;
DISPID dispidPut = DISPID_PROPERTYPUT; // Dispid of prop arg.
DISPPARAMS dp; // Params for Invoke
UINT uiErr; // Invoke error param.
ADsAssert(pDisp);
ADsAssert(pvarg);
dp.rgvarg = pvarg;
dp.rgdispidNamedArgs = &dispidPut;
dp.cArgs = 1;
dp.cNamedArgs = 1;
hr = pDisp->Invoke(
dispid,
riid,
lcid,
DISPATCH_PROPERTYPUT,
&dp,
NULL,
pexcepinfo,
&uiErr);
RRETURN(hr);
}
//+---------------------------------------------------------------------------
//
// Function: GetDispPropOfType
//
// Synopsis: Gets a property from an object, and converts it to a c
// variable.
//
// Arguments: [pDisp] -- The object to retrieve the property from.
// [dispid] -- Property ID.
// [lcid] -- Locale of property.
// [vt] -- Type of c-variable to receive property.
// [pv] -- Pointer to resulting c-variable.
//
// Returns: HRESULT.
//
// Modifies: [pv].
//
// History: 2-23-94 adams Created
//
// Notes: Supports variable types found in VARIANTARGToCVar.
//
//----------------------------------------------------------------------------
HRESULT
GetDispPropOfType(
IDispatch * pDisp,
DISPID dispid,
LCID lcid,
VARTYPE vt,
void * pv)
{
HRESULT hr;
VARIANT varProp; // Property retrieved.
DISPPARAMS dp; // Params for IDispatch::Invoke.
ADsAssert(pDisp);
ADsAssert(pv);
dp.rgvarg = NULL;
dp.rgdispidNamedArgs = NULL;
dp.cArgs = 0;
dp.cNamedArgs = 0;
VariantInit(&varProp);
hr = pDisp->Invoke(
dispid,
IID_NULL,
lcid,
DISPATCH_PROPERTYGET,
&dp,
&varProp,
NULL,
NULL);
if (hr)
goto Cleanup;
hr = VARIANTARGToCVar(&varProp, vt, pv);
Cleanup:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
//
// Function: SetDispPropOfType
//
// Synopsis: Sets a property on an object.
//
// Arguments: [pDisp] -- Object to set property on.
// [dispid] -- Property ID to set.
// [lcid] -- Locale of property.
// [vt] -- Type of property to set.
// [pv] -- Pointer to property value.
//
// Returns: HRESULT.
//
// History: 2-23-94 adams Created
//
// Notes: Supports types found in VARIANTARGToCVar.
//
//----------------------------------------------------------------------------
HRESULT
SetDispPropOfType(
IDispatch * pDisp,
DISPID dispid,
LCID lcid,
VARTYPE vt,
void * pv)
{
HRESULT hr;
VARIANTARG varg; // Variant property to put.
DISPID dispidPut = DISPID_PROPERTYPUT; // Dispid of prop arg.
DISPPARAMS dp; // Params for Invoke
ADsAssert(pDisp);
ADsAssert(pv);
VariantInit(&varg);
CVarToVARIANTARG(pv, vt, &varg);
dp.rgvarg = &varg;
dp.rgdispidNamedArgs = &dispidPut;
dp.cArgs = 1;
dp.cNamedArgs = 1;
hr = pDisp->Invoke(
dispid,
IID_NULL,
lcid,
DISPATCH_PROPERTYPUT,
&dp,
NULL,
NULL,
NULL);
RRETURN(hr);
}
//+---------------------------------------------------------------------------
//
// Function: CallDispMethod
//
// Synopsis: Calls a late-bound method on a object via IDispatch::Invoke.
//
// Arguments: [pDisp] -- Object to call method on.
// [dispid] -- Method ID.
// [lcid] -- Locale of method.
// [vtReturn] -- Type of return value. If no return value,
// must be VT_VOID.
// [pvReturn] -- Location of return value. If no return value,
// must be NULL.
// [pvtParams] -- List of param types. May be NULL. If
// non-NULL, last entry must be VT_EMPTY.
// [...] -- List of params.
//
// Returns: HRESULT.
//
// History: 2-23-94 adams Created
//
//----------------------------------------------------------------------------
HRESULT
CallDispMethod(
IDispatch * pDisp,
DISPID dispid,
LCID lcid,
VARTYPE vtReturn,
void * pvReturn,
VARTYPE * pvtParams,
...)
{
HRESULT hr;
VARIANTARG av[EVENTPARAMS_MAX]; // List of args for Invoke.
DISPPARAMS dp; // Params for Invoke.
VARIANT varReturn; // Return value.
va_list va; // List of C-params.
ADsAssert(pDisp);
ADsAssert((vtReturn != VT_VOID) == (pvReturn != NULL));
va_start(va, pvtParams);
dp.rgvarg = av;
CParamsToDispParams(&dp, pvtParams, va);
va_end(va);
if (pvReturn)
VariantInit(&varReturn);
hr = pDisp->Invoke(
dispid,
IID_NULL,
lcid,
DISPATCH_METHOD,
&dp,
pvReturn ? &varReturn : NULL,
NULL,
NULL);
if (hr)
goto Cleanup;
if (pvReturn)
hr = VARIANTARGToCVar(&varReturn, vtReturn, pvReturn);
Cleanup:
RRETURN(hr);
}
//+------------------------------------------------------------------------
//
// Function: IsVariantEqual, public API
//
// Synopsis: Compares the values of two VARIANTARGs.
//
// Arguments: [pvar1], [pvar2] -- VARIANTARGs to compare.
//
// Returns: TRUE if equal, FALSE if not.
//
// History: 18-Mar-93 SumitC Created.
// 11-May-94 SumitC don't assert for VT_UNKNOWN
//
// Notes: Variant type unequal returns FALSE, even if actual values
// are the same.
// Currently does I2, I4, R4, R8, CY, BSTR, BOOL
// Returns FALSE for all other VariantTypes.
//
//-------------------------------------------------------------------------
BOOL
IsVariantEqual( VARIANTARG FAR* pvar1, VARIANTARG FAR* pvar2 )
{
if( V_VT(pvar1) != V_VT(pvar2) )
return FALSE;
switch (V_VT(pvar1))
{
case VT_EMPTY :
case VT_NULL:
return TRUE; // just the types being equal is good enough
case VT_I2 :
return (V_I2(pvar1) == V_I2(pvar2));
case VT_I4 :
return (V_I4(pvar1) == V_I4(pvar2));
case VT_R4 :
return (V_R4(pvar1) == V_R4(pvar2));
case VT_R8 :
return (V_R8(pvar1) == V_R8(pvar2));
case VT_CY :
return !memcmp(&V_CY(pvar1), &V_CY(pvar2), sizeof(CY));
case VT_BSTR :
return !ADsStringCmp(V_BSTR(pvar1), V_BSTR(pvar2));
case VT_BOOL :
return (V_BOOL(pvar1) == V_BOOL(pvar2));
case VT_UNKNOWN:
// returns FALSE unless the objects are the same
return (V_UNKNOWN(pvar1) == V_UNKNOWN(pvar2));
default:
ADsAssert(0 && "Type not handled");
break;
};
return(FALSE);
}
HRESULT
ConvertSafeArrayToVariantArray(
VARIANT varSafeArray,
PVARIANT * ppVarArray,
PDWORD pdwNumVariants
)
{
HRESULT hr = S_OK;
DWORD dwSLBound = 0;
DWORD dwSUBound = 0;
DWORD dwNumVariants = 0;
DWORD i = 0;
VARIANT * pVarArray = NULL;
SAFEARRAY * pArray = NULL;
VARIANT *pvProp = NULL;
*pdwNumVariants = 0;
*ppVarArray = 0;
//
// It has to be a variant and a safearray. It might
// also be a variant that is byref and safe array
//
//
pvProp = &varSafeArray;
if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
pvProp = V_VARIANTREF(&varSafeArray);
}
if(!(((V_VT(pvProp) & VT_VARIANT)== VT_VARIANT)
&& V_ISARRAY(pvProp))) {
//
// We need to make this additional check. This is not really
// legal but it could be that just the tag at this level is wrong.
// This was allowed in older versions of ADSI and therefore needs
// on future versions (backward compatibility).
//
if(!((V_VT(&varSafeArray) & VT_VARIANT) && V_ISARRAY(&varSafeArray)))
RRETURN(E_FAIL);
}
if (V_VT(pvProp) == (VT_BYREF | VT_VARIANT | VT_ARRAY)) {
//
// in this case we need to use the ARRAY_REF.
//
pArray = *(V_ARRAYREF(pvProp));
}
else {
//
// pvProp will always have the correc info, byref or not.
//
pArray = V_ARRAY(pvProp);
}
//
// Check that there is only one dimension in this array
//
if (pArray->cDims != 1) {
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
//
// Check that there is at least one element in this array
//
if (pArray->rgsabound[0].cElements == 0){
RRETURN(S_OK); // Return success and null array
}
//
// We know that this is a valid single dimension array
//
hr = SafeArrayGetLBound(pArray,
1,
(long FAR *)&dwSLBound
);
BAIL_ON_FAILURE(hr);
hr = SafeArrayGetUBound(pArray,
1,
(long FAR *)&dwSUBound
);
BAIL_ON_FAILURE(hr);
dwNumVariants = dwSUBound - dwSLBound + 1;
pVarArray = (PVARIANT)AllocADsMem(
sizeof(VARIANT)*dwNumVariants
);
if (!pVarArray) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
for (i = dwSLBound; i <= dwSUBound; i++) {
VariantInit(pVarArray + i);
hr = SafeArrayGetElement(pArray,
(long FAR *)&i,
(pVarArray + i)
);
CONTINUE_ON_FAILURE(hr);
}
*ppVarArray = pVarArray;
*pdwNumVariants = dwNumVariants;
error:
RRETURN(hr);
}
//
// This method should go away. ConvertSafeArrayToVariantArray does the job.
//
HRESULT
ConvertByRefSafeArrayToVariantArray(
VARIANT varSafeArray,
PVARIANT * ppVarArray,
PDWORD pdwNumVariants
)
{
RRETURN(ConvertSafeArrayToVariantArray(
varSafeArray,
ppVarArray,
pdwNumVariants
));
}
//
// An LDAP query needs a NULL-terminated array of strings.
//
HRESULT
ConvertVariantArrayToLDAPStringArray(
PVARIANT pVarArray,
PWSTR **pppszStringArray,
DWORD dwNumStrings
)
{
HRESULT hr = S_OK;
PWSTR *ppszStringArray = NULL;
DWORD i = 0;
//
// Start off with a zero-length array.
//
*pppszStringArray = NULL;
//
// The LDAP library expects an array terminated with a NULL string.
// So make space for an extra one.
//
dwNumStrings++;
ppszStringArray = (PWSTR *)AllocADsMem(dwNumStrings * sizeof(PWSTR));
if (!ppszStringArray)
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
for (i = 0; i < dwNumStrings - 1; i++)
{
if (!(V_VT(pVarArray + i) == VT_BSTR))
BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
ppszStringArray[i] = AllocADsStr(V_BSTR(pVarArray + i));
if (!ppszStringArray[i])
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
//
// NULL-terminated for LDAP.
//
ppszStringArray[i] = NULL;
*pppszStringArray = ppszStringArray;
RRETURN(hr);
error:
if (ppszStringArray)
{
for (DWORD j = 0; j < i; j++)
if (ppszStringArray[i])
FreeADsStr(ppszStringArray[i]);
FreeADsMem(ppszStringArray);
}
RRETURN(hr);
}
HRESULT
VariantToBinary(
PVARIANT pVarSrcObject,
DWORD *pdwLength,
BYTE **ppByte
)
{
HRESULT hr = S_OK;
LONG dwSLBound = 0;
LONG dwSUBound = 0;
CHAR HUGEP *pArray = NULL;
BYTE *pByte = NULL;
if( pVarSrcObject->vt != (VT_ARRAY | VT_UI1)) {
RRETURN(hr = E_ADS_CANT_CONVERT_DATATYPE);
}
hr = SafeArrayGetLBound(V_ARRAY(pVarSrcObject),
1,
(long FAR *) &dwSLBound );
BAIL_ON_FAILURE(hr);
hr = SafeArrayGetUBound(V_ARRAY(pVarSrcObject),
1,
(long FAR *) &dwSUBound );
BAIL_ON_FAILURE(hr);
pByte = (BYTE*)AllocADsMem( dwSUBound - dwSLBound + 1);
if ( pByte == NULL) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
hr = SafeArrayAccessData( V_ARRAY(pVarSrcObject),
(void HUGEP * FAR *) &pArray );
BAIL_ON_FAILURE(hr);
memcpy( pByte,
pArray,
dwSUBound-dwSLBound+1);
SafeArrayUnaccessData( V_ARRAY(pVarSrcObject) );
*pdwLength = dwSUBound - dwSLBound + 1;
*ppByte = pByte;
RRETURN(hr);
error:
if (pByte) {
FreeADsMem(pByte);
}
RRETURN(hr);
}
HRESULT
BinaryToVariant(
DWORD Length,
BYTE* pByte,
PVARIANT lpVarDestObject
)
{
HRESULT hr = S_OK;
SAFEARRAY *aList = NULL;
SAFEARRAYBOUND aBound;
CHAR HUGEP *pArray = NULL;
aBound.lLbound = 0;
aBound.cElements = Length;
aList = SafeArrayCreate( VT_UI1, 1, &aBound );
if ( aList == NULL ) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray );
BAIL_ON_FAILURE(hr);
memcpy( pArray, pByte, aBound.cElements );
SafeArrayUnaccessData( aList );
V_VT(lpVarDestObject) = VT_ARRAY | VT_UI1;
V_ARRAY(lpVarDestObject) = aList;
RRETURN(hr);
error:
if ( aList ) {
SafeArrayDestroy( aList );
}
RRETURN(hr);
}
HRESULT
CopyOctetString(
DWORD dwNumBytes,
BYTE *pData,
DWORD *pdwNumBytes,
BYTE **ppByte
)
{
LPBYTE lpByteStream = NULL;
HRESULT hr = S_OK;
if (dwNumBytes) {
lpByteStream = (LPBYTE)AllocADsMem(dwNumBytes);
if (lpByteStream == NULL) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
memcpy(
lpByteStream,
pData,
dwNumBytes
);
*pdwNumBytes = dwNumBytes;
*ppByte = lpByteStream;
}
else {
*pdwNumBytes = 0;
*ppByte = NULL;
}
error:
RRETURN(hr);
}
//+------------------------------------------------------------------------
//
// Function: RaiseException, public API
//
// Synopsis: Generic function for translating ADS HRESULT codes to an
// OLE error object.
//
// Arguments: [hr] - The HRESULT code to be translated into
// an OLE error object.
//
//
// Returns: Nothing. This function is called when an error occurred.
// There isn't much the caller can do if this function fails.
//
// History: 10-Sep-97 t-rmak Created.
//
//
// Notes: 1) Only ADS error codes are properly translated to
// corresponding OLE error objects.
// 2) This function will ignore the lcid passed into
// ITypeInfo::Invoke and it always passes 0 as the langid
// to FormatMessage.
// 3) Only the source field and the description field of the
// error object will be filled by this function.
// 4) This function does not support inserts in the description
// string.
//
//-------------------------------------------------------------------------
void
RaiseException(HRESULT hr)
{
DWORD dwStrLen;
LPTSTR lpszMessage = NULL;
ICreateErrorInfo *pICreateErrorInfo = NULL;
IErrorInfo *pIErrorInfo = NULL;
HRESULT localhr = S_OK;
if (g_hActiveDs != NULL) {
//
// Clear any previously set error object
//
SetErrorInfo(0, NULL);
//
// Let FormatMessage allocate the message buffer.
// In a multi-threaded environment, this is the simplest
// solution.
//
dwStrLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
// Ignore inserts for now.
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_HMODULE,
(LPCVOID) g_hActiveDs,
hr,
0,
(LPTSTR) &lpszMessage,
0,
NULL);
//
// We may want to fail with a special error code if the specified
// lcid is not supported.
//
if (dwStrLen == 0) {
goto error;
}
//
// We may want to add support for help file in the future.
//
localhr = CreateErrorInfo(&pICreateErrorInfo);
BAIL_ON_FAILURE(localhr);
//
// Note that we don't care whether the following calls succeed since
// there is nothing we can if they fail.
//
pICreateErrorInfo->SetDescription(lpszMessage);
pICreateErrorInfo->SetSource(TEXT("Active Directory"));
//
// Set the threads error object.
//
pICreateErrorInfo->QueryInterface(IID_IErrorInfo, (void **)&pIErrorInfo);
SetErrorInfo(0, pIErrorInfo);
}
error:
if (lpszMessage != NULL) {
LocalFree(lpszMessage);
}
//
// Release the error object's interface pointers
//
if (pIErrorInfo != NULL) {
pIErrorInfo->Release();
}
if (pICreateErrorInfo != NULL) {
pICreateErrorInfo->Release();
}
}