| /* | |
| * Misc marshalling routines | |
| * | |
| * Copyright 2002 Ove Kaaven | |
| * Copyright 2003 Mike Hearn | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winerror.h" | |
| #include "ole2.h" | |
| #include "oleauto.h" | |
| #include "typelib.h" | |
| #include "ocidl.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); | |
| #define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) | |
| #define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) | |
| #define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) | |
| #define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) | |
| /* ole32 exports those, not defined in public headers */ | |
| ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG*, ULONG, ULONG, IUnknown*, REFIID); | |
| unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG*, ULONG, unsigned char*, IUnknown*, REFIID); | |
| unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG*, unsigned char*, IUnknown**, REFIID); | |
| static void dump_user_flags(const ULONG *pFlags) | |
| { | |
| if (HIWORD(*pFlags) == NDR_LOCAL_DATA_REPRESENTATION) | |
| TRACE("MAKELONG(NDR_LOCAL_REPRESENTATION, "); | |
| else | |
| TRACE("MAKELONG(0x%04x, ", HIWORD(*pFlags)); | |
| switch (LOWORD(*pFlags)) | |
| { | |
| case MSHCTX_LOCAL: TRACE("MSHCTX_LOCAL)"); break; | |
| case MSHCTX_NOSHAREDMEM: TRACE("MSHCTX_NOSHAREDMEM)"); break; | |
| case MSHCTX_DIFFERENTMACHINE: TRACE("MSHCTX_DIFFERENTMACHINE)"); break; | |
| case MSHCTX_INPROC: TRACE("MSHCTX_INPROC)"); break; | |
| default: TRACE("%d)", LOWORD(*pFlags)); | |
| } | |
| } | |
| /* CLEANLOCALSTORAGE */ | |
| #define CLS_FUNCDESC 'f' | |
| #define CLS_LIBATTR 'l' | |
| #define CLS_TYPEATTR 't' | |
| #define CLS_VARDESC 'v' | |
| ULONG WINAPI CLEANLOCALSTORAGE_UserSize(ULONG *pFlags, ULONG Start, CLEANLOCALSTORAGE *pstg) | |
| { | |
| ALIGN_LENGTH(Start, 3); | |
| return Start + sizeof(DWORD); | |
| } | |
| unsigned char * WINAPI CLEANLOCALSTORAGE_UserMarshal(ULONG *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstg) | |
| { | |
| ALIGN_POINTER(Buffer, 3); | |
| *(DWORD*)Buffer = pstg->flags; | |
| if (!pstg->pInterface) | |
| return Buffer + sizeof(DWORD); | |
| switch(pstg->flags) | |
| { | |
| case CLS_LIBATTR: | |
| ITypeLib_ReleaseTLibAttr((ITypeLib*)pstg->pInterface, *(TLIBATTR**)pstg->pStorage); | |
| break; | |
| case CLS_TYPEATTR: | |
| ITypeInfo_ReleaseTypeAttr((ITypeInfo*)pstg->pInterface, *(TYPEATTR**)pstg->pStorage); | |
| break; | |
| case CLS_FUNCDESC: | |
| ITypeInfo_ReleaseFuncDesc((ITypeInfo*)pstg->pInterface, *(FUNCDESC**)pstg->pStorage); | |
| break; | |
| case CLS_VARDESC: | |
| ITypeInfo_ReleaseVarDesc((ITypeInfo*)pstg->pInterface, *(VARDESC**)pstg->pStorage); | |
| break; | |
| default: | |
| ERR("Unknown type %x\n", pstg->flags); | |
| } | |
| *(VOID**)pstg->pStorage = NULL; | |
| IUnknown_Release(pstg->pInterface); | |
| pstg->pInterface = NULL; | |
| return Buffer + sizeof(DWORD); | |
| } | |
| unsigned char * WINAPI CLEANLOCALSTORAGE_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstr) | |
| { | |
| ALIGN_POINTER(Buffer, 3); | |
| pstr->flags = *(DWORD*)Buffer; | |
| return Buffer + sizeof(DWORD); | |
| } | |
| void WINAPI CLEANLOCALSTORAGE_UserFree(ULONG *pFlags, CLEANLOCALSTORAGE *pstr) | |
| { | |
| /* Nothing to do */ | |
| } | |
| /* BSTR */ | |
| typedef struct | |
| { | |
| DWORD len; /* No. of chars not including trailing '\0' */ | |
| DWORD byte_len; /* len * 2 or 0xffffffff if len == 0 */ | |
| DWORD len2; /* == len */ | |
| } bstr_wire_t; | |
| ULONG WINAPI BSTR_UserSize(ULONG *pFlags, ULONG Start, BSTR *pstr) | |
| { | |
| TRACE("(%x,%d,%p) => %p\n", *pFlags, Start, pstr, *pstr); | |
| if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); | |
| ALIGN_LENGTH(Start, 3); | |
| Start += sizeof(bstr_wire_t) + ((SysStringByteLen(*pstr) + 1) & ~1); | |
| TRACE("returning %d\n", Start); | |
| return Start; | |
| } | |
| unsigned char * WINAPI BSTR_UserMarshal(ULONG *pFlags, unsigned char *Buffer, BSTR *pstr) | |
| { | |
| bstr_wire_t *header; | |
| DWORD len = SysStringByteLen(*pstr); | |
| TRACE("(%x,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); | |
| if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); | |
| ALIGN_POINTER(Buffer, 3); | |
| header = (bstr_wire_t*)Buffer; | |
| header->len = header->len2 = (len + 1) / 2; | |
| if (*pstr) | |
| { | |
| header->byte_len = len; | |
| memcpy(header + 1, *pstr, header->len * 2); | |
| } | |
| else | |
| header->byte_len = 0xffffffff; /* special case for a null bstr */ | |
| return Buffer + sizeof(*header) + sizeof(OLECHAR) * header->len; | |
| } | |
| unsigned char * WINAPI BSTR_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, BSTR *pstr) | |
| { | |
| bstr_wire_t *header; | |
| TRACE("(%x,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); | |
| ALIGN_POINTER(Buffer, 3); | |
| header = (bstr_wire_t*)Buffer; | |
| if(header->len != header->len2) | |
| FIXME("len %08x != len2 %08x\n", header->len, header->len2); | |
| if (header->byte_len == 0xffffffff) | |
| { | |
| SysFreeString(*pstr); | |
| *pstr = NULL; | |
| } | |
| else SysReAllocStringLen( pstr, (OLECHAR *)(header + 1), header->len ); | |
| if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); | |
| return Buffer + sizeof(*header) + sizeof(OLECHAR) * header->len; | |
| } | |
| void WINAPI BSTR_UserFree(ULONG *pFlags, BSTR *pstr) | |
| { | |
| TRACE("(%x,%p) => %p\n", *pFlags, pstr, *pstr); | |
| SysFreeString(*pstr); | |
| *pstr = NULL; | |
| } | |
| /* VARIANT */ | |
| typedef struct | |
| { | |
| DWORD clSize; | |
| DWORD rpcReserved; | |
| USHORT vt; | |
| USHORT wReserved1; | |
| USHORT wReserved2; | |
| USHORT wReserved3; | |
| DWORD switch_is; | |
| } variant_wire_t; | |
| unsigned int get_type_size(ULONG *pFlags, VARTYPE vt) | |
| { | |
| if (vt & VT_ARRAY) return 4; | |
| switch (vt & ~VT_BYREF) { | |
| case VT_EMPTY: | |
| case VT_NULL: | |
| return 0; | |
| case VT_I1: | |
| case VT_UI1: | |
| return sizeof(CHAR); | |
| case VT_I2: | |
| case VT_UI2: | |
| return sizeof(SHORT); | |
| case VT_I4: | |
| case VT_UI4: | |
| case VT_HRESULT: | |
| return sizeof(LONG); | |
| case VT_INT: | |
| case VT_UINT: | |
| return sizeof(INT); | |
| case VT_R4: | |
| return sizeof(FLOAT); | |
| case VT_R8: | |
| return sizeof(DOUBLE); | |
| case VT_BOOL: | |
| return sizeof(VARIANT_BOOL); | |
| case VT_ERROR: | |
| return sizeof(SCODE); | |
| case VT_DATE: | |
| return sizeof(DATE); | |
| case VT_CY: | |
| return sizeof(CY); | |
| case VT_DECIMAL: | |
| return sizeof(DECIMAL); | |
| case VT_BSTR: | |
| return sizeof(ULONG); | |
| case VT_VARIANT: | |
| return sizeof(VARIANT); | |
| case VT_UNKNOWN: | |
| case VT_DISPATCH: | |
| case VT_RECORD: | |
| return 0; | |
| default: | |
| FIXME("unhandled VT %d\n", vt); | |
| return 0; | |
| } | |
| } | |
| static unsigned int get_type_alignment(ULONG *pFlags, VARTYPE vt) | |
| { | |
| unsigned int size = get_type_size(pFlags, vt); | |
| if(vt & VT_BYREF) return 3; | |
| if(size == 0) return 0; | |
| if(size <= 4) return size - 1; | |
| return 7; | |
| } | |
| /* WdtpInterfacePointer_UserSize takes care of 2 additional DWORDs to store marshalling buffer size */ | |
| static unsigned interface_variant_size(ULONG *pFlags, REFIID riid, IUnknown *punk) | |
| { | |
| ULONG size = 0; | |
| if (punk) | |
| { | |
| size = WdtpInterfacePointer_UserSize(pFlags, LOWORD(*pFlags), 0, punk, riid); | |
| if (!size) | |
| { | |
| ERR("interface variant buffer size calculation failed\n"); | |
| return 0; | |
| } | |
| } | |
| size += sizeof(ULONG); | |
| TRACE("wire-size extra of interface variant is %d\n", size); | |
| return size; | |
| } | |
| static ULONG wire_extra_user_size(ULONG *pFlags, ULONG Start, VARIANT *pvar) | |
| { | |
| if (V_ISARRAY(pvar)) | |
| { | |
| if (V_ISBYREF(pvar)) | |
| return LPSAFEARRAY_UserSize(pFlags, Start, V_ARRAYREF(pvar)); | |
| else | |
| return LPSAFEARRAY_UserSize(pFlags, Start, &V_ARRAY(pvar)); | |
| } | |
| switch (V_VT(pvar)) { | |
| case VT_BSTR: | |
| return BSTR_UserSize(pFlags, Start, &V_BSTR(pvar)); | |
| case VT_BSTR | VT_BYREF: | |
| return BSTR_UserSize(pFlags, Start, V_BSTRREF(pvar)); | |
| case VT_VARIANT | VT_BYREF: | |
| return VARIANT_UserSize(pFlags, Start, V_VARIANTREF(pvar)); | |
| case VT_UNKNOWN: | |
| return Start + interface_variant_size(pFlags, &IID_IUnknown, V_UNKNOWN(pvar)); | |
| case VT_UNKNOWN | VT_BYREF: | |
| return Start + interface_variant_size(pFlags, &IID_IUnknown, *V_UNKNOWNREF(pvar)); | |
| case VT_DISPATCH: | |
| return Start + interface_variant_size(pFlags, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar)); | |
| case VT_DISPATCH | VT_BYREF: | |
| return Start + interface_variant_size(pFlags, &IID_IDispatch, (IUnknown*)*V_DISPATCHREF(pvar)); | |
| case VT_RECORD: | |
| FIXME("wire-size record\n"); | |
| return Start; | |
| case VT_SAFEARRAY: | |
| case VT_SAFEARRAY | VT_BYREF: | |
| FIXME("wire-size safearray: shouldn't be marshaling this\n"); | |
| return Start; | |
| default: | |
| return Start; | |
| } | |
| } | |
| /* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer */ | |
| static unsigned char* interface_variant_marshal(ULONG *pFlags, unsigned char *Buffer, | |
| REFIID riid, IUnknown *punk) | |
| { | |
| TRACE("pFlags=%d, Buffer=%p, pUnk=%p\n", *pFlags, Buffer, punk); | |
| /* first DWORD is used to store pointer itself, truncated on win64 */ | |
| if(!punk) | |
| { | |
| memset(Buffer, 0, sizeof(ULONG)); | |
| return Buffer + sizeof(ULONG); | |
| } | |
| else | |
| { | |
| *(DWORD*)Buffer = (DWORD_PTR)punk; | |
| Buffer += sizeof(DWORD); | |
| } | |
| return WdtpInterfacePointer_UserMarshal(pFlags, LOWORD(*pFlags), Buffer, punk, riid); | |
| } | |
| /* helper: called for VT_DISPATCH / VT_UNKNOWN variants to unmarshal the buffer */ | |
| static unsigned char *interface_variant_unmarshal(ULONG *pFlags, unsigned char *Buffer, | |
| REFIID riid, IUnknown **ppunk) | |
| { | |
| DWORD ptr; | |
| TRACE("pFlags=%d, Buffer=%p, ppUnk=%p\n", *pFlags, Buffer, ppunk); | |
| /* skip pointer part itself */ | |
| ptr = *(DWORD*)Buffer; | |
| Buffer += sizeof(DWORD); | |
| if(!ptr) | |
| return Buffer; | |
| return WdtpInterfacePointer_UserUnmarshal(pFlags, Buffer, ppunk, riid); | |
| } | |
| ULONG WINAPI VARIANT_UserSize(ULONG *pFlags, ULONG Start, VARIANT *pvar) | |
| { | |
| int align; | |
| TRACE("(%x,%d,%p)\n", *pFlags, Start, pvar); | |
| TRACE("vt=%04x\n", V_VT(pvar)); | |
| ALIGN_LENGTH(Start, 7); | |
| Start += sizeof(variant_wire_t); | |
| if(V_VT(pvar) & VT_BYREF) | |
| Start += 4; | |
| align = get_type_alignment(pFlags, V_VT(pvar)); | |
| ALIGN_LENGTH(Start, align); | |
| if(V_VT(pvar) == (VT_VARIANT | VT_BYREF)) | |
| Start += 4; | |
| else | |
| Start += get_type_size(pFlags, V_VT(pvar)); | |
| Start = wire_extra_user_size(pFlags, Start, pvar); | |
| TRACE("returning %d\n", Start); | |
| return Start; | |
| } | |
| unsigned char * WINAPI VARIANT_UserMarshal(ULONG *pFlags, unsigned char *Buffer, VARIANT *pvar) | |
| { | |
| variant_wire_t *header; | |
| ULONG type_size; | |
| int align; | |
| unsigned char *Pos; | |
| TRACE("(%x,%p,%p)\n", *pFlags, Buffer, pvar); | |
| TRACE("vt=%04x\n", V_VT(pvar)); | |
| ALIGN_POINTER(Buffer, 7); | |
| header = (variant_wire_t *)Buffer; | |
| header->clSize = 0; /* fixed up at the end */ | |
| header->rpcReserved = 0; | |
| header->vt = pvar->n1.n2.vt; | |
| header->wReserved1 = pvar->n1.n2.wReserved1; | |
| header->wReserved2 = pvar->n1.n2.wReserved2; | |
| header->wReserved3 = pvar->n1.n2.wReserved3; | |
| header->switch_is = pvar->n1.n2.vt; | |
| if(header->switch_is & VT_ARRAY) | |
| header->switch_is &= ~VT_TYPEMASK; | |
| Pos = (unsigned char*)(header + 1); | |
| type_size = get_type_size(pFlags, V_VT(pvar)); | |
| align = get_type_alignment(pFlags, V_VT(pvar)); | |
| ALIGN_POINTER(Pos, align); | |
| if(header->vt & VT_BYREF) | |
| { | |
| *(DWORD *)Pos = max(type_size, 4); | |
| Pos += 4; | |
| if((header->vt & VT_TYPEMASK) != VT_VARIANT) | |
| { | |
| memcpy(Pos, pvar->n1.n2.n3.byref, type_size); | |
| Pos += type_size; | |
| } | |
| else | |
| { | |
| *(DWORD*)Pos = 'U' | 's' << 8 | 'e' << 16 | 'r' << 24; | |
| Pos += 4; | |
| } | |
| } | |
| else | |
| { | |
| if((header->vt & VT_TYPEMASK) == VT_DECIMAL) | |
| memcpy(Pos, pvar, type_size); | |
| else | |
| memcpy(Pos, &pvar->n1.n2.n3, type_size); | |
| Pos += type_size; | |
| } | |
| if(header->vt & VT_ARRAY) | |
| { | |
| if(header->vt & VT_BYREF) | |
| Pos = LPSAFEARRAY_UserMarshal(pFlags, Pos, V_ARRAYREF(pvar)); | |
| else | |
| Pos = LPSAFEARRAY_UserMarshal(pFlags, Pos, &V_ARRAY(pvar)); | |
| } | |
| else | |
| { | |
| switch (header->vt) | |
| { | |
| case VT_BSTR: | |
| Pos = BSTR_UserMarshal(pFlags, Pos, &V_BSTR(pvar)); | |
| break; | |
| case VT_BSTR | VT_BYREF: | |
| Pos = BSTR_UserMarshal(pFlags, Pos, V_BSTRREF(pvar)); | |
| break; | |
| case VT_VARIANT | VT_BYREF: | |
| Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar)); | |
| break; | |
| case VT_UNKNOWN: | |
| Pos = interface_variant_marshal(pFlags, Pos, &IID_IUnknown, V_UNKNOWN(pvar)); | |
| break; | |
| case VT_UNKNOWN | VT_BYREF: | |
| Pos = interface_variant_marshal(pFlags, Pos, &IID_IUnknown, *V_UNKNOWNREF(pvar)); | |
| break; | |
| case VT_DISPATCH: | |
| Pos = interface_variant_marshal(pFlags, Pos, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar)); | |
| break; | |
| case VT_DISPATCH | VT_BYREF: | |
| Pos = interface_variant_marshal(pFlags, Pos, &IID_IDispatch, (IUnknown*)*V_DISPATCHREF(pvar)); | |
| break; | |
| case VT_RECORD: | |
| FIXME("handle BRECORD by val\n"); | |
| break; | |
| case VT_RECORD | VT_BYREF: | |
| FIXME("handle BRECORD by ref\n"); | |
| break; | |
| } | |
| } | |
| header->clSize = ((Pos - Buffer) + 7) >> 3; | |
| TRACE("marshalled size=%d\n", header->clSize); | |
| return Pos; | |
| } | |
| unsigned char * WINAPI VARIANT_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, VARIANT *pvar) | |
| { | |
| variant_wire_t *header; | |
| ULONG type_size; | |
| int align; | |
| unsigned char *Pos; | |
| TRACE("(%x,%p,%p)\n", *pFlags, Buffer, pvar); | |
| ALIGN_POINTER(Buffer, 7); | |
| header = (variant_wire_t *)Buffer; | |
| Pos = (unsigned char*)(header + 1); | |
| type_size = get_type_size(pFlags, header->vt); | |
| align = get_type_alignment(pFlags, header->vt); | |
| ALIGN_POINTER(Pos, align); | |
| if(header->vt & VT_BYREF) | |
| { | |
| ULONG mem_size; | |
| Pos += 4; | |
| switch (header->vt & ~VT_BYREF) | |
| { | |
| /* these types have a different memory size compared to wire size */ | |
| case VT_UNKNOWN: | |
| case VT_DISPATCH: | |
| case VT_BSTR: | |
| mem_size = sizeof(void *); | |
| break; | |
| default: | |
| mem_size = type_size; | |
| break; | |
| } | |
| if (V_VT(pvar) != header->vt) | |
| { | |
| VariantClear(pvar); | |
| V_BYREF(pvar) = CoTaskMemAlloc(mem_size); | |
| memset(V_BYREF(pvar), 0, mem_size); | |
| } | |
| else if (!V_BYREF(pvar)) | |
| { | |
| V_BYREF(pvar) = CoTaskMemAlloc(mem_size); | |
| memset(V_BYREF(pvar), 0, mem_size); | |
| } | |
| if(!(header->vt & VT_ARRAY) | |
| && (header->vt & VT_TYPEMASK) != VT_BSTR | |
| && (header->vt & VT_TYPEMASK) != VT_VARIANT | |
| && (header->vt & VT_TYPEMASK) != VT_UNKNOWN | |
| && (header->vt & VT_TYPEMASK) != VT_DISPATCH | |
| && (header->vt & VT_TYPEMASK) != VT_RECORD) | |
| memcpy(V_BYREF(pvar), Pos, type_size); | |
| if((header->vt & VT_TYPEMASK) != VT_VARIANT) | |
| Pos += type_size; | |
| else | |
| Pos += 4; | |
| } | |
| else | |
| { | |
| VariantClear(pvar); | |
| if(header->vt & VT_ARRAY) | |
| V_ARRAY(pvar) = NULL; | |
| else if((header->vt & VT_TYPEMASK) == VT_BSTR) | |
| V_BSTR(pvar) = NULL; | |
| else if((header->vt & VT_TYPEMASK) == VT_UNKNOWN) | |
| V_UNKNOWN(pvar) = NULL; | |
| else if((header->vt & VT_TYPEMASK) == VT_DISPATCH) | |
| V_DISPATCH(pvar) = NULL; | |
| else if((header->vt & VT_TYPEMASK) == VT_RECORD) | |
| V_RECORD(pvar) = NULL; | |
| else if((header->vt & VT_TYPEMASK) == VT_DECIMAL) | |
| memcpy(pvar, Pos, type_size); | |
| else | |
| memcpy(&pvar->n1.n2.n3, Pos, type_size); | |
| Pos += type_size; | |
| } | |
| pvar->n1.n2.vt = header->vt; | |
| pvar->n1.n2.wReserved1 = header->wReserved1; | |
| pvar->n1.n2.wReserved2 = header->wReserved2; | |
| pvar->n1.n2.wReserved3 = header->wReserved3; | |
| if(header->vt & VT_ARRAY) | |
| { | |
| if(header->vt & VT_BYREF) | |
| Pos = LPSAFEARRAY_UserUnmarshal(pFlags, Pos, V_ARRAYREF(pvar)); | |
| else | |
| Pos = LPSAFEARRAY_UserUnmarshal(pFlags, Pos, &V_ARRAY(pvar)); | |
| } | |
| else | |
| { | |
| switch (header->vt) | |
| { | |
| case VT_BSTR: | |
| Pos = BSTR_UserUnmarshal(pFlags, Pos, &V_BSTR(pvar)); | |
| break; | |
| case VT_BSTR | VT_BYREF: | |
| Pos = BSTR_UserUnmarshal(pFlags, Pos, V_BSTRREF(pvar)); | |
| break; | |
| case VT_VARIANT | VT_BYREF: | |
| Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar)); | |
| break; | |
| case VT_UNKNOWN: | |
| Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IUnknown, &V_UNKNOWN(pvar)); | |
| break; | |
| case VT_UNKNOWN | VT_BYREF: | |
| Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IUnknown, V_UNKNOWNREF(pvar)); | |
| break; | |
| case VT_DISPATCH: | |
| Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IDispatch, (IUnknown**)&V_DISPATCH(pvar)); | |
| break; | |
| case VT_DISPATCH | VT_BYREF: | |
| Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IDispatch, (IUnknown**)V_DISPATCHREF(pvar)); | |
| break; | |
| case VT_RECORD: | |
| FIXME("handle BRECORD by val\n"); | |
| break; | |
| case VT_RECORD | VT_BYREF: | |
| FIXME("handle BRECORD by ref\n"); | |
| break; | |
| } | |
| } | |
| return Pos; | |
| } | |
| void WINAPI VARIANT_UserFree(ULONG *pFlags, VARIANT *pvar) | |
| { | |
| VARTYPE vt = V_VT(pvar); | |
| PVOID ref = NULL; | |
| TRACE("(%x,%p)\n", *pFlags, pvar); | |
| TRACE("vt=%04x\n", V_VT(pvar)); | |
| if (vt & VT_BYREF) ref = pvar->n1.n2.n3.byref; | |
| VariantClear(pvar); | |
| if (!ref) return; | |
| if(vt & VT_ARRAY) | |
| { | |
| if (vt & VT_BYREF) | |
| LPSAFEARRAY_UserFree(pFlags, V_ARRAYREF(pvar)); | |
| else | |
| LPSAFEARRAY_UserFree(pFlags, &V_ARRAY(pvar)); | |
| } | |
| else | |
| { | |
| switch (vt) | |
| { | |
| case VT_BSTR | VT_BYREF: | |
| BSTR_UserFree(pFlags, V_BSTRREF(pvar)); | |
| break; | |
| case VT_VARIANT | VT_BYREF: | |
| VARIANT_UserFree(pFlags, V_VARIANTREF(pvar)); | |
| break; | |
| case VT_RECORD | VT_BYREF: | |
| FIXME("handle BRECORD by ref\n"); | |
| break; | |
| case VT_UNKNOWN | VT_BYREF: | |
| case VT_DISPATCH | VT_BYREF: | |
| IUnknown_Release(*V_UNKNOWNREF(pvar)); | |
| break; | |
| } | |
| } | |
| CoTaskMemFree(ref); | |
| } | |
| /* LPSAFEARRAY */ | |
| /* Get the number of cells in a SafeArray */ | |
| static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa) | |
| { | |
| const SAFEARRAYBOUND* psab = psa->rgsabound; | |
| USHORT cCount = psa->cDims; | |
| ULONG ulNumCells = 1; | |
| while (cCount--) | |
| { | |
| /* This is a valid bordercase. See testcases. -Marcus */ | |
| if (!psab->cElements) | |
| return 0; | |
| ulNumCells *= psab->cElements; | |
| psab++; | |
| } | |
| return ulNumCells; | |
| } | |
| static inline SF_TYPE SAFEARRAY_GetUnionType(SAFEARRAY *psa) | |
| { | |
| VARTYPE vt; | |
| HRESULT hr; | |
| hr = SafeArrayGetVartype(psa, &vt); | |
| if (FAILED(hr)) | |
| { | |
| if(psa->fFeatures & FADF_VARIANT) return SF_VARIANT; | |
| switch(psa->cbElements) | |
| { | |
| case 1: vt = VT_I1; break; | |
| case 2: vt = VT_I2; break; | |
| case 4: vt = VT_I4; break; | |
| case 8: vt = VT_I8; break; | |
| default: | |
| RpcRaiseException(hr); | |
| } | |
| } | |
| if (psa->fFeatures & FADF_HAVEIID) | |
| return SF_HAVEIID; | |
| switch (vt) | |
| { | |
| case VT_I1: | |
| case VT_UI1: return SF_I1; | |
| case VT_BOOL: | |
| case VT_I2: | |
| case VT_UI2: return SF_I2; | |
| case VT_INT: | |
| case VT_UINT: | |
| case VT_I4: | |
| case VT_UI4: | |
| case VT_R4: return SF_I4; | |
| case VT_DATE: | |
| case VT_CY: | |
| case VT_R8: | |
| case VT_I8: | |
| case VT_UI8: return SF_I8; | |
| case VT_INT_PTR: | |
| case VT_UINT_PTR: return (sizeof(UINT_PTR) == 4 ? SF_I4 : SF_I8); | |
| case VT_BSTR: return SF_BSTR; | |
| case VT_DISPATCH: return SF_DISPATCH; | |
| case VT_VARIANT: return SF_VARIANT; | |
| case VT_UNKNOWN: return SF_UNKNOWN; | |
| /* Note: Return a non-zero size to indicate vt is valid. The actual size | |
| * of a UDT is taken from the result of IRecordInfo_GetSize(). | |
| */ | |
| case VT_RECORD: return SF_RECORD; | |
| default: return SF_ERROR; | |
| } | |
| } | |
| static DWORD elem_wire_size(LPSAFEARRAY lpsa, SF_TYPE sftype) | |
| { | |
| if (sftype == SF_BSTR) | |
| return sizeof(DWORD); | |
| else if (sftype == SF_VARIANT) | |
| return sizeof(variant_wire_t) - sizeof(DWORD); | |
| else | |
| return lpsa->cbElements; | |
| } | |
| static DWORD elem_mem_size(wireSAFEARRAY wiresa, SF_TYPE sftype) | |
| { | |
| if (sftype == SF_BSTR) | |
| return sizeof(BSTR); | |
| else if (sftype == SF_VARIANT) | |
| return sizeof(VARIANT); | |
| else | |
| return wiresa->cbElements; | |
| } | |
| ULONG WINAPI LPSAFEARRAY_UserSize(ULONG *pFlags, ULONG StartingSize, LPSAFEARRAY *ppsa) | |
| { | |
| ULONG size = StartingSize; | |
| TRACE("("); dump_user_flags(pFlags); TRACE(", %d, %p\n", StartingSize, *ppsa); | |
| ALIGN_LENGTH(size, 3); | |
| size += sizeof(ULONG); | |
| if (*ppsa) | |
| { | |
| SAFEARRAY *psa = *ppsa; | |
| ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); | |
| SF_TYPE sftype; | |
| HRESULT hr; | |
| size += sizeof(ULONG); | |
| size += 2 * sizeof(USHORT) + 2 * sizeof(ULONG); | |
| sftype = SAFEARRAY_GetUnionType(psa); | |
| size += sizeof(ULONG); | |
| size += sizeof(ULONG); | |
| size += sizeof(ULONG); | |
| if (sftype == SF_HAVEIID) | |
| size += sizeof(IID); | |
| size += sizeof(psa->rgsabound[0]) * psa->cDims; | |
| size += sizeof(ULONG); | |
| switch (sftype) | |
| { | |
| case SF_BSTR: | |
| { | |
| BSTR* lpBstr; | |
| for (lpBstr = psa->pvData; ulCellCount; ulCellCount--, lpBstr++) | |
| size = BSTR_UserSize(pFlags, size, lpBstr); | |
| break; | |
| } | |
| case SF_DISPATCH: | |
| case SF_UNKNOWN: | |
| case SF_HAVEIID: | |
| FIXME("size interfaces\n"); | |
| break; | |
| case SF_VARIANT: | |
| { | |
| VARIANT* lpVariant; | |
| for (lpVariant = psa->pvData; ulCellCount; ulCellCount--, lpVariant++) | |
| size = VARIANT_UserSize(pFlags, size, lpVariant); | |
| break; | |
| } | |
| case SF_RECORD: | |
| { | |
| IRecordInfo* pRecInfo = NULL; | |
| hr = SafeArrayGetRecordInfo(psa, &pRecInfo); | |
| if (FAILED(hr)) | |
| RpcRaiseException(hr); | |
| if (pRecInfo) | |
| { | |
| FIXME("size record info %p\n", pRecInfo); | |
| IRecordInfo_Release(pRecInfo); | |
| } | |
| break; | |
| } | |
| case SF_I8: | |
| ALIGN_LENGTH(size, 7); | |
| /* fallthrough */ | |
| case SF_I1: | |
| case SF_I2: | |
| case SF_I4: | |
| size += ulCellCount * psa->cbElements; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| return size; | |
| } | |
| unsigned char * WINAPI LPSAFEARRAY_UserMarshal(ULONG *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa) | |
| { | |
| HRESULT hr; | |
| TRACE("("); dump_user_flags(pFlags); TRACE(", %p, &%p\n", Buffer, *ppsa); | |
| ALIGN_POINTER(Buffer, 3); | |
| *(ULONG *)Buffer = *ppsa ? 0x1 : 0x0; | |
| Buffer += sizeof(ULONG); | |
| if (*ppsa) | |
| { | |
| VARTYPE vt; | |
| SAFEARRAY *psa = *ppsa; | |
| ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); | |
| SAFEARRAYBOUND *bound; | |
| SF_TYPE sftype; | |
| GUID guid; | |
| INT i; | |
| sftype = SAFEARRAY_GetUnionType(psa); | |
| *(ULONG *)Buffer = psa->cDims; | |
| Buffer += sizeof(ULONG); | |
| *(USHORT *)Buffer = psa->cDims; | |
| Buffer += sizeof(USHORT); | |
| *(USHORT *)Buffer = psa->fFeatures; | |
| Buffer += sizeof(USHORT); | |
| *(ULONG *)Buffer = elem_wire_size(psa, sftype); | |
| Buffer += sizeof(ULONG); | |
| hr = SafeArrayGetVartype(psa, &vt); | |
| if (FAILED(hr)) vt = 0; | |
| *(ULONG *)Buffer = (USHORT)psa->cLocks | (vt << 16); | |
| Buffer += sizeof(ULONG); | |
| *(ULONG *)Buffer = sftype; | |
| Buffer += sizeof(ULONG); | |
| *(ULONG *)Buffer = ulCellCount; | |
| Buffer += sizeof(ULONG); | |
| *(ULONG *)Buffer = psa->pvData ? 0x2 : 0x0; | |
| Buffer += sizeof(ULONG); | |
| if (sftype == SF_HAVEIID) | |
| { | |
| SafeArrayGetIID(psa, &guid); | |
| memcpy(Buffer, &guid, sizeof(guid)); | |
| Buffer += sizeof(guid); | |
| } | |
| /* bounds are marshaled in opposite order comparing to storage layout */ | |
| bound = (SAFEARRAYBOUND*)Buffer; | |
| for (i = 0; i < psa->cDims; i++) | |
| { | |
| memcpy(bound++, &psa->rgsabound[psa->cDims-i-1], sizeof(psa->rgsabound[0])); | |
| } | |
| Buffer += sizeof(psa->rgsabound[0]) * psa->cDims; | |
| *(ULONG *)Buffer = ulCellCount; | |
| Buffer += sizeof(ULONG); | |
| if (psa->pvData) | |
| { | |
| switch (sftype) | |
| { | |
| case SF_BSTR: | |
| { | |
| BSTR* lpBstr; | |
| for (lpBstr = psa->pvData; ulCellCount; ulCellCount--, lpBstr++) | |
| Buffer = BSTR_UserMarshal(pFlags, Buffer, lpBstr); | |
| break; | |
| } | |
| case SF_DISPATCH: | |
| case SF_UNKNOWN: | |
| case SF_HAVEIID: | |
| FIXME("marshal interfaces\n"); | |
| break; | |
| case SF_VARIANT: | |
| { | |
| VARIANT* lpVariant; | |
| for (lpVariant = psa->pvData; ulCellCount; ulCellCount--, lpVariant++) | |
| Buffer = VARIANT_UserMarshal(pFlags, Buffer, lpVariant); | |
| break; | |
| } | |
| case SF_RECORD: | |
| { | |
| IRecordInfo* pRecInfo = NULL; | |
| hr = SafeArrayGetRecordInfo(psa, &pRecInfo); | |
| if (FAILED(hr)) | |
| RpcRaiseException(hr); | |
| if (pRecInfo) | |
| { | |
| FIXME("write record info %p\n", pRecInfo); | |
| IRecordInfo_Release(pRecInfo); | |
| } | |
| break; | |
| } | |
| case SF_I8: | |
| ALIGN_POINTER(Buffer, 7); | |
| /* fallthrough */ | |
| case SF_I1: | |
| case SF_I2: | |
| case SF_I4: | |
| /* Just copy the data over */ | |
| memcpy(Buffer, psa->pvData, ulCellCount * psa->cbElements); | |
| Buffer += ulCellCount * psa->cbElements; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| return Buffer; | |
| } | |
| #define FADF_AUTOSETFLAGS (FADF_HAVEIID | FADF_RECORD | FADF_HAVEVARTYPE | \ | |
| FADF_BSTR | FADF_UNKNOWN | FADF_DISPATCH | \ | |
| FADF_VARIANT | FADF_CREATEVECTOR) | |
| unsigned char * WINAPI LPSAFEARRAY_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, LPSAFEARRAY *ppsa) | |
| { | |
| ULONG ptr; | |
| wireSAFEARRAY wiresa; | |
| ULONG cDims; | |
| HRESULT hr; | |
| SF_TYPE sftype; | |
| ULONG cell_count; | |
| GUID guid; | |
| VARTYPE vt; | |
| SAFEARRAYBOUND *wiresab; | |
| TRACE("("); dump_user_flags(pFlags); TRACE(", %p, %p\n", Buffer, ppsa); | |
| ALIGN_POINTER(Buffer, 3); | |
| ptr = *(ULONG *)Buffer; | |
| Buffer += sizeof(ULONG); | |
| if (!ptr) | |
| { | |
| SafeArrayDestroy(*ppsa); | |
| *ppsa = NULL; | |
| TRACE("NULL safe array unmarshaled\n"); | |
| return Buffer; | |
| } | |
| cDims = *(ULONG *)Buffer; | |
| Buffer += sizeof(ULONG); | |
| wiresa = (wireSAFEARRAY)Buffer; | |
| Buffer += 2 * sizeof(USHORT) + 2 * sizeof(ULONG); | |
| if (cDims != wiresa->cDims) | |
| RpcRaiseException(RPC_S_INVALID_BOUND); | |
| /* FIXME: there should be a limit on how large cDims can be */ | |
| vt = HIWORD(wiresa->cLocks); | |
| sftype = *(ULONG *)Buffer; | |
| Buffer += sizeof(ULONG); | |
| cell_count = *(ULONG *)Buffer; | |
| Buffer += sizeof(ULONG); | |
| ptr = *(ULONG *)Buffer; | |
| Buffer += sizeof(ULONG); | |
| if (sftype == SF_HAVEIID) | |
| { | |
| memcpy(&guid, Buffer, sizeof(guid)); | |
| Buffer += sizeof(guid); | |
| } | |
| wiresab = (SAFEARRAYBOUND *)Buffer; | |
| Buffer += sizeof(wiresab[0]) * wiresa->cDims; | |
| if(*ppsa && (*ppsa)->cDims==wiresa->cDims) | |
| { | |
| if(((*ppsa)->fFeatures & ~FADF_AUTOSETFLAGS) != (wiresa->fFeatures & ~FADF_AUTOSETFLAGS)) | |
| RpcRaiseException(DISP_E_BADCALLEE); | |
| if(SAFEARRAY_GetCellCount(*ppsa)*(*ppsa)->cbElements != cell_count*elem_mem_size(wiresa, sftype)) | |
| { | |
| if((*ppsa)->fFeatures & (FADF_AUTO|FADF_STATIC|FADF_EMBEDDED|FADF_FIXEDSIZE)) | |
| RpcRaiseException(DISP_E_BADCALLEE); | |
| hr = SafeArrayDestroyData(*ppsa); | |
| if(FAILED(hr)) | |
| RpcRaiseException(hr); | |
| } | |
| memcpy((*ppsa)->rgsabound, wiresab, sizeof(*wiresab)*wiresa->cDims); | |
| if((*ppsa)->fFeatures & FADF_HAVEVARTYPE) | |
| ((DWORD*)(*ppsa))[-1] = vt; | |
| } | |
| else if(vt) | |
| { | |
| SafeArrayDestroy(*ppsa); | |
| *ppsa = SafeArrayCreateEx(vt, wiresa->cDims, wiresab, NULL); | |
| if (!*ppsa) RpcRaiseException(E_OUTOFMEMORY); | |
| } | |
| else | |
| { | |
| SafeArrayDestroy(*ppsa); | |
| if (FAILED(SafeArrayAllocDescriptor(wiresa->cDims, ppsa))) | |
| RpcRaiseException(E_OUTOFMEMORY); | |
| memcpy((*ppsa)->rgsabound, wiresab, sizeof(SAFEARRAYBOUND) * wiresa->cDims); | |
| } | |
| /* be careful about which flags we set since they could be a security | |
| * risk */ | |
| (*ppsa)->fFeatures &= FADF_AUTOSETFLAGS; | |
| (*ppsa)->fFeatures |= (wiresa->fFeatures & ~(FADF_AUTOSETFLAGS)); | |
| /* FIXME: there should be a limit on how large wiresa->cbElements can be */ | |
| (*ppsa)->cbElements = elem_mem_size(wiresa, sftype); | |
| /* SafeArrayCreateEx allocates the data for us, but | |
| * SafeArrayAllocDescriptor doesn't */ | |
| if(!(*ppsa)->pvData) | |
| { | |
| hr = SafeArrayAllocData(*ppsa); | |
| if (FAILED(hr)) | |
| RpcRaiseException(hr); | |
| } | |
| if ((*(ULONG *)Buffer != cell_count) || (SAFEARRAY_GetCellCount(*ppsa) != cell_count)) | |
| RpcRaiseException(RPC_S_INVALID_BOUND); | |
| Buffer += sizeof(ULONG); | |
| if (ptr) | |
| { | |
| switch (sftype) | |
| { | |
| case SF_BSTR: | |
| { | |
| BSTR* lpBstr; | |
| for (lpBstr = (*ppsa)->pvData; cell_count; cell_count--, lpBstr++) | |
| Buffer = BSTR_UserUnmarshal(pFlags, Buffer, lpBstr); | |
| break; | |
| } | |
| case SF_DISPATCH: | |
| case SF_UNKNOWN: | |
| case SF_HAVEIID: | |
| FIXME("marshal interfaces\n"); | |
| break; | |
| case SF_VARIANT: | |
| { | |
| VARIANT* lpVariant; | |
| for (lpVariant = (*ppsa)->pvData; cell_count; cell_count--, lpVariant++) | |
| Buffer = VARIANT_UserUnmarshal(pFlags, Buffer, lpVariant); | |
| break; | |
| } | |
| case SF_RECORD: | |
| { | |
| FIXME("set record info\n"); | |
| break; | |
| } | |
| case SF_I8: | |
| ALIGN_POINTER(Buffer, 7); | |
| /* fallthrough */ | |
| case SF_I1: | |
| case SF_I2: | |
| case SF_I4: | |
| /* Just copy the data over */ | |
| memcpy((*ppsa)->pvData, Buffer, cell_count * (*ppsa)->cbElements); | |
| Buffer += cell_count * (*ppsa)->cbElements; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| TRACE("safe array unmarshaled: %p\n", *ppsa); | |
| return Buffer; | |
| } | |
| void WINAPI LPSAFEARRAY_UserFree(ULONG *pFlags, LPSAFEARRAY *ppsa) | |
| { | |
| TRACE("("); dump_user_flags(pFlags); TRACE(", &%p\n", *ppsa); | |
| SafeArrayDestroy(*ppsa); | |
| *ppsa = NULL; | |
| } | |
| ULONG WINAPI HFONT_UserSize(ULONG *pFlags, ULONG Start, HFONT *phfont) | |
| { | |
| FIXME(":stub\n"); | |
| return 0; | |
| } | |
| unsigned char * WINAPI HFONT_UserMarshal(ULONG *pFlags, unsigned char *Buffer, HFONT *phfont) | |
| { | |
| FIXME(":stub\n"); | |
| return NULL; | |
| } | |
| unsigned char * WINAPI HFONT_UserUnmarshal(ULONG *pFlags, unsigned char *Buffer, HFONT *phfont) | |
| { | |
| FIXME(":stub\n"); | |
| return NULL; | |
| } | |
| void WINAPI HFONT_UserFree(ULONG *pFlags, HFONT *phfont) | |
| { | |
| FIXME(":stub\n"); | |
| return; | |
| } | |
| /* IDispatch */ | |
| /* exactly how Invoke is marshalled is not very clear to me yet, | |
| * but the way I've done it seems to work for me */ | |
| HRESULT CALLBACK IDispatch_Invoke_Proxy( | |
| IDispatch* This, | |
| DISPID dispIdMember, | |
| REFIID riid, | |
| LCID lcid, | |
| WORD wFlags, | |
| DISPPARAMS* pDispParams, | |
| VARIANT* pVarResult, | |
| EXCEPINFO* pExcepInfo, | |
| UINT* puArgErr) | |
| { | |
| HRESULT hr; | |
| VARIANT VarResult; | |
| UINT* rgVarRefIdx = NULL; | |
| VARIANTARG* rgVarRef = NULL; | |
| UINT u, cVarRef; | |
| UINT uArgErr; | |
| EXCEPINFO ExcepInfo; | |
| TRACE("(%p)->(%d,%s,%x,%x,%p,%p,%p,%p)\n", This, | |
| dispIdMember, debugstr_guid(riid), | |
| lcid, wFlags, pDispParams, pVarResult, | |
| pExcepInfo, puArgErr); | |
| /* [out] args can't be null, use dummy vars if needed */ | |
| if (!pVarResult) pVarResult = &VarResult; | |
| if (!puArgErr) puArgErr = &uArgErr; | |
| if (!pExcepInfo) pExcepInfo = &ExcepInfo; | |
| /* count by-ref args */ | |
| for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) { | |
| VARIANTARG* arg = &pDispParams->rgvarg[u]; | |
| if (V_ISBYREF(arg)) { | |
| cVarRef++; | |
| } | |
| } | |
| if (cVarRef) { | |
| rgVarRefIdx = CoTaskMemAlloc(sizeof(UINT)*cVarRef); | |
| rgVarRef = CoTaskMemAlloc(sizeof(VARIANTARG)*cVarRef); | |
| /* make list of by-ref args */ | |
| for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) { | |
| VARIANTARG* arg = &pDispParams->rgvarg[u]; | |
| if (V_ISBYREF(arg)) { | |
| rgVarRefIdx[cVarRef] = u; | |
| VariantInit(&rgVarRef[cVarRef]); | |
| VariantCopy(&rgVarRef[cVarRef], arg); | |
| VariantClear(arg); | |
| cVarRef++; | |
| } | |
| } | |
| } else { | |
| /* [out] args still can't be null, | |
| * but we can point these anywhere in this case, | |
| * since they won't be written to when cVarRef is 0 */ | |
| rgVarRefIdx = puArgErr; | |
| rgVarRef = pVarResult; | |
| } | |
| TRACE("passed by ref: %d args\n", cVarRef); | |
| hr = IDispatch_RemoteInvoke_Proxy(This, | |
| dispIdMember, | |
| riid, | |
| lcid, | |
| wFlags, | |
| pDispParams, | |
| pVarResult, | |
| pExcepInfo, | |
| puArgErr, | |
| cVarRef, | |
| rgVarRefIdx, | |
| rgVarRef); | |
| if (cVarRef) { | |
| for (u=0; u<cVarRef; u++) { | |
| unsigned i = rgVarRefIdx[u]; | |
| VariantCopy(&pDispParams->rgvarg[i], | |
| &rgVarRef[u]); | |
| VariantClear(&rgVarRef[u]); | |
| } | |
| CoTaskMemFree(rgVarRef); | |
| CoTaskMemFree(rgVarRefIdx); | |
| } | |
| if(pExcepInfo == &ExcepInfo) | |
| { | |
| SysFreeString(pExcepInfo->bstrSource); | |
| SysFreeString(pExcepInfo->bstrDescription); | |
| SysFreeString(pExcepInfo->bstrHelpFile); | |
| } | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB IDispatch_Invoke_Stub( | |
| IDispatch* This, | |
| DISPID dispIdMember, | |
| REFIID riid, | |
| LCID lcid, | |
| DWORD dwFlags, | |
| DISPPARAMS* pDispParams, | |
| VARIANT* pVarResult, | |
| EXCEPINFO* pExcepInfo, | |
| UINT* pArgErr, | |
| UINT cVarRef, | |
| UINT* rgVarRefIdx, | |
| VARIANTARG* rgVarRef) | |
| { | |
| HRESULT hr = S_OK; | |
| VARIANTARG *rgvarg, *arg; | |
| UINT u; | |
| /* initialize out parameters, so that they can be marshalled | |
| * in case the real Invoke doesn't initialize them */ | |
| VariantInit(pVarResult); | |
| memset(pExcepInfo, 0, sizeof(*pExcepInfo)); | |
| *pArgErr = 0; | |
| /* let the real Invoke operate on a copy of the in parameters, | |
| * so we don't risk losing pointers to allocated memory */ | |
| rgvarg = pDispParams->rgvarg; | |
| arg = CoTaskMemAlloc(sizeof(VARIANTARG)*pDispParams->cArgs); | |
| if (!arg) return E_OUTOFMEMORY; | |
| /* init all args so we can call VariantClear on all the args if the copy | |
| * below fails */ | |
| for (u = 0; u < pDispParams->cArgs; u++) | |
| VariantInit(&arg[u]); | |
| for (u = 0; u < pDispParams->cArgs; u++) { | |
| hr = VariantCopy(&arg[u], &rgvarg[u]); | |
| if (FAILED(hr)) | |
| break; | |
| } | |
| if (SUCCEEDED(hr)) { | |
| /* copy ref args to arg array */ | |
| for (u=0; u<cVarRef; u++) { | |
| unsigned i = rgVarRefIdx[u]; | |
| VariantCopy(&arg[i], &rgVarRef[u]); | |
| } | |
| pDispParams->rgvarg = arg; | |
| hr = IDispatch_Invoke(This, | |
| dispIdMember, | |
| riid, | |
| lcid, | |
| dwFlags, | |
| pDispParams, | |
| pVarResult, | |
| pExcepInfo, | |
| pArgErr); | |
| /* copy ref args from arg array */ | |
| for (u=0; u<cVarRef; u++) { | |
| unsigned i = rgVarRefIdx[u]; | |
| VariantCopy(&rgVarRef[u], &arg[i]); | |
| } | |
| } | |
| /* clear the duplicate argument list */ | |
| for (u=0; u<pDispParams->cArgs; u++) | |
| VariantClear(&arg[u]); | |
| pDispParams->rgvarg = rgvarg; | |
| CoTaskMemFree(arg); | |
| return hr; | |
| } | |
| /* IEnumVARIANT */ | |
| HRESULT CALLBACK IEnumVARIANT_Next_Proxy( | |
| IEnumVARIANT* This, | |
| ULONG celt, | |
| VARIANT* rgVar, | |
| ULONG* pCeltFetched) | |
| { | |
| ULONG fetched; | |
| if (!pCeltFetched) | |
| pCeltFetched = &fetched; | |
| return IEnumVARIANT_RemoteNext_Proxy(This, | |
| celt, | |
| rgVar, | |
| pCeltFetched); | |
| } | |
| HRESULT __RPC_STUB IEnumVARIANT_Next_Stub( | |
| IEnumVARIANT* This, | |
| ULONG celt, | |
| VARIANT* rgVar, | |
| ULONG* pCeltFetched) | |
| { | |
| HRESULT hr; | |
| *pCeltFetched = 0; | |
| hr = IEnumVARIANT_Next(This, | |
| celt, | |
| rgVar, | |
| pCeltFetched); | |
| if (hr == S_OK) *pCeltFetched = celt; | |
| return hr; | |
| } | |
| /* TypeInfo related freers */ | |
| static void free_embedded_typedesc(TYPEDESC *tdesc); | |
| static void free_embedded_arraydesc(ARRAYDESC *adesc) | |
| { | |
| switch(adesc->tdescElem.vt) | |
| { | |
| case VT_PTR: | |
| case VT_SAFEARRAY: | |
| free_embedded_typedesc(adesc->tdescElem.u.lptdesc); | |
| CoTaskMemFree(adesc->tdescElem.u.lptdesc); | |
| break; | |
| case VT_CARRAY: | |
| free_embedded_arraydesc(adesc->tdescElem.u.lpadesc); | |
| CoTaskMemFree(adesc->tdescElem.u.lpadesc); | |
| break; | |
| } | |
| } | |
| static void free_embedded_typedesc(TYPEDESC *tdesc) | |
| { | |
| switch(tdesc->vt) | |
| { | |
| case VT_PTR: | |
| case VT_SAFEARRAY: | |
| free_embedded_typedesc(tdesc->u.lptdesc); | |
| CoTaskMemFree(tdesc->u.lptdesc); | |
| break; | |
| case VT_CARRAY: | |
| free_embedded_arraydesc(tdesc->u.lpadesc); | |
| CoTaskMemFree(tdesc->u.lpadesc); | |
| break; | |
| } | |
| } | |
| static void free_embedded_elemdesc(ELEMDESC *edesc) | |
| { | |
| free_embedded_typedesc(&edesc->tdesc); | |
| if(edesc->u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) | |
| CoTaskMemFree(edesc->u.paramdesc.pparamdescex); | |
| } | |
| /* ITypeComp */ | |
| HRESULT CALLBACK ITypeComp_Bind_Proxy( | |
| ITypeComp* This, | |
| LPOLESTR name, | |
| ULONG lHashVal, | |
| WORD flags, | |
| ITypeInfo **ti, | |
| DESCKIND *desckind, | |
| BINDPTR *bindptr) | |
| { | |
| CLEANLOCALSTORAGE stg = { 0 }; | |
| ITypeComp *typecomp; | |
| FUNCDESC *funcdesc; | |
| VARDESC *vardesc; | |
| HRESULT hr; | |
| TRACE("(%p, %s, %#x, %#x, %p, %p, %p)\n", This, debugstr_w(name), lHashVal, flags, ti, | |
| desckind, bindptr); | |
| *desckind = DESCKIND_NONE; | |
| memset(bindptr, 0, sizeof(*bindptr)); | |
| hr = ITypeComp_RemoteBind_Proxy(This, name, lHashVal, flags, ti, desckind, | |
| &funcdesc, &vardesc, &typecomp, &stg); | |
| if (hr == S_OK) | |
| { | |
| switch (*desckind) | |
| { | |
| case DESCKIND_FUNCDESC: | |
| bindptr->lpfuncdesc = funcdesc; | |
| break; | |
| case DESCKIND_VARDESC: | |
| case DESCKIND_IMPLICITAPPOBJ: | |
| bindptr->lpvardesc = vardesc; | |
| break; | |
| case DESCKIND_TYPECOMP: | |
| bindptr->lptcomp = typecomp; | |
| break; | |
| default: | |
| ; | |
| } | |
| } | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeComp_Bind_Stub( | |
| ITypeComp* This, | |
| LPOLESTR name, | |
| ULONG lHashVal, | |
| WORD flags, | |
| ITypeInfo **ti, | |
| DESCKIND *desckind, | |
| FUNCDESC **funcdesc, | |
| VARDESC **vardesc, | |
| ITypeComp **typecomp, | |
| CLEANLOCALSTORAGE *stg) | |
| { | |
| BINDPTR bindptr; | |
| HRESULT hr; | |
| TRACE("(%p, %s, %#x, %#x, %p, %p, %p, %p, %p, %p)\n", This, debugstr_w(name), | |
| lHashVal, flags, ti, desckind, funcdesc, vardesc, typecomp, stg); | |
| memset(stg, 0, sizeof(*stg)); | |
| memset(&bindptr, 0, sizeof(bindptr)); | |
| *funcdesc = NULL; | |
| *vardesc = NULL; | |
| *typecomp = NULL; | |
| *ti = NULL; | |
| hr = ITypeComp_Bind(This, name, lHashVal, flags, ti, desckind, &bindptr); | |
| if(hr != S_OK) | |
| return hr; | |
| switch (*desckind) | |
| { | |
| case DESCKIND_FUNCDESC: | |
| *funcdesc = bindptr.lpfuncdesc; | |
| stg->pInterface = (IUnknown*)*ti; | |
| stg->pStorage = funcdesc; | |
| stg->flags = CLS_FUNCDESC; | |
| break; | |
| case DESCKIND_VARDESC: | |
| case DESCKIND_IMPLICITAPPOBJ: | |
| *vardesc = bindptr.lpvardesc; | |
| stg->pInterface = (IUnknown*)*ti; | |
| stg->pStorage = vardesc; | |
| stg->flags = CLS_VARDESC; | |
| break; | |
| case DESCKIND_TYPECOMP: | |
| *typecomp = bindptr.lptcomp; | |
| break; | |
| default: | |
| ; | |
| } | |
| if (stg->pInterface) | |
| IUnknown_AddRef(stg->pInterface); | |
| return hr; | |
| } | |
| HRESULT CALLBACK ITypeComp_BindType_Proxy( | |
| ITypeComp* This, | |
| LPOLESTR name, | |
| ULONG lHashVal, | |
| ITypeInfo **ti, | |
| ITypeComp **typecomp) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p, %s, %#x, %p, %p)\n", This, debugstr_w(name), lHashVal, ti, typecomp); | |
| hr = ITypeComp_RemoteBindType_Proxy(This, name, lHashVal, ti); | |
| if (hr == S_OK) | |
| ITypeInfo_GetTypeComp(*ti, typecomp); | |
| else if (typecomp) | |
| *typecomp = NULL; | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeComp_BindType_Stub( | |
| ITypeComp* This, | |
| LPOLESTR name, | |
| ULONG lHashVal, | |
| ITypeInfo **ti) | |
| { | |
| ITypeComp *typecomp = NULL; | |
| HRESULT hr; | |
| TRACE("(%p, %s, %#x, %p)\n", This, debugstr_w(name), lHashVal, ti); | |
| hr = ITypeComp_BindType(This, name, lHashVal, ti, &typecomp); | |
| if (typecomp) | |
| ITypeComp_Release(typecomp); | |
| return hr; | |
| } | |
| /* ITypeInfo */ | |
| HRESULT CALLBACK ITypeInfo_GetTypeAttr_Proxy( | |
| ITypeInfo* This, | |
| TYPEATTR** ppTypeAttr) | |
| { | |
| CLEANLOCALSTORAGE stg; | |
| TRACE("(%p, %p)\n", This, ppTypeAttr); | |
| stg.flags = 0; | |
| stg.pStorage = NULL; | |
| stg.pInterface = NULL; | |
| return ITypeInfo_RemoteGetTypeAttr_Proxy(This, ppTypeAttr, &stg); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetTypeAttr_Stub( | |
| ITypeInfo* This, | |
| LPTYPEATTR* ppTypeAttr, | |
| CLEANLOCALSTORAGE* pDummy) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p, %p)\n", This, ppTypeAttr); | |
| hr = ITypeInfo_GetTypeAttr(This, ppTypeAttr); | |
| if(hr != S_OK) | |
| return hr; | |
| pDummy->flags = CLS_TYPEATTR; | |
| ITypeInfo_AddRef(This); | |
| pDummy->pInterface = (IUnknown*)This; | |
| pDummy->pStorage = ppTypeAttr; | |
| return hr; | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetFuncDesc_Proxy( | |
| ITypeInfo* This, | |
| UINT index, | |
| FUNCDESC** ppFuncDesc) | |
| { | |
| CLEANLOCALSTORAGE stg; | |
| TRACE("(%p, %d, %p)\n", This, index, ppFuncDesc); | |
| stg.flags = 0; | |
| stg.pStorage = NULL; | |
| stg.pInterface = NULL; | |
| return ITypeInfo_RemoteGetFuncDesc_Proxy(This, index, ppFuncDesc, &stg); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetFuncDesc_Stub( | |
| ITypeInfo* This, | |
| UINT index, | |
| LPFUNCDESC* ppFuncDesc, | |
| CLEANLOCALSTORAGE* pDummy) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p, %d, %p)\n", This, index, ppFuncDesc); | |
| hr = ITypeInfo_GetFuncDesc(This, index, ppFuncDesc); | |
| if(hr != S_OK) | |
| return hr; | |
| pDummy->flags = CLS_FUNCDESC; | |
| ITypeInfo_AddRef(This); | |
| pDummy->pInterface = (IUnknown*)This; | |
| pDummy->pStorage = ppFuncDesc; | |
| return hr; | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetVarDesc_Proxy( | |
| ITypeInfo* This, | |
| UINT index, | |
| VARDESC** ppVarDesc) | |
| { | |
| CLEANLOCALSTORAGE stg; | |
| TRACE("(%p, %d, %p)\n", This, index, ppVarDesc); | |
| stg.flags = 0; | |
| stg.pStorage = NULL; | |
| stg.pInterface = NULL; | |
| return ITypeInfo_RemoteGetVarDesc_Proxy(This, index, ppVarDesc, &stg); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetVarDesc_Stub( | |
| ITypeInfo* This, | |
| UINT index, | |
| LPVARDESC* ppVarDesc, | |
| CLEANLOCALSTORAGE* pDummy) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p, %d, %p)\n", This, index, ppVarDesc); | |
| hr = ITypeInfo_GetVarDesc(This, index, ppVarDesc); | |
| if(hr != S_OK) | |
| return hr; | |
| pDummy->flags = CLS_VARDESC; | |
| ITypeInfo_AddRef(This); | |
| pDummy->pInterface = (IUnknown*)This; | |
| pDummy->pStorage = ppVarDesc; | |
| return hr; | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetNames_Proxy( | |
| ITypeInfo* This, | |
| MEMBERID memid, | |
| BSTR* rgBstrNames, | |
| UINT cMaxNames, | |
| UINT* pcNames) | |
| { | |
| TRACE("(%p, %08x, %p, %d, %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); | |
| return ITypeInfo_RemoteGetNames_Proxy(This, memid, rgBstrNames, cMaxNames, pcNames); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetNames_Stub( | |
| ITypeInfo* This, | |
| MEMBERID memid, | |
| BSTR* rgBstrNames, | |
| UINT cMaxNames, | |
| UINT* pcNames) | |
| { | |
| TRACE("(%p, %08x, %p, %d, %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames); | |
| return ITypeInfo_GetNames(This, memid, rgBstrNames, cMaxNames, pcNames); | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetIDsOfNames_Proxy( | |
| ITypeInfo* This, | |
| LPOLESTR* rgszNames, | |
| UINT cNames, | |
| MEMBERID* pMemId) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetIDsOfNames_Stub( | |
| ITypeInfo* This) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT CALLBACK ITypeInfo_Invoke_Proxy( | |
| ITypeInfo* This, | |
| PVOID pvInstance, | |
| MEMBERID memid, | |
| WORD wFlags, | |
| DISPPARAMS* pDispParams, | |
| VARIANT* pVarResult, | |
| EXCEPINFO* pExcepInfo, | |
| UINT* puArgErr) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_Invoke_Stub( | |
| ITypeInfo* This) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetDocumentation_Proxy(ITypeInfo *This, MEMBERID memid, | |
| BSTR *name, BSTR *doc_string, | |
| DWORD *help_context, BSTR *help_file) | |
| { | |
| DWORD dummy_help_context, flags = 0; | |
| BSTR dummy_name, dummy_doc_string, dummy_help_file; | |
| HRESULT hr; | |
| TRACE("(%p, %08x, %p, %p, %p, %p)\n", This, memid, name, doc_string, help_context, help_file); | |
| if(!name) name = &dummy_name; | |
| else flags = 1; | |
| if(!doc_string) doc_string = &dummy_doc_string; | |
| else flags |= 2; | |
| if(!help_context) help_context = &dummy_help_context; | |
| else flags |= 4; | |
| if(!help_file) help_file = &dummy_help_file; | |
| else flags |= 8; | |
| hr = ITypeInfo_RemoteGetDocumentation_Proxy(This, memid, flags, name, doc_string, help_context, help_file); | |
| /* We don't need to free the dummy BSTRs since the stub ensures that these will be NULLs. */ | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetDocumentation_Stub(ITypeInfo *This, MEMBERID memid, | |
| DWORD flags, BSTR *name, BSTR *doc_string, | |
| DWORD *help_context, BSTR *help_file) | |
| { | |
| TRACE("(%p, %08x, %08x, %p, %p, %p, %p)\n", This, memid, flags, name, doc_string, help_context, help_file); | |
| *name = *doc_string = *help_file = NULL; | |
| *help_context = 0; | |
| if(!(flags & 1)) name = NULL; | |
| if(!(flags & 2)) doc_string = NULL; | |
| if(!(flags & 4)) help_context = NULL; | |
| if(!(flags & 8)) help_file = NULL; | |
| return ITypeInfo_GetDocumentation(This, memid, name, doc_string, help_context, help_file); | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetDllEntry_Proxy(ITypeInfo *This, MEMBERID memid, | |
| INVOKEKIND invkind, BSTR *dll_name, | |
| BSTR* name, WORD *ordinal) | |
| { | |
| DWORD flags = 0; | |
| BSTR dummy_dll_name, dummy_name; | |
| WORD dummy_ordinal; | |
| HRESULT hr; | |
| TRACE("(%p, %08x, %x, %p, %p, %p)\n", This, memid, invkind, dll_name, name, ordinal); | |
| if(!dll_name) dll_name = &dummy_dll_name; | |
| else flags = 1; | |
| if(!name) name = &dummy_name; | |
| else flags |= 2; | |
| if(!ordinal) ordinal = &dummy_ordinal; | |
| else flags |= 4; | |
| hr = ITypeInfo_RemoteGetDllEntry_Proxy(This, memid, invkind, flags, dll_name, name, ordinal); | |
| /* We don't need to free the dummy BSTRs since the stub ensures that these will be NULLs. */ | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetDllEntry_Stub(ITypeInfo *This, MEMBERID memid, | |
| INVOKEKIND invkind, DWORD flags, | |
| BSTR *dll_name, BSTR *name, | |
| WORD *ordinal) | |
| { | |
| TRACE("(%p, %08x, %x, %p, %p, %p)\n", This, memid, invkind, dll_name, name, ordinal); | |
| *dll_name = *name = NULL; | |
| *ordinal = 0; | |
| if(!(flags & 1)) dll_name = NULL; | |
| if(!(flags & 2)) name = NULL; | |
| if(!(flags & 4)) ordinal = NULL; | |
| return ITypeInfo_GetDllEntry(This, memid, invkind, dll_name, name, ordinal); | |
| } | |
| HRESULT CALLBACK ITypeInfo_AddressOfMember_Proxy( | |
| ITypeInfo* This, | |
| MEMBERID memid, | |
| INVOKEKIND invKind, | |
| PVOID* ppv) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_AddressOfMember_Stub( | |
| ITypeInfo* This) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT CALLBACK ITypeInfo_CreateInstance_Proxy( | |
| ITypeInfo* This, | |
| IUnknown* pUnkOuter, | |
| REFIID riid, | |
| PVOID* ppvObj) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_CreateInstance_Stub( | |
| ITypeInfo* This, | |
| REFIID riid, | |
| IUnknown** ppvObj) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT CALLBACK ITypeInfo_GetContainingTypeLib_Proxy( | |
| ITypeInfo* This, | |
| ITypeLib** ppTLib, | |
| UINT* pIndex) | |
| { | |
| ITypeLib *pTL; | |
| UINT index; | |
| HRESULT hr; | |
| TRACE("(%p, %p, %p)\n", This, ppTLib, pIndex ); | |
| hr = ITypeInfo_RemoteGetContainingTypeLib_Proxy(This, &pTL, &index); | |
| if(SUCCEEDED(hr)) | |
| { | |
| if(pIndex) | |
| *pIndex = index; | |
| if(ppTLib) | |
| *ppTLib = pTL; | |
| else | |
| ITypeLib_Release(pTL); | |
| } | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_GetContainingTypeLib_Stub( | |
| ITypeInfo* This, | |
| ITypeLib** ppTLib, | |
| UINT* pIndex) | |
| { | |
| TRACE("(%p, %p, %p)\n", This, ppTLib, pIndex ); | |
| return ITypeInfo_GetContainingTypeLib(This, ppTLib, pIndex); | |
| } | |
| void CALLBACK ITypeInfo_ReleaseTypeAttr_Proxy( | |
| ITypeInfo* This, | |
| TYPEATTR* pTypeAttr) | |
| { | |
| TRACE("(%p, %p)\n", This, pTypeAttr); | |
| free_embedded_typedesc(&pTypeAttr->tdescAlias); | |
| CoTaskMemFree(pTypeAttr); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_ReleaseTypeAttr_Stub( | |
| ITypeInfo* This) | |
| { | |
| TRACE("nothing to do\n"); | |
| return S_OK; | |
| } | |
| void CALLBACK ITypeInfo_ReleaseFuncDesc_Proxy( | |
| ITypeInfo* This, | |
| FUNCDESC* pFuncDesc) | |
| { | |
| SHORT param; | |
| TRACE("(%p, %p)\n", This, pFuncDesc); | |
| for(param = 0; param < pFuncDesc->cParams; param++) | |
| free_embedded_elemdesc(pFuncDesc->lprgelemdescParam + param); | |
| if(param) | |
| CoTaskMemFree(pFuncDesc->lprgelemdescParam); | |
| free_embedded_elemdesc(&pFuncDesc->elemdescFunc); | |
| if(pFuncDesc->cScodes != 0 && pFuncDesc->cScodes != -1) | |
| CoTaskMemFree(pFuncDesc->lprgscode); | |
| CoTaskMemFree(pFuncDesc); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_ReleaseFuncDesc_Stub( | |
| ITypeInfo* This) | |
| { | |
| TRACE("nothing to do\n"); | |
| return S_OK; | |
| } | |
| void CALLBACK ITypeInfo_ReleaseVarDesc_Proxy( | |
| ITypeInfo* This, | |
| VARDESC* pVarDesc) | |
| { | |
| TRACE("(%p, %p)\n", This, pVarDesc); | |
| CoTaskMemFree(pVarDesc->lpstrSchema); | |
| if(pVarDesc->varkind == VAR_CONST) | |
| CoTaskMemFree(pVarDesc->u.lpvarValue); | |
| free_embedded_elemdesc(&pVarDesc->elemdescVar); | |
| CoTaskMemFree(pVarDesc); | |
| } | |
| HRESULT __RPC_STUB ITypeInfo_ReleaseVarDesc_Stub( | |
| ITypeInfo* This) | |
| { | |
| TRACE("nothing to do\n"); | |
| return S_OK; | |
| } | |
| /* ITypeInfo2 */ | |
| HRESULT CALLBACK ITypeInfo2_GetDocumentation2_Proxy(ITypeInfo2 *This, MEMBERID memid, | |
| LCID lcid, BSTR *help_string, | |
| DWORD *help_context, BSTR *help_dll) | |
| { | |
| DWORD dummy_help_context, flags = 0; | |
| BSTR dummy_help_string, dummy_help_dll; | |
| HRESULT hr; | |
| TRACE("(%p, %08x, %08x, %p, %p, %p)\n", This, memid, lcid, help_string, help_context, help_dll); | |
| if(!help_string) help_string = &dummy_help_string; | |
| else flags = 1; | |
| if(!help_context) help_context = &dummy_help_context; | |
| else flags |= 2; | |
| if(!help_dll) help_dll = &dummy_help_dll; | |
| else flags |= 4; | |
| hr = ITypeInfo2_RemoteGetDocumentation2_Proxy(This, memid, lcid, flags, help_string, help_context, help_dll); | |
| /* We don't need to free the dummy BSTRs since the stub ensures that these will be NULLs. */ | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeInfo2_GetDocumentation2_Stub(ITypeInfo2 *This, MEMBERID memid, | |
| LCID lcid, DWORD flags, | |
| BSTR *help_string, DWORD *help_context, | |
| BSTR *help_dll) | |
| { | |
| TRACE("(%p, %08x, %08x, %08x, %p, %p, %p)\n", This, memid, lcid, flags, help_string, help_context, help_dll); | |
| *help_string = *help_dll = NULL; | |
| *help_context = 0; | |
| if(!(flags & 1)) help_string = NULL; | |
| if(!(flags & 2)) help_context = NULL; | |
| if(!(flags & 4)) help_dll = NULL; | |
| return ITypeInfo2_GetDocumentation2(This, memid, lcid, help_string, help_context, help_dll); | |
| } | |
| /* ITypeLib */ | |
| UINT CALLBACK ITypeLib_GetTypeInfoCount_Proxy( | |
| ITypeLib* This) | |
| { | |
| UINT count = 0; | |
| TRACE("(%p)\n", This); | |
| ITypeLib_RemoteGetTypeInfoCount_Proxy(This, &count); | |
| return count; | |
| } | |
| HRESULT __RPC_STUB ITypeLib_GetTypeInfoCount_Stub( | |
| ITypeLib* This, | |
| UINT* pcTInfo) | |
| { | |
| TRACE("(%p, %p)\n", This, pcTInfo); | |
| *pcTInfo = ITypeLib_GetTypeInfoCount(This); | |
| return S_OK; | |
| } | |
| HRESULT CALLBACK ITypeLib_GetLibAttr_Proxy( | |
| ITypeLib* This, | |
| TLIBATTR** ppTLibAttr) | |
| { | |
| CLEANLOCALSTORAGE stg; | |
| TRACE("(%p, %p)\n", This, ppTLibAttr); | |
| stg.flags = 0; | |
| stg.pStorage = NULL; | |
| stg.pInterface = NULL; | |
| return ITypeLib_RemoteGetLibAttr_Proxy(This, ppTLibAttr, &stg); | |
| } | |
| HRESULT __RPC_STUB ITypeLib_GetLibAttr_Stub( | |
| ITypeLib* This, | |
| LPTLIBATTR* ppTLibAttr, | |
| CLEANLOCALSTORAGE* pDummy) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p, %p)\n", This, ppTLibAttr); | |
| hr = ITypeLib_GetLibAttr(This, ppTLibAttr); | |
| if(hr != S_OK) | |
| return hr; | |
| pDummy->flags = CLS_LIBATTR; | |
| ITypeLib_AddRef(This); | |
| pDummy->pInterface = (IUnknown*)This; | |
| pDummy->pStorage = ppTLibAttr; | |
| return hr; | |
| } | |
| HRESULT CALLBACK ITypeLib_GetDocumentation_Proxy(ITypeLib *This, INT index, BSTR *name, | |
| BSTR *doc_string, DWORD *help_context, | |
| BSTR *help_file) | |
| { | |
| DWORD dummy_help_context, flags = 0; | |
| BSTR dummy_name, dummy_doc_string, dummy_help_file; | |
| HRESULT hr; | |
| TRACE("(%p, %d, %p, %p, %p, %p)\n", This, index, name, doc_string, help_context, help_file); | |
| if(!name) name = &dummy_name; | |
| else flags = 1; | |
| if(!doc_string) doc_string = &dummy_doc_string; | |
| else flags |= 2; | |
| if(!help_context) help_context = &dummy_help_context; | |
| else flags |= 4; | |
| if(!help_file) help_file = &dummy_help_file; | |
| else flags |= 8; | |
| hr = ITypeLib_RemoteGetDocumentation_Proxy(This, index, flags, name, doc_string, help_context, help_file); | |
| /* We don't need to free the dummy BSTRs since the stub ensures that these will be NULLs. */ | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeLib_GetDocumentation_Stub(ITypeLib *This, INT index, DWORD flags, | |
| BSTR *name, BSTR *doc_string, | |
| DWORD *help_context, BSTR *help_file) | |
| { | |
| TRACE("(%p, %d, %08x, %p, %p, %p, %p)\n", This, index, flags, name, doc_string, help_context, help_file); | |
| *name = *doc_string = *help_file = NULL; | |
| *help_context = 0; | |
| if(!(flags & 1)) name = NULL; | |
| if(!(flags & 2)) doc_string = NULL; | |
| if(!(flags & 4)) help_context = NULL; | |
| if(!(flags & 8)) help_file = NULL; | |
| return ITypeLib_GetDocumentation(This, index, name, doc_string, help_context, help_file); | |
| } | |
| HRESULT CALLBACK ITypeLib_IsName_Proxy( | |
| ITypeLib* This, | |
| LPOLESTR szNameBuf, | |
| ULONG lHashVal, | |
| BOOL* pfName) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeLib_IsName_Stub( | |
| ITypeLib* This, | |
| LPOLESTR szNameBuf, | |
| ULONG lHashVal, | |
| BOOL* pfName, | |
| BSTR* pBstrLibName) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT CALLBACK ITypeLib_FindName_Proxy( | |
| ITypeLib* This, | |
| LPOLESTR szNameBuf, | |
| ULONG lHashVal, | |
| ITypeInfo** ppTInfo, | |
| MEMBERID* rgMemId, | |
| USHORT* pcFound) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeLib_FindName_Stub( | |
| ITypeLib* This, | |
| LPOLESTR szNameBuf, | |
| ULONG lHashVal, | |
| ITypeInfo** ppTInfo, | |
| MEMBERID* rgMemId, | |
| USHORT* pcFound, | |
| BSTR* pBstrLibName) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| void CALLBACK ITypeLib_ReleaseTLibAttr_Proxy( | |
| ITypeLib* This, | |
| TLIBATTR* pTLibAttr) | |
| { | |
| TRACE("(%p, %p)\n", This, pTLibAttr); | |
| CoTaskMemFree(pTLibAttr); | |
| } | |
| HRESULT __RPC_STUB ITypeLib_ReleaseTLibAttr_Stub( | |
| ITypeLib* This) | |
| { | |
| TRACE("nothing to do\n"); | |
| return S_OK; | |
| } | |
| /* ITypeLib2 */ | |
| HRESULT CALLBACK ITypeLib2_GetLibStatistics_Proxy( | |
| ITypeLib2* This, | |
| ULONG* pcUniqueNames, | |
| ULONG* pcchUniqueNames) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT __RPC_STUB ITypeLib2_GetLibStatistics_Stub( | |
| ITypeLib2* This, | |
| ULONG* pcUniqueNames, | |
| ULONG* pcchUniqueNames) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_FAIL; | |
| } | |
| HRESULT CALLBACK ITypeLib2_GetDocumentation2_Proxy(ITypeLib2 *This, INT index, | |
| LCID lcid, BSTR *help_string, | |
| DWORD *help_context, BSTR *help_dll) | |
| { | |
| DWORD dummy_help_context, flags = 0; | |
| BSTR dummy_help_string, dummy_help_dll; | |
| HRESULT hr; | |
| TRACE("(%p, %d, %08x, %p, %p, %p)\n", This, index, lcid, help_string, help_context, help_dll); | |
| if(!help_string) help_string = &dummy_help_string; | |
| else flags = 1; | |
| if(!help_context) help_context = &dummy_help_context; | |
| else flags |= 2; | |
| if(!help_dll) help_dll = &dummy_help_dll; | |
| else flags |= 4; | |
| hr = ITypeLib2_RemoteGetDocumentation2_Proxy(This, index, lcid, flags, help_string, help_context, help_dll); | |
| /* We don't need to free the dummy BSTRs since the stub ensures that these will be NULLs. */ | |
| return hr; | |
| } | |
| HRESULT __RPC_STUB ITypeLib2_GetDocumentation2_Stub(ITypeLib2 *This, INT index, LCID lcid, | |
| DWORD flags, BSTR *help_string, | |
| DWORD *help_context, BSTR *help_dll) | |
| { | |
| TRACE("(%p, %d, %08x, %08x, %p, %p, %p)\n", This, index, lcid, flags, help_string, help_context, help_dll); | |
| *help_string = *help_dll = NULL; | |
| *help_context = 0; | |
| if(!(flags & 1)) help_string = NULL; | |
| if(!(flags & 2)) help_context = NULL; | |
| if(!(flags & 4)) help_dll = NULL; | |
| return ITypeLib2_GetDocumentation2(This, index, lcid, help_string, help_context, help_dll); | |
| } | |
| HRESULT CALLBACK IPropertyBag_Read_Proxy( | |
| IPropertyBag* This, | |
| LPCOLESTR pszPropName, | |
| VARIANT *pVar, | |
| IErrorLog *pErrorLog) | |
| { | |
| IUnknown *pUnk = NULL; | |
| TRACE("(%p, %s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog); | |
| if(!pVar) | |
| return E_POINTER; | |
| if(V_VT(pVar) & (VT_BYREF | VT_ARRAY | VT_VECTOR)) | |
| { | |
| FIXME("Variant type %x is byref, array or vector. Not implemented.\n", V_VT(pVar)); | |
| return E_NOTIMPL; | |
| } | |
| switch(V_VT(pVar)) | |
| { | |
| case VT_DISPATCH: | |
| pUnk = (IUnknown*)V_DISPATCH(pVar); | |
| break; | |
| case VT_UNKNOWN: | |
| pUnk = V_UNKNOWN(pVar); | |
| break; | |
| case VT_SAFEARRAY: | |
| FIXME("Safearray support not yet implemented.\n"); | |
| return E_NOTIMPL; | |
| default: | |
| FIXME("Unknown V_VT %d - support not yet implemented.\n", V_VT(pVar)); | |
| return E_NOTIMPL; | |
| } | |
| return IPropertyBag_RemoteRead_Proxy(This, pszPropName, pVar, pErrorLog, | |
| V_VT(pVar), pUnk); | |
| } | |
| HRESULT __RPC_STUB IPropertyBag_Read_Stub( | |
| IPropertyBag* This, | |
| LPCOLESTR pszPropName, | |
| VARIANT *pVar, | |
| IErrorLog *pErrorLog, | |
| DWORD varType, | |
| IUnknown *pUnkObj) | |
| { | |
| static const WCHAR emptyWstr[] = {0}; | |
| IDispatch *disp; | |
| HRESULT hr; | |
| TRACE("(%p, %s, %p, %p, %x, %p)\n", This, debugstr_w(pszPropName), pVar, | |
| pErrorLog, varType, pUnkObj); | |
| if(varType & (VT_BYREF | VT_ARRAY | VT_VECTOR)) | |
| { | |
| FIXME("Variant type %x is byref, array or vector. Not implemented.\n", V_VT(pVar)); | |
| return E_NOTIMPL; | |
| } | |
| V_VT(pVar) = varType; | |
| switch(varType) | |
| { | |
| case VT_DISPATCH: | |
| hr = IUnknown_QueryInterface(pUnkObj, &IID_IDispatch, (LPVOID*)&disp); | |
| if(FAILED(hr)) | |
| return hr; | |
| IUnknown_Release(pUnkObj); | |
| V_DISPATCH(pVar) = disp; | |
| break; | |
| case VT_UNKNOWN: | |
| V_UNKNOWN(pVar) = pUnkObj; | |
| break; | |
| case VT_BSTR: | |
| V_BSTR(pVar) = SysAllocString(emptyWstr); | |
| break; | |
| case VT_SAFEARRAY: | |
| FIXME("Safearray support not yet implemented.\n"); | |
| return E_NOTIMPL; | |
| default: | |
| break; | |
| } | |
| hr = IPropertyBag_Read(This, pszPropName, pVar, pErrorLog); | |
| if(FAILED(hr)) | |
| VariantClear(pVar); | |
| return hr; | |
| } | |
| /* call_as/local stubs for ocidl.idl */ | |
| HRESULT CALLBACK IClassFactory2_CreateInstanceLic_Proxy( | |
| IClassFactory2* This, | |
| IUnknown *pUnkOuter, | |
| IUnknown *pUnkReserved, | |
| REFIID riid, | |
| BSTR bstrKey, | |
| PVOID *ppvObj) | |
| { | |
| TRACE("(%p, %s, %p)\n", pUnkOuter, debugstr_guid(riid), ppvObj); | |
| *ppvObj = NULL; | |
| if (pUnkOuter) | |
| { | |
| ERR("aggregation is not allowed on remote objects\n"); | |
| return CLASS_E_NOAGGREGATION; | |
| } | |
| return IClassFactory2_RemoteCreateInstanceLic_Proxy(This, riid, bstrKey, (IUnknown**)ppvObj); | |
| } | |
| HRESULT __RPC_STUB IClassFactory2_CreateInstanceLic_Stub( | |
| IClassFactory2* This, | |
| REFIID riid, | |
| BSTR bstrKey, | |
| IUnknown **ppvObj) | |
| { | |
| TRACE("(%s, %p)\n", debugstr_guid(riid), ppvObj); | |
| return IClassFactory2_CreateInstanceLic(This, NULL, NULL, riid, bstrKey, (void**)ppvObj); | |
| } | |
| HRESULT CALLBACK IEnumConnections_Next_Proxy( | |
| IEnumConnections* This, | |
| ULONG cConnections, | |
| LPCONNECTDATA rgcd, | |
| ULONG *pcFetched) | |
| { | |
| ULONG fetched; | |
| TRACE("(%u, %p %p)\n", cConnections, rgcd, pcFetched); | |
| if (!pcFetched) | |
| pcFetched = &fetched; | |
| return IEnumConnections_RemoteNext_Proxy(This, cConnections, rgcd, pcFetched); | |
| } | |
| HRESULT __RPC_STUB IEnumConnections_Next_Stub( | |
| IEnumConnections* This, | |
| ULONG cConnections, | |
| LPCONNECTDATA rgcd, | |
| ULONG *pcFetched) | |
| { | |
| HRESULT hr; | |
| TRACE("(%u, %p, %p)\n", cConnections, rgcd, pcFetched); | |
| *pcFetched = 0; | |
| hr = IEnumConnections_Next(This, cConnections, rgcd, pcFetched); | |
| if (hr == S_OK) | |
| *pcFetched = cConnections; | |
| return hr; | |
| } | |
| HRESULT CALLBACK IEnumConnectionPoints_Next_Proxy( | |
| IEnumConnectionPoints* This, | |
| ULONG cConnections, | |
| IConnectionPoint **ppCP, | |
| ULONG *pcFetched) | |
| { | |
| ULONG fetched; | |
| TRACE("(%u, %p %p)\n", cConnections, ppCP, pcFetched); | |
| if (!pcFetched) | |
| pcFetched = &fetched; | |
| return IEnumConnectionPoints_RemoteNext_Proxy(This, cConnections, ppCP, pcFetched); | |
| } | |
| HRESULT __RPC_STUB IEnumConnectionPoints_Next_Stub( | |
| IEnumConnectionPoints* This, | |
| ULONG cConnections, | |
| IConnectionPoint **ppCP, | |
| ULONG *pcFetched) | |
| { | |
| HRESULT hr; | |
| TRACE("(%u, %p, %p)\n", cConnections, ppCP, pcFetched); | |
| *pcFetched = 0; | |
| hr = IEnumConnectionPoints_Next(This, cConnections, ppCP, pcFetched); | |
| if (hr == S_OK) | |
| *pcFetched = cConnections; | |
| return hr; | |
| } | |
| HRESULT CALLBACK IPersistMemory_Load_Proxy( | |
| IPersistMemory* This, | |
| LPVOID pMem, | |
| ULONG cbSize) | |
| { | |
| TRACE("(%p, %u)\n", pMem, cbSize); | |
| if (!pMem) | |
| return E_POINTER; | |
| return IPersistMemory_RemoteLoad_Proxy(This, pMem, cbSize); | |
| } | |
| HRESULT __RPC_STUB IPersistMemory_Load_Stub( | |
| IPersistMemory* This, | |
| BYTE *pMem, | |
| ULONG cbSize) | |
| { | |
| TRACE("(%p, %u)\n", pMem, cbSize); | |
| return IPersistMemory_Load(This, pMem, cbSize); | |
| } | |
| HRESULT CALLBACK IPersistMemory_Save_Proxy( | |
| IPersistMemory* This, | |
| LPVOID pMem, | |
| BOOL fClearDirty, | |
| ULONG cbSize) | |
| { | |
| TRACE("(%p, %d, %u)\n", pMem, fClearDirty, cbSize); | |
| if (!pMem) | |
| return E_POINTER; | |
| return IPersistMemory_RemoteSave_Proxy(This, pMem, fClearDirty, cbSize); | |
| } | |
| HRESULT __RPC_STUB IPersistMemory_Save_Stub( | |
| IPersistMemory* This, | |
| BYTE *pMem, | |
| BOOL fClearDirty, | |
| ULONG cbSize) | |
| { | |
| TRACE("(%p, %d, %u)\n", pMem, fClearDirty, cbSize); | |
| return IPersistMemory_Save(This, pMem, fClearDirty, cbSize); | |
| } | |
| void CALLBACK IAdviseSinkEx_OnViewStatusChange_Proxy( | |
| IAdviseSinkEx* This, | |
| DWORD dwViewStatus) | |
| { | |
| TRACE("(%p, 0x%08x)\n", This, dwViewStatus); | |
| IAdviseSinkEx_RemoteOnViewStatusChange_Proxy(This, dwViewStatus); | |
| } | |
| HRESULT __RPC_STUB IAdviseSinkEx_OnViewStatusChange_Stub( | |
| IAdviseSinkEx* This, | |
| DWORD dwViewStatus) | |
| { | |
| TRACE("(%p, 0x%08x)\n", This, dwViewStatus); | |
| IAdviseSinkEx_OnViewStatusChange(This, dwViewStatus); | |
| return S_OK; | |
| } | |
| HRESULT CALLBACK IEnumOleUndoUnits_Next_Proxy( | |
| IEnumOleUndoUnits* This, | |
| ULONG cElt, | |
| IOleUndoUnit **rgElt, | |
| ULONG *pcEltFetched) | |
| { | |
| ULONG fetched; | |
| TRACE("(%u, %p %p)\n", cElt, rgElt, pcEltFetched); | |
| if (!pcEltFetched) | |
| pcEltFetched = &fetched; | |
| return IEnumOleUndoUnits_RemoteNext_Proxy(This, cElt, rgElt, pcEltFetched); | |
| } | |
| HRESULT __RPC_STUB IEnumOleUndoUnits_Next_Stub( | |
| IEnumOleUndoUnits* This, | |
| ULONG cElt, | |
| IOleUndoUnit **rgElt, | |
| ULONG *pcEltFetched) | |
| { | |
| HRESULT hr; | |
| TRACE("(%u, %p, %p)\n", cElt, rgElt, pcEltFetched); | |
| *pcEltFetched = 0; | |
| hr = IEnumOleUndoUnits_Next(This, cElt, rgElt, pcEltFetched); | |
| if (hr == S_OK) | |
| *pcEltFetched = cElt; | |
| return hr; | |
| } | |
| HRESULT CALLBACK IQuickActivate_QuickActivate_Proxy( | |
| IQuickActivate* This, | |
| QACONTAINER *pQaContainer, | |
| QACONTROL *pQaControl) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_NOTIMPL; | |
| } | |
| HRESULT __RPC_STUB IQuickActivate_QuickActivate_Stub( | |
| IQuickActivate* This, | |
| QACONTAINER *pQaContainer, | |
| QACONTROL *pQaControl) | |
| { | |
| FIXME("not implemented\n"); | |
| return E_NOTIMPL; | |
| } |