/*1* Marshaling Routines2*3* Copyright 2005 Robert Shearman4* Copyright 2009 Huw Davies5*6* This library is free software; you can redistribute it and/or7* modify it under the terms of the GNU Lesser General Public8* License as published by the Free Software Foundation; either9* version 2.1 of the License, or (at your option) any later version.10*11* This library is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14* Lesser General Public License for more details.15*16* You should have received a copy of the GNU Lesser General Public17* License along with this library; if not, write to the Free Software18* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA19*/2021#define COBJMACROS22#include "ole2.h"2324#include "winstring.h"25#include "wine/debug.h"2627WINE_DEFAULT_DEBUG_CHANNEL(ole);2829#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align))30#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align))31#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align)32#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align)3334static const char* debugstr_user_flags(ULONG *pFlags)35{36char buf[12];37const char* loword;38switch (LOWORD(*pFlags))39{40case MSHCTX_LOCAL:41loword = "MSHCTX_LOCAL";42break;43case MSHCTX_NOSHAREDMEM:44loword = "MSHCTX_NOSHAREDMEM";45break;46case MSHCTX_DIFFERENTMACHINE:47loword = "MSHCTX_DIFFERENTMACHINE";48break;49case MSHCTX_INPROC:50loword = "MSHCTX_INPROC";51break;52default:53sprintf(buf, "%d", LOWORD(*pFlags));54loword=buf;55}5657if (HIWORD(*pFlags) == NDR_LOCAL_DATA_REPRESENTATION)58return wine_dbg_sprintf("MAKELONG(%s, NDR_LOCAL_DATA_REPRESENTATION)", loword);59else60return wine_dbg_sprintf("MAKELONG(%s, 0x%04x)", loword, HIWORD(*pFlags));61}6263static ULONG handle_UserSize(ULONG *pFlags, ULONG StartingSize, HANDLE *handle)64{65if (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE)66{67ERR("can't remote a local handle\n");68RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);69return StartingSize;70}7172ALIGN_LENGTH(StartingSize, 3);73return StartingSize + sizeof(RemotableHandle);74}7576static unsigned char * handle_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HANDLE *handle)77{78RemotableHandle *remhandle;79if (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE)80{81ERR("can't remote a local handle\n");82RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);83return pBuffer;84}8586ALIGN_POINTER(pBuffer, 3);87remhandle = (RemotableHandle *)pBuffer;88remhandle->fContext = WDT_INPROC_CALL;89remhandle->u.hInproc = (LONG_PTR)*handle;90return pBuffer + sizeof(RemotableHandle);91}9293static unsigned char * handle_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HANDLE *handle)94{95RemotableHandle *remhandle;9697ALIGN_POINTER(pBuffer, 3);98remhandle = (RemotableHandle *)pBuffer;99if (remhandle->fContext != WDT_INPROC_CALL)100RaiseException(RPC_X_BAD_STUB_DATA, 0, 0, NULL);101*handle = (HANDLE)(LONG_PTR)remhandle->u.hInproc;102return pBuffer + sizeof(RemotableHandle);103}104105static void handle_UserFree(ULONG *pFlags, HANDLE *handle)106{107/* nothing to do */108}109110#define IMPL_WIREM_HANDLE(type) \111ULONG __RPC_USER type##_UserSize(ULONG *pFlags, ULONG StartingSize, type *handle) \112{ \113TRACE("%s, %lu, %p.\n", debugstr_user_flags(pFlags), StartingSize, handle); \114return handle_UserSize(pFlags, StartingSize, (HANDLE *)handle); \115} \116\117unsigned char * __RPC_USER type##_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, type *handle) \118{ \119TRACE("%s, %p, &%p.\n", debugstr_user_flags(pFlags), pBuffer, *handle); \120return handle_UserMarshal(pFlags, pBuffer, (HANDLE *)handle); \121} \122\123unsigned char * __RPC_USER type##_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, type *handle) \124{ \125TRACE("%s, %p, %p.\n", debugstr_user_flags(pFlags), pBuffer, handle); \126return handle_UserUnmarshal(pFlags, pBuffer, (HANDLE *)handle); \127} \128\129void __RPC_USER type##_UserFree(ULONG *pFlags, type *handle) \130{ \131TRACE("%s, &%p.\n", debugstr_user_flags(pFlags), *handle); \132handle_UserFree(pFlags, (HANDLE *)handle); \133}134135IMPL_WIREM_HANDLE(HACCEL)136IMPL_WIREM_HANDLE(HBRUSH)137IMPL_WIREM_HANDLE(HDC)138IMPL_WIREM_HANDLE(HICON)139IMPL_WIREM_HANDLE(HMENU)140IMPL_WIREM_HANDLE(HWND)141142/******************************************************************************143* CLIPFORMAT_UserSize (combase.@)144*145* Calculates the buffer size required to marshal a clip format.146*147* PARAMS148* pFlags [I] Flags. See notes.149* StartingSize [I] Starting size of the buffer. This value is added on to150* the buffer size required for the clip format.151* pCF [I] Clip format to size.152*153* RETURNS154* The buffer size required to marshal a clip format plus the starting size.155*156* NOTES157* Even though the function is documented to take a pointer to an unsigned158* long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which159* the first parameter is an unsigned long.160* This function is only intended to be called by the RPC runtime.161*/162ULONG __RPC_USER CLIPFORMAT_UserSize(ULONG *pFlags, ULONG size, CLIPFORMAT *pCF)163{164TRACE("%s, %lu, %p.\n", debugstr_user_flags(pFlags), size, pCF);165166ALIGN_LENGTH(size, 3);167168size += 8;169170/* only need to marshal the name if it is not a pre-defined type and171* we are going remote */172if ((*pCF >= 0xc000) && (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE))173{174WCHAR format[255];175INT ret;176size += 3 * sizeof(UINT);177/* urg! this function is badly designed because it won't tell us how178* much space is needed without doing a dummy run of storing the179* name into a buffer */180ret = GetClipboardFormatNameW(*pCF, format, ARRAY_SIZE(format)-1);181if (!ret)182RaiseException(DV_E_CLIPFORMAT, 0, 0, NULL);183size += (ret + 1) * sizeof(WCHAR);184}185return size;186}187188/******************************************************************************189* CLIPFORMAT_UserMarshal (combase.@)190*191* Marshals a clip format into a buffer.192*193* PARAMS194* pFlags [I] Flags. See notes.195* pBuffer [I] Buffer to marshal the clip format into.196* pCF [I] Clip format to marshal.197*198* RETURNS199* The end of the marshaled data in the buffer.200*201* NOTES202* Even though the function is documented to take a pointer to an unsigned203* long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which204* the first parameter is an unsigned long.205* This function is only intended to be called by the RPC runtime.206*/207unsigned char * __RPC_USER CLIPFORMAT_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, CLIPFORMAT *pCF)208{209TRACE("%s, %p, &0x%04x.\n", debugstr_user_flags(pFlags), pBuffer, *pCF);210211ALIGN_POINTER(pBuffer, 3);212213/* only need to marshal the name if it is not a pre-defined type and214* we are going remote */215if ((*pCF >= 0xc000) && (LOWORD(*pFlags) == MSHCTX_DIFFERENTMACHINE))216{217WCHAR format[255];218UINT len;219220*(DWORD *)pBuffer = WDT_REMOTE_CALL;221pBuffer += 4;222*(DWORD *)pBuffer = *pCF;223pBuffer += 4;224225len = GetClipboardFormatNameW(*pCF, format, ARRAY_SIZE(format)-1);226if (!len)227RaiseException(DV_E_CLIPFORMAT, 0, 0, NULL);228len += 1;229*(UINT *)pBuffer = len;230pBuffer += sizeof(UINT);231*(UINT *)pBuffer = 0;232pBuffer += sizeof(UINT);233*(UINT *)pBuffer = len;234pBuffer += sizeof(UINT);235TRACE("marshaling format name %s\n", debugstr_w(format));236memcpy(pBuffer, format, len * sizeof(WCHAR));237pBuffer += len * sizeof(WCHAR);238}239else240{241*(DWORD *)pBuffer = WDT_INPROC_CALL;242pBuffer += 4;243*(DWORD *)pBuffer = *pCF;244pBuffer += 4;245}246247return pBuffer;248}249250/******************************************************************************251* CLIPFORMAT_UserUnmarshal (combase.@)252*253* Unmarshals a clip format from a buffer.254*255* PARAMS256* pFlags [I] Flags. See notes.257* pBuffer [I] Buffer to marshal the clip format from.258* pCF [O] Address that receive the unmarshaled clip format.259*260* RETURNS261* The end of the marshaled data in the buffer.262*263* NOTES264* Even though the function is documented to take a pointer to an unsigned265* long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which266* the first parameter is an unsigned long.267* This function is only intended to be called by the RPC runtime.268*/269unsigned char * __RPC_USER CLIPFORMAT_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, CLIPFORMAT *pCF)270{271LONG fContext;272273TRACE("%s, %p, %p.\n", debugstr_user_flags(pFlags), pBuffer, pCF);274275ALIGN_POINTER(pBuffer, 3);276277fContext = *(DWORD *)pBuffer;278pBuffer += 4;279280if (fContext == WDT_INPROC_CALL)281{282*pCF = *(CLIPFORMAT *)pBuffer;283pBuffer += 4;284}285else if (fContext == WDT_REMOTE_CALL)286{287CLIPFORMAT cf;288UINT len;289290/* pointer ID for registered clip format string */291if (*(DWORD *)pBuffer == 0)292RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL);293pBuffer += 4;294295len = *(UINT *)pBuffer;296pBuffer += sizeof(UINT);297if (*(UINT *)pBuffer != 0)298RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL);299pBuffer += sizeof(UINT);300if (*(UINT *)pBuffer != len)301RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL);302pBuffer += sizeof(UINT);303if (((WCHAR *)pBuffer)[len - 1] != '\0')304RaiseException(RPC_S_INVALID_BOUND, 0, 0, NULL);305TRACE("unmarshaling clip format %s\n", debugstr_w((LPCWSTR)pBuffer));306cf = RegisterClipboardFormatW((LPCWSTR)pBuffer);307pBuffer += len * sizeof(WCHAR);308if (!cf)309RaiseException(DV_E_CLIPFORMAT, 0, 0, NULL);310*pCF = cf;311}312else313/* code not really appropriate, but nearest I can find */314RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);315return pBuffer;316}317318/******************************************************************************319* CLIPFORMAT_UserFree (combase.@)320*321* Frees an unmarshaled clip format.322*323* PARAMS324* pFlags [I] Flags. See notes.325* pCF [I] Clip format to free.326*327* RETURNS328* The end of the marshaled data in the buffer.329*330* NOTES331* Even though the function is documented to take a pointer to an unsigned332* long in pFlags, it actually takes a pointer to a USER_MARSHAL_CB333* structure, of which the first parameter is an unsigned long.334* This function is only intended to be called by the RPC runtime.335*/336void __RPC_USER CLIPFORMAT_UserFree(ULONG *pFlags, CLIPFORMAT *pCF)337{338/* there is no inverse of the RegisterClipboardFormat function,339* so nothing to do */340}341342/******************************************************************************343* HBITMAP_UserSize (combase.@)344*345* Calculates the buffer size required to marshal a bitmap.346*347* PARAMS348* pFlags [I] Flags. See notes.349* StartingSize [I] Starting size of the buffer. This value is added on to350* the buffer size required for the clip format.351* phBmp [I] Bitmap to size.352*353* RETURNS354* The buffer size required to marshal an bitmap plus the starting size.355*356* NOTES357* Even though the function is documented to take a pointer to a ULONG in358* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which359* the first parameter is a ULONG.360* This function is only intended to be called by the RPC runtime.361*/362ULONG __RPC_USER HBITMAP_UserSize(ULONG *flags, ULONG size, HBITMAP *bmp)363{364TRACE("%s, %lu, %p.\n", debugstr_user_flags(flags), size, *bmp);365366ALIGN_LENGTH(size, 3);367368size += sizeof(ULONG);369if (LOWORD(*flags) == MSHCTX_INPROC)370size += sizeof(ULONG);371else372{373size += sizeof(ULONG);374375if (*bmp)376{377size += sizeof(ULONG);378size += FIELD_OFFSET(userBITMAP, cbSize);379size += GetBitmapBits(*bmp, 0, NULL);380}381}382383return size;384}385386/******************************************************************************387* HBITMAP_UserMarshal (combase.@)388*389* Marshals a bitmap into a buffer.390*391* PARAMS392* pFlags [I] Flags. See notes.393* pBuffer [I] Buffer to marshal the clip format into.394* phBmp [I] Bitmap to marshal.395*396* RETURNS397* The end of the marshaled data in the buffer.398*399* NOTES400* Even though the function is documented to take a pointer to a ULONG in401* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which402* the first parameter is a ULONG.403* This function is only intended to be called by the RPC runtime.404*/405unsigned char * __RPC_USER HBITMAP_UserMarshal(ULONG *flags, unsigned char *buffer, HBITMAP *bmp)406{407TRACE("(%s, %p, %p)\n", debugstr_user_flags(flags), buffer, *bmp);408409ALIGN_POINTER(buffer, 3);410411if (LOWORD(*flags) == MSHCTX_INPROC)412{413*(ULONG *)buffer = WDT_INPROC_CALL;414buffer += sizeof(ULONG);415*(ULONG *)buffer = (ULONG)(ULONG_PTR)*bmp;416buffer += sizeof(ULONG);417}418else419{420*(ULONG *)buffer = WDT_REMOTE_CALL;421buffer += sizeof(ULONG);422*(ULONG *)buffer = (ULONG)(ULONG_PTR)*bmp;423buffer += sizeof(ULONG);424425if (*bmp)426{427static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize);428BITMAP bitmap;429ULONG bitmap_size;430431bitmap_size = GetBitmapBits(*bmp, 0, NULL);432*(ULONG *)buffer = bitmap_size;433buffer += sizeof(ULONG);434435GetObjectW(*bmp, sizeof(BITMAP), &bitmap);436memcpy(buffer, &bitmap, header_size);437buffer += header_size;438439GetBitmapBits(*bmp, bitmap_size, buffer);440buffer += bitmap_size;441}442}443return buffer;444}445446/******************************************************************************447* HBITMAP_UserUnmarshal (combase.@)448*449* Unmarshals a bitmap from a buffer.450*451* PARAMS452* pFlags [I] Flags. See notes.453* pBuffer [I] Buffer to marshal the clip format from.454* phBmp [O] Address that receive the unmarshaled bitmap.455*456* RETURNS457* The end of the marshaled data in the buffer.458*459* NOTES460* Even though the function is documented to take a pointer to an ULONG in461* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which462* the first parameter is an ULONG.463* This function is only intended to be called by the RPC runtime.464*/465unsigned char * __RPC_USER HBITMAP_UserUnmarshal(ULONG *flags, unsigned char *buffer, HBITMAP *bmp)466{467ULONG context;468469TRACE("(%s, %p, %p)\n", debugstr_user_flags(flags), buffer, bmp);470471ALIGN_POINTER(buffer, 3);472473context = *(ULONG *)buffer;474buffer += sizeof(ULONG);475476if (context == WDT_INPROC_CALL)477{478*bmp = *(HBITMAP *)buffer;479buffer += sizeof(*bmp);480}481else if (context == WDT_REMOTE_CALL)482{483ULONG handle = *(ULONG *)buffer;484buffer += sizeof(ULONG);485486if (handle)487{488static const ULONG header_size = FIELD_OFFSET(userBITMAP, cbSize);489BITMAP bitmap;490ULONG bitmap_size;491unsigned char *bits;492493bitmap_size = *(ULONG *)buffer;494buffer += sizeof(ULONG);495bits = malloc(bitmap_size);496497memcpy(&bitmap, buffer, header_size);498buffer += header_size;499500memcpy(bits, buffer, bitmap_size);501buffer += bitmap_size;502503bitmap.bmBits = bits;504*bmp = CreateBitmapIndirect(&bitmap);505506free(bits);507}508else509*bmp = NULL;510}511else512RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);513514return buffer;515}516517/******************************************************************************518* HBITMAP_UserFree (combase.@)519*520* Frees an unmarshaled bitmap.521*522* PARAMS523* pFlags [I] Flags. See notes.524* phBmp [I] Bitmap to free.525*526* RETURNS527* The end of the marshaled data in the buffer.528*529* NOTES530* Even though the function is documented to take a pointer to a ULONG in531* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of532* which the first parameter is a ULONG.533* This function is only intended to be called by the RPC runtime.534*/535void __RPC_USER HBITMAP_UserFree(ULONG *flags, HBITMAP *bmp)536{537TRACE("(%s, %p)\n", debugstr_user_flags(flags), *bmp);538539if (LOWORD(*flags) != MSHCTX_INPROC)540DeleteObject(*bmp);541}542543/******************************************************************************544* HPALETTE_UserSize (combase.@)545*546* Calculates the buffer size required to marshal a palette.547*548* PARAMS549* pFlags [I] Flags. See notes.550* StartingSize [I] Starting size of the buffer. This value is added on to551* the buffer size required for the clip format.552* phPal [I] Palette to size.553*554* RETURNS555* The buffer size required to marshal a palette plus the starting size.556*557* NOTES558* Even though the function is documented to take a pointer to a ULONG in559* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which560* the first parameter is a ULONG.561* This function is only intended to be called by the RPC runtime.562*/563ULONG __RPC_USER HPALETTE_UserSize(ULONG *pFlags, ULONG StartingSize, HPALETTE *phPal)564{565FIXME(":stub\n");566return StartingSize;567}568569/******************************************************************************570* HPALETTE_UserMarshal (combase.@)571*572* Marshals a palette into a buffer.573*574* PARAMS575* pFlags [I] Flags. See notes.576* pBuffer [I] Buffer to marshal the clip format into.577* phPal [I] Palette to marshal.578*579* RETURNS580* The end of the marshaled data in the buffer.581*582* NOTES583* Even though the function is documented to take a pointer to a ULONG in584* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which585* the first parameter is a ULONG.586* This function is only intended to be called by the RPC runtime.587*/588unsigned char * __RPC_USER HPALETTE_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HPALETTE *phPal)589{590FIXME(":stub\n");591return pBuffer;592}593594/******************************************************************************595* HPALETTE_UserUnmarshal (combase.@)596*597* Unmarshals a palette from a buffer.598*599* PARAMS600* pFlags [I] Flags. See notes.601* pBuffer [I] Buffer to marshal the clip format from.602* phPal [O] Address that receive the unmarshaled palette.603*604* RETURNS605* The end of the marshaled data in the buffer.606*607* NOTES608* Even though the function is documented to take a pointer to an ULONG in609* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which610* the first parameter is an ULONG.611* This function is only intended to be called by the RPC runtime.612*/613unsigned char * __RPC_USER HPALETTE_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HPALETTE *phPal)614{615FIXME(":stub\n");616return pBuffer;617}618619/******************************************************************************620* HGLOBAL_UserSize (combase.@)621*622* Calculates the buffer size required to marshal an HGLOBAL.623*624* PARAMS625* pFlags [I] Flags. See notes.626* StartingSize [I] Starting size of the buffer. This value is added on to627* the buffer size required for the clip format.628* phGlobal [I] HGLOBAL to size.629*630* RETURNS631* The buffer size required to marshal an HGLOBAL plus the starting size.632*633* NOTES634* Even though the function is documented to take a pointer to a ULONG in635* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which636* the first parameter is a ULONG.637* This function is only intended to be called by the RPC runtime.638*/639ULONG __RPC_USER HGLOBAL_UserSize(ULONG *pFlags, ULONG StartingSize, HGLOBAL *phGlobal)640{641ULONG size = StartingSize;642643TRACE("%s, %lu, %p.\n", debugstr_user_flags(pFlags), StartingSize, phGlobal);644645ALIGN_LENGTH(size, 3);646647size += sizeof(ULONG);648649if (LOWORD(*pFlags) == MSHCTX_INPROC)650size += sizeof(HGLOBAL);651else652{653size += sizeof(ULONG);654if (*phGlobal)655{656SIZE_T ret;657size += 3 * sizeof(ULONG);658ret = GlobalSize(*phGlobal);659size += (ULONG)ret;660}661}662663return size;664}665666/******************************************************************************667* HGLOBAL_UserMarshal (combase.@)668*669* Marshals an HGLOBAL into a buffer.670*671* PARAMS672* pFlags [I] Flags. See notes.673* pBuffer [I] Buffer to marshal the clip format into.674* phGlobal [I] HGLOBAL to marshal.675*676* RETURNS677* The end of the marshaled data in the buffer.678*679* NOTES680* Even though the function is documented to take a pointer to a ULONG in681* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which682* the first parameter is a ULONG.683* This function is only intended to be called by the RPC runtime.684*/685unsigned char * __RPC_USER HGLOBAL_UserMarshal(ULONG *pFlags, unsigned char *pBuffer, HGLOBAL *phGlobal)686{687TRACE("%s, %p, &%p.\n", debugstr_user_flags(pFlags), pBuffer, *phGlobal);688689ALIGN_POINTER(pBuffer, 3);690691if (LOWORD(*pFlags) == MSHCTX_INPROC)692{693if (sizeof(*phGlobal) == 8)694*(ULONG *)pBuffer = WDT_INPROC64_CALL;695else696*(ULONG *)pBuffer = WDT_INPROC_CALL;697pBuffer += sizeof(ULONG);698*(HGLOBAL *)pBuffer = *phGlobal;699pBuffer += sizeof(HGLOBAL);700}701else702{703*(ULONG *)pBuffer = WDT_REMOTE_CALL;704pBuffer += sizeof(ULONG);705*(ULONG *)pBuffer = HandleToULong(*phGlobal);706pBuffer += sizeof(ULONG);707if (*phGlobal)708{709const unsigned char *memory;710SIZE_T size = GlobalSize(*phGlobal);711*(ULONG *)pBuffer = (ULONG)size;712pBuffer += sizeof(ULONG);713*(ULONG *)pBuffer = HandleToULong(*phGlobal);714pBuffer += sizeof(ULONG);715*(ULONG *)pBuffer = (ULONG)size;716pBuffer += sizeof(ULONG);717718memory = GlobalLock(*phGlobal);719memcpy(pBuffer, memory, size);720pBuffer += size;721GlobalUnlock(*phGlobal);722}723}724725return pBuffer;726}727728/******************************************************************************729* HGLOBAL_UserUnmarshal (combase.@)730*731* Unmarshals an HGLOBAL from a buffer.732*733* PARAMS734* pFlags [I] Flags. See notes.735* pBuffer [I] Buffer to marshal the clip format from.736* phGlobal [O] Address that receive the unmarshaled HGLOBAL.737*738* RETURNS739* The end of the marshaled data in the buffer.740*741* NOTES742* Even though the function is documented to take a pointer to an ULONG in743* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which744* the first parameter is an ULONG.745* This function is only intended to be called by the RPC runtime.746*/747unsigned char * __RPC_USER HGLOBAL_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, HGLOBAL *phGlobal)748{749ULONG fContext;750751TRACE("%s, %p, &%p.\n", debugstr_user_flags(pFlags), pBuffer, *phGlobal);752753ALIGN_POINTER(pBuffer, 3);754755fContext = *(ULONG *)pBuffer;756pBuffer += sizeof(ULONG);757758if (((fContext == WDT_INPROC_CALL) && (sizeof(*phGlobal) < 8)) ||759((fContext == WDT_INPROC64_CALL) && (sizeof(*phGlobal) == 8)))760{761*phGlobal = *(HGLOBAL *)pBuffer;762pBuffer += sizeof(*phGlobal);763}764else if (fContext == WDT_REMOTE_CALL)765{766ULONG handle;767768handle = *(ULONG *)pBuffer;769pBuffer += sizeof(ULONG);770771if (handle)772{773ULONG size;774void *memory;775776size = *(ULONG *)pBuffer;777pBuffer += sizeof(ULONG);778/* redundancy is bad - it means you have to check consistency like779* this: */780if (*(ULONG *)pBuffer != handle)781{782RaiseException(RPC_X_BAD_STUB_DATA, 0, 0, NULL);783return pBuffer;784}785pBuffer += sizeof(ULONG);786/* redundancy is bad - it means you have to check consistency like787* this: */788if (*(ULONG *)pBuffer != size)789{790RaiseException(RPC_X_BAD_STUB_DATA, 0, 0, NULL);791return pBuffer;792}793pBuffer += sizeof(ULONG);794795/* FIXME: check size is not too big */796797*phGlobal = GlobalAlloc(GMEM_MOVEABLE, size);798memory = GlobalLock(*phGlobal);799memcpy(memory, pBuffer, size);800pBuffer += size;801GlobalUnlock(*phGlobal);802}803else804*phGlobal = NULL;805}806else807RaiseException(RPC_S_INVALID_TAG, 0, 0, NULL);808809return pBuffer;810}811812/******************************************************************************813* HGLOBAL_UserFree (combase.@)814*815* Frees an unmarshaled HGLOBAL.816*817* PARAMS818* pFlags [I] Flags. See notes.819* phGlobal [I] HGLOBAL to free.820*821* RETURNS822* The end of the marshaled data in the buffer.823*824* NOTES825* Even though the function is documented to take a pointer to a ULONG in826* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of827* which the first parameter is a ULONG.828* This function is only intended to be called by the RPC runtime.829*/830void __RPC_USER HGLOBAL_UserFree(ULONG *pFlags, HGLOBAL *phGlobal)831{832TRACE("%s, &%p.\n", debugstr_user_flags(pFlags), *phGlobal);833834if (LOWORD(*pFlags) != MSHCTX_INPROC && *phGlobal)835GlobalFree(*phGlobal);836}837838/******************************************************************************839* HPALETTE_UserFree (combase.@)840*841* Frees an unmarshaled palette.842*843* PARAMS844* pFlags [I] Flags. See notes.845* phPal [I] Palette to free.846*847* RETURNS848* The end of the marshaled data in the buffer.849*850* NOTES851* Even though the function is documented to take a pointer to a ULONG in852* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of853* which the first parameter is a ULONG.854* This function is only intended to be called by the RPC runtime.855*/856void __RPC_USER HPALETTE_UserFree(ULONG *pFlags, HPALETTE *phPal)857{858FIXME(":stub\n");859}860861/******************************************************************************862* WdtpInterfacePointer_UserSize (combase.@)863*864* Calculates the buffer size required to marshal an interface pointer.865*866* PARAMS867* pFlags [I] Flags. See notes.868* RealFlags [I] The MSHCTX to use when marshaling the interface.869* punk [I] Interface pointer to size.870* StartingSize [I] Starting size of the buffer. This value is added on to871* the buffer size required for the clip format.872* riid [I] ID of interface to size.873*874* RETURNS875* The buffer size required to marshal an interface pointer plus the starting size.876*877* NOTES878* Even though the function is documented to take a pointer to a ULONG in879* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which880* the first parameter is a ULONG.881*/882ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *pFlags, ULONG RealFlags, ULONG StartingSize, IUnknown *punk, REFIID riid)883{884DWORD marshal_size = 0;885HRESULT hr;886887TRACE("%s, %#lx, %lu, %p, %s.\n", debugstr_user_flags(pFlags), RealFlags, StartingSize, punk, debugstr_guid(riid));888889hr = CoGetMarshalSizeMax(&marshal_size, riid, punk, LOWORD(RealFlags), NULL, MSHLFLAGS_NORMAL);890if (FAILED(hr)) return StartingSize;891892ALIGN_LENGTH(StartingSize, 3);893StartingSize += 2 * sizeof(DWORD);894return StartingSize + marshal_size;895}896897/******************************************************************************898* WdtpInterfacePointer_UserMarshal (combase.@)899*900* Marshals an interface pointer into a buffer.901*902* PARAMS903* pFlags [I] Flags. See notes.904* RealFlags [I] The MSHCTX to use when marshaling the interface.905* pBuffer [I] Buffer to marshal the clip format into.906* punk [I] Interface pointer to marshal.907* riid [I] ID of interface to marshal.908*909* RETURNS910* The end of the marshaled data in the buffer.911*912* NOTES913* Even though the function is documented to take a pointer to a ULONG in914* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which915* the first parameter is a ULONG.916*/917unsigned char * WINAPI WdtpInterfacePointer_UserMarshal(ULONG *pFlags, ULONG RealFlags, unsigned char *pBuffer, IUnknown *punk, REFIID riid)918{919HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, 0);920IStream *stm;921DWORD size;922void *ptr;923924TRACE("%s, %#lx, %p, &%p, %s.\n", debugstr_user_flags(pFlags), RealFlags, pBuffer, punk, debugstr_guid(riid));925926if (!h) return NULL;927if (CreateStreamOnHGlobal(h, TRUE, &stm) != S_OK)928{929GlobalFree(h);930return NULL;931}932933if (CoMarshalInterface(stm, riid, punk, LOWORD(RealFlags), NULL, MSHLFLAGS_NORMAL) != S_OK)934{935IStream_Release(stm);936return pBuffer;937}938939ALIGN_POINTER(pBuffer, 3);940size = GlobalSize(h);941942*(DWORD *)pBuffer = size;943pBuffer += sizeof(DWORD);944*(DWORD *)pBuffer = size;945pBuffer += sizeof(DWORD);946947ptr = GlobalLock(h);948memcpy(pBuffer, ptr, size);949GlobalUnlock(h);950951IStream_Release(stm);952return pBuffer + size;953}954955/******************************************************************************956* WdtpInterfacePointer_UserUnmarshal (combase.@)957*958* Unmarshals an interface pointer from a buffer.959*960* PARAMS961* pFlags [I] Flags. See notes.962* pBuffer [I] Buffer to marshal the clip format from.963* ppunk [I/O] Address that receives the unmarshaled interface pointer.964* riid [I] ID of interface to unmarshal.965*966* RETURNS967* The end of the marshaled data in the buffer.968*969* NOTES970* Even though the function is documented to take a pointer to an ULONG in971* pFlags, it actually takes a pointer to a USER_MARSHAL_CB structure, of which972* the first parameter is an ULONG.973*/974unsigned char * WINAPI WdtpInterfacePointer_UserUnmarshal(ULONG *pFlags, unsigned char *pBuffer, IUnknown **ppunk, REFIID riid)975{976HRESULT hr;977HGLOBAL h;978IStream *stm;979DWORD size;980void *ptr;981IUnknown *orig;982983TRACE("%s, %p, %p, %s.\n", debugstr_user_flags(pFlags), pBuffer, ppunk, debugstr_guid(riid));984985ALIGN_POINTER(pBuffer, 3);986987size = *(DWORD *)pBuffer;988pBuffer += sizeof(DWORD);989if (size != *(DWORD *)pBuffer)990RaiseException(RPC_X_BAD_STUB_DATA, 0, 0, NULL);991992pBuffer += sizeof(DWORD);993994/* FIXME: sanity check on size */995996h = GlobalAlloc(GMEM_MOVEABLE, size);997if (!h) RaiseException(RPC_X_NO_MEMORY, 0, 0, NULL);998999if (CreateStreamOnHGlobal(h, TRUE, &stm) != S_OK)1000{1001GlobalFree(h);1002RaiseException(RPC_X_NO_MEMORY, 0, 0, NULL);1003}10041005ptr = GlobalLock(h);1006memcpy(ptr, pBuffer, size);1007GlobalUnlock(h);10081009orig = *ppunk;1010hr = CoUnmarshalInterface(stm, riid, (void**)ppunk);1011IStream_Release(stm);10121013if (hr != S_OK) RaiseException(hr, 0, 0, NULL);10141015if (orig) IUnknown_Release(orig);10161017return pBuffer + size;1018}10191020/******************************************************************************1021* WdtpInterfacePointer_UserFree (combase.@)1022*/1023void WINAPI WdtpInterfacePointer_UserFree(IUnknown *punk)1024{1025TRACE("%p.\n", punk);1026if (punk) IUnknown_Release(punk);1027}10281029struct hstring_wire_inproc1030{1031ULONG context;1032HSTRING str;1033};10341035struct hstring_wire_local1036{1037ULONG context;1038ULONG size;1039WCHAR data[1];1040};10411042/******************************************************************************1043* HSTRING_UserSize (combase.@)1044*/1045ULONG __RPC_USER HSTRING_UserSize(ULONG *flags, ULONG size, HSTRING *str)1046{1047TRACE("%s, %lu, %s.\n", debugstr_user_flags(flags), size, debugstr_hstring(*str));10481049ALIGN_LENGTH(size, 7);1050if (LOWORD(*flags) == MSHCTX_INPROC)1051size += sizeof(struct hstring_wire_inproc);1052else1053size += offsetof(struct hstring_wire_local, data[WindowsGetStringLen(*str)]);1054return size;1055}10561057/******************************************************************************1058* HSTRING_UserMarshal (combase.@)1059*/1060BYTE * __RPC_USER HSTRING_UserMarshal(ULONG *flags, BYTE *buf, HSTRING *str)1061{1062const ULONG context = sizeof(*str) == 8 ? WDT_INPROC64_CALL : WDT_INPROC_CALL;10631064TRACE("%s, %p, %s.\n", debugstr_user_flags(flags), buf, debugstr_hstring(*str));10651066if (LOWORD(*flags) == MSHCTX_DIFFERENTMACHINE)1067{1068FIXME("MSHCTX_DIFFERENTMACHINE is not supported yet.\n");1069RpcRaiseException(RPC_S_INVALID_TAG);1070}10711072if (LOWORD(*flags) == MSHCTX_INPROC)1073{1074struct hstring_wire_inproc *wire = ALIGNED_POINTER(buf, 7);10751076wire->context = context;1077WindowsDuplicateString(*str, &wire->str);1078buf = (BYTE *)(wire + 1);1079}1080else1081{1082struct hstring_wire_local *wire = ALIGNED_POINTER(buf, 7);1083const WCHAR *str_buf;1084UINT32 len;10851086wire->context = context;1087str_buf = WindowsGetStringRawBuffer(*str, &len);1088wire->size = len * sizeof(WCHAR);1089memcpy(wire->data, str_buf, wire->size);1090buf = (BYTE *)&wire->data[len];1091}10921093return buf;1094}10951096/******************************************************************************1097* HSTRING_UserUnmarshal (combase.@)1098*/1099BYTE * __RPC_USER HSTRING_UserUnmarshal(ULONG *flags, BYTE *buf, HSTRING *str)1100{1101TRACE("%p, %p, %p\n", debugstr_user_flags(flags), buf, str);11021103if (LOWORD(*flags) == MSHCTX_INPROC)1104{1105const struct hstring_wire_inproc *wire = ALIGNED_POINTER(buf, 7);11061107*str = wire->str;1108TRACE("str=%s\n", debugstr_hstring(*str));1109buf = (BYTE *)(wire + 1);1110}1111else1112{1113const struct hstring_wire_local *wire = ALIGNED_POINTER(buf, 7);1114UINT32 len;1115HRESULT hr;11161117len = wire->size / sizeof(WCHAR);1118hr = WindowsCreateString(wire->data, len, str);1119if (FAILED(hr))1120RpcRaiseException(RPC_S_OUT_OF_MEMORY);1121buf = (BYTE *)&wire->data[len];1122}11231124return buf;1125}11261127/******************************************************************************1128* HSTRING_UserFree (combase.@)1129*/1130void __RPC_USER HSTRING_UserFree(ULONG *flags, HSTRING *str)1131{1132TRACE("%s, %s.\n", debugstr_user_flags(flags), debugstr_hstring(*str));11331134if (LOWORD(*flags) == MSHCTX_INPROC)1135WindowsDeleteString(*str);1136}113711381139