Exemplo n.º 1
0
BOOL PyADSIObject_AsTypedValue(PyObject *val, ADSVALUE &v)
{
	BOOL ok = TRUE;
	switch (v.dwType) {
		// OK - get lazy - we know its a union!
		case ADSTYPE_DN_STRING:
		case ADSTYPE_CASE_EXACT_STRING:
		case ADSTYPE_CASE_IGNORE_STRING:
		case ADSTYPE_PRINTABLE_STRING:
		case ADSTYPE_NUMERIC_STRING:
		case ADSTYPE_OBJECT_CLASS:
			ok = PyWinObject_AsWCHAR(val, &v.DNString, FALSE);
			break;
		case ADSTYPE_BOOLEAN:
			v.Boolean = PyInt_AsLong(val);
			break;
		case ADSTYPE_INTEGER:
			v.Integer = PyInt_AsLong(val);
			break;
		case ADSTYPE_UTC_TIME:
			ok = PyWinObject_AsSYSTEMTIME(val, &v.UTCTime);
			break;
		case ADSTYPE_LARGE_INTEGER:
			ok = PyWinObject_AsLARGE_INTEGER(val, &v.LargeInteger);
			break;
		default:
			PyErr_SetString(PyExc_TypeError, "Cant convert to this type");
			return FALSE;
	}
	return ok;
}
Exemplo n.º 2
0
// @object PySPropValue|A MAPI property value.  Property values can either be passed from
// python into MAPI functions, or returned from MAPI functions to Python.
BOOL PyMAPIObject_AsSPropValue(PyObject *Valob, SPropValue *pv, void *pAllocMoreLinkBlock)
{
    PyObject *ob;
    // @pyparm int|propType||The type of the MAPI property
    // @pyparm object|value||The property value
    if (!PyArg_ParseTuple(Valob, "lO:SPropValue item", &pv->ulPropTag, &ob )) {
        PyErr_Clear();
        PyErr_SetString(PyExc_TypeError, "An SPropValue item must be a tuple of (integer, object)");
        return NULL;
    }
    BOOL ok = TRUE;
    unsigned int i;
    PyErr_Clear();
    // @comm The parameters can be one of the following pairs of values.
    // @flagh propType|value
    switch (PROP_TYPE(pv->ulPropTag)) {
    // @flag PT_I2|An integer
    case PT_I2:	//		case PT_SHORT:
        pv->Value.i = (int)PyInt_AsLong(ob);
        break;
    // @flag PT_MV_I2|A sequence of integers
    case PT_MV_I2:
        MAKE_MV(short int, pAllocMoreLinkBlock, pv->Value.MVi.lpi, pv->Value.MVi.cValues, PyInt_AsLong)
    // @flag PT_I4|An integer
    case PT_I4: //		case PT_LONG:
        pv->Value.l = PyInt_AsLong(ob);
        break;
    // @flag PT_MV_I4|A sequence of integers
    case PT_MV_I4:
        MAKE_MV(long, pAllocMoreLinkBlock, pv->Value.MVl.lpl, pv->Value.MVl.cValues, PyInt_AsLong)
    // @flag PT_R4|A float
    case PT_R4: //		case PT_FLOAT:
        pv->Value.flt = (float)PyFloat_AsDouble(ob);
        break;
    // @flag PT_MV_R4|A sequence of floats
    case PT_MV_R4:
        MAKE_MV(float, pAllocMoreLinkBlock, pv->Value.MVflt.lpflt, pv->Value.MVflt.cValues, PyFloat_AsDouble)
    // @flag PT_R8|A float
    case PT_R8: //		case PT_DOUBLE:
        pv->Value.dbl = PyFloat_AsDouble(ob);
        break;
    // @flag PT_MV_R8|A sequence of floats
    case PT_MV_R8:
        MAKE_MV(double, pAllocMoreLinkBlock, pv->Value.MVdbl.lpdbl, pv->Value.MVdbl.cValues, PyFloat_AsDouble)
    // @flag PT_BOOLEAN|A boolean value (or an int)
    case PT_BOOLEAN:
        pv->Value.b = PyInt_AsLong(ob) ? VARIANT_TRUE : VARIANT_FALSE;
        break;

    /*
    		case PT_CURRENCY:
    			p->Value.cur ??
    			break;

    */
    // @flag PT_APPTIME|A <o PyTime> object
    case PT_APPTIME :
        ok = PyWinObject_AsDATE(ob, &pv->Value.at);
        break;

    // @flag PT_MV_APPTIME|An sequence of <o PyTime> object
    case PT_MV_APPTIME:
        MAKEB_MV(double, pAllocMoreLinkBlock, pv->Value.MVat.lpat, pv->Value.MVat.cValues, PyWinObject_AsDATE)

    // @flag PT_SYSTIME|A <o PyTime> object
    case PT_SYSTIME:
        ok = PyWinObject_AsFILETIME(ob, &pv->Value.ft);
        break;

    // @flag PT_MV_APPTIME|An sequence of <o PyTime> object
    case PT_MV_SYSTIME:
        MAKEB_MV(FILETIME, pAllocMoreLinkBlock, pv->Value.MVft.lpft, pv->Value.MVft.cValues, PyWinObject_AsFILETIME)

    // @flag PT_STRING8|A string or <o PyUnicode>
    case PT_STRING8:
    {   // Copy into new MAPI memory block
        DWORD bufLen;
        char *str;
        ok = PyWinObject_AsString(ob, &str, FALSE, &bufLen);
        if (ok) {
            bufLen++;
            HRESULT hr = MAPIAllocateMore(bufLen, pAllocMoreLinkBlock, (void **)&pv->Value.lpszA);
            if (S_OK!=hr) {
                OleSetOleError(hr);
                ok = FALSE;
            } else {
                memcpy(pv->Value.lpszA, str, bufLen-sizeof(char));
                // Null terminate
                memcpy(((char *)pv->Value.lpszA)+(bufLen-sizeof(char)),"\0", sizeof(char));
            }
        }
        PyWinObject_FreeString(str);
        break;
    }

    // @flag PT_STRING8|A sequence of string or <o PyUnicode> objects.
    case PT_MV_STRING8:
        ok = AllocMVBuffer( ob, sizeof(char *), pAllocMoreLinkBlock, (void **)&pv->Value.MVszA.lppszA, &pv->Value.MVszA.cValues);
        if (!ok) break;
        for (i=0; ok && !PyErr_Occurred() && i<pv->Value.MVszA.cValues; i++) {
            PyObject *obmv=PySequence_GetItem(ob,i);
            if (obmv==NULL) break;

            DWORD bufLen;
            char *str;
            ok = PyWinObject_AsString(obmv, &str, FALSE, &bufLen);
            if (ok) {
                bufLen++;
                HRESULT hr = MAPIAllocateMore(bufLen, pAllocMoreLinkBlock, (void **)&pv->Value.MVszA.lppszA[i]);
                if (S_OK!=hr) {
                    OleSetOleError(hr);
                    ok = FALSE;
                } else {
                    memcpy(pv->Value.MVszA.lppszA[i], str, bufLen-sizeof(char));
                    // Null terminate
                    memcpy(((char *)pv->Value.MVszA.lppszA[i])+(bufLen-sizeof(char)),"\0", sizeof(char));
                }
            }
            PyWinObject_FreeString(str);
            Py_DECREF(obmv);
        }
        break;

    // @flag PT_UNICODE|A string or <o PyUnicode>
    case PT_UNICODE:
    {   // Bit of a hack - need to copy into MAPI block.
        BSTR wstr = NULL;
        ok = PyWinObject_AsBstr(ob, &wstr, FALSE);
        if (ok) {
            DWORD bufSize = sizeof(WCHAR) * (SysStringLen(wstr)+1);
            HRESULT hr = MAPIAllocateMore(bufSize, pAllocMoreLinkBlock, (void **)&pv->Value.lpszW);
            if (S_OK!=hr) {
                OleSetOleError(hr);
                ok = FALSE;
            } else {
                memcpy(pv->Value.lpszW, wstr, bufSize-2);
                // Null terminate
                memcpy(((char *)pv->Value.lpszW)+(bufSize-2),"\0\0", 2);
            }
        }
        SysFreeString(wstr);
        break;
    }

    // @flag PT_MV_UNICODE|A sequence of string or <o PyUnicode>
    case PT_MV_UNICODE:
        ok = AllocMVBuffer( ob, sizeof(char *), pAllocMoreLinkBlock, (void **)&pv->Value.MVszW.lppszW, &pv->Value.MVszW.cValues);
        if (!ok) break;
        for (i=0; ok && !PyErr_Occurred() && i<pv->Value.MVszW.cValues; i++) {
            PyObject *obmv=PySequence_GetItem(ob,i);
            if (obmv==NULL) break;

            BSTR wstr = NULL;
            ok = PyWinObject_AsBstr(obmv, &wstr, FALSE);
            if (ok) {
                DWORD bufSize = sizeof(WCHAR) * (SysStringLen(wstr)+1);
                HRESULT hr = MAPIAllocateMore(bufSize, pAllocMoreLinkBlock, (void **)&pv->Value.MVszW.lppszW[i]);
                if (S_OK!=hr) {
                    OleSetOleError(hr);
                    ok = FALSE;
                } else {
                    memcpy(pv->Value.MVszW.lppszW[i], wstr, bufSize-2);
                    // Null terminate
                    memcpy(((char *)pv->Value.MVszW.lppszW[i])+(bufSize-2),"\0\0", 2);
                }
            }
            SysFreeString(wstr);
            Py_DECREF(obmv);
        }
        break;

    // @flag PT_BINARY|A string containing binary data
    case PT_BINARY:
        pv->Value.bin.lpb = (unsigned char *)PyString_AsString(ob);
        pv->Value.bin.cb = PyString_Size(ob);
        break;

    // @flag PT_MV_BINARY|A sequence of strings containing binary data
    case PT_MV_BINARY:
        ok = AllocMVBuffer( ob, sizeof(SBinary), pAllocMoreLinkBlock, (void **)&pv->Value.MVbin.lpbin, &pv->Value.MVbin.cValues);
        for (i=0; !PyErr_Occurred() && i<pv->Value.MVbin.cValues; i++) {
            PyObject *obmv=PySequence_GetItem(ob,i);
            if (obmv==NULL) break;
            pv->Value.MVbin.lpbin[i].lpb = (unsigned char *)PyString_AsString(ob);
            pv->Value.MVbin.lpbin[i].cb = PyString_Size(ob);
            Py_DECREF(obmv);
        }
        break;

    // @flag PT_CLSID|A <o PyIID>
    case PT_CLSID:
    {
        HRESULT hr = MAPIAllocateMore(sizeof(CLSID), pAllocMoreLinkBlock, (void **)&pv->Value.lpguid);
        if (S_OK != hr) {
            OleSetOleError(hr);
            ok = FALSE;
        } else
            ok = PyWinObject_AsIID(ob, pv->Value.lpguid);
        break;
    }

    // @flag PT_MV_CLSID|A sequence of <o PyIID> objects
    case PT_MV_CLSID:
        MAKEB_MV(CLSID, pAllocMoreLinkBlock, pv->Value.MVguid.lpguid, pv->Value.MVguid.cValues, PyWinObject_AsIID)

    // @flag PT_I8|A <o PyLARGE_INTEGER>
    case PT_I8:
//		case PT_LONGLONG:
        ok = PyWinObject_AsLARGE_INTEGER(ob, &pv->Value.li);
        break;

    // @flag PT_MV_I8|A sequence of <o PyLARGE_INTEGER>
    case PT_MV_I8:
        MAKEB_MV(LARGE_INTEGER, pAllocMoreLinkBlock, pv->Value.MVli.lpli, pv->Value.MVli.cValues, PyWinObject_AsLARGE_INTEGER)

    // @flag PT_ERROR|An integer error code.
    case PT_ERROR:
        pv->Value.err = (SCODE)PyInt_AsLong(ob);
        break;

    // @flag PT_NULL|Anything!
    case PT_NULL:
        pv->Value.x = 0;
        break;

    default: {
        char buf[128];
        sprintf(buf, "Unsupported MAPI property type 0x%X", PROP_TYPE(pv->ulPropTag));
        PyErr_SetString(PyExc_TypeError, buf);
        ok = FALSE;
    }
    }
    ok = (ok && !PyErr_Occurred());
    return ok;
}
Exemplo n.º 3
0
PyObject * dataconv_WriteFromOutTuple(PyObject *self, PyObject *args)
{
	PyObject *obArgTypes;
	PyObject *obArgType;
	PyObject *obRetValues;
	PyObject *obPtr;
	PyObject *obOutValue;
	VARTYPE vtArgType;
	BYTE *pbArgs;
	BYTE *pbArg;
	Py_ssize_t cArgs;
	UINT uiIndirectionLevel = 0;
	Py_ssize_t i;
	
	if (!PyArg_ParseTuple(args, "OOO:WriteFromOutTuple", &obRetValues, &obArgTypes, &obPtr))
		return NULL;

	pbArgs = (BYTE *)PyLong_AsVoidPtr(obPtr);
	assert(pbArgs);
	if (!pbArgs)
		return NULL;

	// Nothing to do, oh darn.
	if (obRetValues == Py_None || obArgTypes == Py_None)
	{
		Py_INCREF(Py_None);
		return Py_None;
	}

	if (!PyTuple_Check(obArgTypes))
	{
		PyErr_SetString(PyExc_TypeError, "OLE type description - expecting a tuple");
		return NULL;
	}

	cArgs = PyTuple_Size(obArgTypes);
	if (!PyTuple_Check(obRetValues) && (UINT)PyTuple_Size(obRetValues) != cArgs)
	{
		PyErr_Format(PyExc_TypeError, "Expecting a tuple of length %d or None.", cArgs);
		return NULL;
	}
	
	for(i = 0 ; i < cArgs; i++)
	{
		obArgType = PyTuple_GET_ITEM(PyTuple_GET_ITEM(obArgTypes, i), 0);
		vtArgType = (VARTYPE)PyInt_AS_LONG(obArgType);


		// The following types aren't supported:
		// SAFEARRAY *: This requires support for SAFEARRAYs as a
		//              Python extensions type so we can update the SAFEARRAY
		//              in place.
		// VT_LPWSTR:   This just hasn't been written yet.
		// VT_LPSTR:    This just hasn't been written yet.
		// VT_LPWSTR | VT_BYREF:
		// VT_LPSTR  | VT_BYREF:
		//              These can't be supported since we don't know the correct
		//              memory allocation policy.

		// Find the start of the argument.
		pbArg = pbArgs + PyInt_AS_LONG(PyTuple_GET_ITEM(PyTuple_GET_ITEM(obArgTypes, i), 1));
		obOutValue = PyTuple_GET_ITEM(obRetValues, i);
	
		if (vtArgType & VT_ARRAY)
		{
			VARENUM rawVT = (VARENUM)(vtArgType & VT_TYPEMASK);
			if (vtArgType & VT_BYREF)
			{
				SAFEARRAY **ppsa = *(SAFEARRAY ***)pbArg;
				SAFEARRAY *psa;
				if (!VALID_BYREF_MISSING(obOutValue))
				{
					if (!PyCom_SAFEARRAYFromPyObject(obOutValue, ppsa, rawVT))
					{
						goto Error;
					}
				}
				else
				{
					SAFEARRAYBOUND rgsabound[1];
					rgsabound[0].lLbound = 0;
					rgsabound[0].cElements = 1;
					psa = SafeArrayCreate(rawVT, 1, rgsabound);
					*ppsa = psa;
				}
			}
			else
			{
				// We can't convert this in place... Ack...
				PyErr_SetString(
					PyExc_TypeError,
					"Inplace SAFEARRAY mucking isn't allowed, doh!");
				goto Error;
				
				SAFEARRAY *psa = *(SAFEARRAY **)pbArg;
				// Here we're updating an existing SafeArray.
				// so we need to handle it very carefully....
				SafeArrayDestroy(psa);
				if (!PyCom_SAFEARRAYFromPyObject(obOutValue, &psa, rawVT))
					return NULL;
			}
		}
			
		// All done with safe array handling.

		PyObject *obUse = NULL;

		switch (vtArgType) {
		case VT_VARIANT | VT_BYREF:
		{
			VARIANT *pvar = *(VARIANT **)pbArg;
			VariantClear(pvar);
			if (!VALID_BYREF_MISSING(obOutValue)) {
				PyCom_VariantFromPyObject(obOutValue, pvar);
			}
			else
			{
				V_VT(pvar) = VT_NULL;
			}
			break;
		}
		case VT_BSTR:
		{
			// This is the normal "BSTR" case, we can't
			// allocate a new BSTR we have to back patch the one
			// thats already there...
			BSTR bstr = *(BSTR *)pbArg;
			BSTR bstrT;
			UINT cch = SysStringLen(bstr);
			if ( PyString_Check(obOutValue) || PyUnicode_Check(obOutValue) )
			{
				if ( !PyWinObject_AsBstr(obOutValue, &bstrT) )
				{
					goto Error;
				}
			}
			else
			{
				// Use str(object) instead!
				obUse = PyObject_Str(obOutValue);
				if (obUse == NULL)
				{
					goto Error;
				}
				if ( !PyWinObject_AsBstr(obUse, &bstrT) )
				{
					goto Error;
				}
			}
			
			if (SysStringLen(bstrT) > cch)
			{
				PyErr_Format(
					PyExc_ValueError,
					"Return value[%d] with type BSTR was "
					"longer than the input value: %d",
					i,
					cch);
				goto Error;
			}
				
			// Ok, now we know theres enough room in the source BSTR to
			// modify the sucker in place.
			wcscpy(bstr, bstrT);

			// Free the temp BSTR.
			SysFreeString(bstrT);
			break;
		}
		case VT_BSTR | VT_BYREF:
		{
			BSTR *pbstr = *(BSTR **)pbArg;
			BSTR bstrT = NULL;
			SysFreeString(*pbstr);

			*pbstr = NULL;
			
			if ( PyString_Check(obOutValue) || PyUnicode_Check(obOutValue) )
			{
				if ( !PyWinObject_AsBstr(obOutValue, &bstrT) )
				{
					goto Error;
				}
			}
			else
			{
				// Use str(object) instead!
				obUse = PyObject_Str(obOutValue);
				if (obUse == NULL)
				{
					goto Error;
				}
				if (!PyWinObject_AsBstr(obUse, &bstrT) )
				{
					goto Error;
				}
			}
			*pbstr = bstrT;
			break;
		}
		case VT_ERROR | VT_BYREF:
		case VT_HRESULT | VT_BYREF:
		case VT_I4 | VT_BYREF:
		{
			INT *pi = *(INT **)pbArg;
			obUse = PyNumber_Int(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*pi = PyInt_AsLong(obUse);
			if (*pi == (UINT)-1 && PyErr_Occurred())
				goto Error;
			break;
		}
		case VT_UI4 | VT_BYREF:
		{
			UINT *pui = *(UINT **)pbArg;
			// special care here as we could be > sys.maxint,
			// in which case we must work with longs.
			// Avoiding PyInt_AsUnsignedLongMask as it doesn't
			// exist in 2.2.
			if (PyLong_Check(obOutValue)) {
				*pui = PyLong_AsUnsignedLong(obOutValue);
			} else {
				// just do the generic "number" thing.
				obUse = PyNumber_Int(obOutValue);
				if (obUse == NULL)
				{
					goto Error;
				}
				*pui = (UINT)PyInt_AsLong(obUse);
			}
			if (*pui == (UINT)-1 && PyErr_Occurred())
				goto Error;
			break;
		}
		case VT_I2 | VT_BYREF:
		{
			short *ps = *(short **)pbArg;
			obUse = PyNumber_Int(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*ps = (short)PyInt_AsLong(obUse);
			if (*ps == (UINT)-1 && PyErr_Occurred())
				goto Error;
			break;
		}
		case VT_UI2 | VT_BYREF:
		{
			unsigned short *pus = *(unsigned short **)pbArg;
			obUse = PyNumber_Int(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*pus = (unsigned short)PyInt_AsLong(obUse);
			if (*pus == (UINT)-1 && PyErr_Occurred())
				goto Error;
			break;
		}
		case VT_I1 | VT_BYREF:
		{
			signed char *pb = *(signed char **)pbArg;
			obUse = PyNumber_Int(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*pb = (signed char)PyInt_AsLong(obUse);
			if (*pb == (UINT)-1 && PyErr_Occurred())
				goto Error;
			break;
		}
		case VT_UI1 | VT_BYREF:
		{
			BYTE *pb = *(BYTE **)pbArg;
			BYTE *pbOutBuffer = NULL;
			if (PyString_Check(obOutValue))
			{
				pbOutBuffer = (BYTE *)PyString_AS_STRING(obOutValue);
				Py_ssize_t cb = PyString_GET_SIZE(obOutValue);
				memcpy(pb, pbOutBuffer, cb);
			}
			// keep this after string check since string can act as buffers
			else if (obOutValue->ob_type->tp_as_buffer)
			{
				DWORD cb;
				if (!PyWinObject_AsReadBuffer(obOutValue, (void **)&pbOutBuffer, &cb))
					goto Error;
				memcpy(pb, pbOutBuffer, cb);
			}
			else
			{
				obUse = PyNumber_Int(obOutValue);
				if (obUse == NULL)
				{
					goto Error;
				}
				*pb = (BYTE)PyInt_AsLong(obUse);
				if (*pb == (UINT)-1 && PyErr_Occurred())
					goto Error;
			}
			break;
		}
		case VT_BOOL | VT_BYREF:
		{
			VARIANT_BOOL *pbool = *(VARIANT_BOOL **)pbArg;
			obUse = PyNumber_Int(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*pbool = PyInt_AsLong(obUse) ? VARIANT_TRUE : VARIANT_FALSE;
			if (*pbool == (UINT)-1 && PyErr_Occurred())
				goto Error;
			break;
		}
		case VT_R8 | VT_BYREF:
		{
			double *pdbl = *(double **)pbArg;
			obUse = PyNumber_Float(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*pdbl = PyFloat_AsDouble(obUse);
			break;
		}
		case VT_R4 | VT_BYREF:
		{
			float *pfloat = *(float **)pbArg;
			obUse = PyNumber_Float(obOutValue);
			if (obUse == NULL)
			{
				goto Error;
			}
			*pfloat = (float)PyFloat_AsDouble(obUse);
			break;
		}
		case VT_DISPATCH | VT_BYREF:
		{
			PyObject *obIID = PyTuple_GET_ITEM(PyTuple_GET_ITEM(obArgTypes, i), 3);
			IID iid = IID_IDispatch;
			if (obIID != NULL && obIID!=Py_None)
				PyWinObject_AsIID(obIID, &iid);
			IDispatch **pdisp = *(IDispatch ***)pbArg;
			if (!PyCom_InterfaceFromPyInstanceOrObject(
				obOutValue,
				iid,
				(void **)pdisp,
				TRUE))
			{
				goto Error;
			}
			// COM Reference added by InterfaceFrom...
			break;
		}
		case VT_UNKNOWN | VT_BYREF:
		{
			PyObject *obIID = PyTuple_GET_ITEM(PyTuple_GET_ITEM(obArgTypes, i), 3);
			IID iid = IID_IUnknown;
			if (obIID != NULL && obIID!=Py_None)
				PyWinObject_AsIID(obIID, &iid);
			IUnknown **punk = *(IUnknown ***)pbArg;
			if (!PyCom_InterfaceFromPyInstanceOrObject(
				obOutValue,
				iid,
				(void **)punk, TRUE))
			{
				goto Error;
			}
			// COM Reference added by InterfaceFrom...
			break;
		}
		case VT_DATE | VT_BYREF:
		{
			DATE *pdbl = *(DATE **)pbArg;
			if ( !PyWinObject_AsDATE(obOutValue, pdbl) )
			{
				goto Error;
			}
			break;
		}
		case VT_CY | VT_BYREF:
		{
			CY *pcy = *(CY **)pbArg;
			if (!PyObject_AsCurrency(obOutValue, pcy))
				goto Error;
			break;
		}
		case VT_I8 | VT_BYREF:
		{
			LARGE_INTEGER *pi64 = *(LARGE_INTEGER **)pbArg;
			if (!PyWinObject_AsLARGE_INTEGER(obOutValue, pi64))
			{
				goto Error;
			}
			break;
		}
		case VT_UI8 | VT_BYREF:
		{
			ULARGE_INTEGER *pui64 = *(ULARGE_INTEGER **)pbArg;
			if (!PyWinObject_AsULARGE_INTEGER(obOutValue, pui64))
			{
				goto Error;
			}
			break;
		}
		default:
			// could try default, but this error indicates we need to
			// beef up the VARIANT support, rather than default.
			PyErr_Format(PyExc_TypeError, "The VARIANT type is unknown (0x%x).",
			             vtArgType);
			goto Error;
		}
		
		Py_XDECREF(obUse);
	}

	Py_INCREF(Py_None);
	return Py_None;
Error:
	return NULL;
}