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