⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usrmarshal.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * 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
#define NONAMELESSSTRUCT

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"

#include "ole2.h"
#include "oleauto.h"
#include "rpcproxy.h"
#include "typelib.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)

static CStdPSFactoryBuffer PSFactoryBuffer;

CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer)

extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo;

static const ProxyFileInfo *OLEAUT32_ProxyFileList[] = {
  &oaidl_ProxyFileInfo,
  NULL
};

HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
  return NdrDllGetClassObject(rclsid, riid, ppv, OLEAUT32_ProxyFileList,
                              &CLSID_PSDispatch, &PSFactoryBuffer);
}

static void dump_user_flags(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;
    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(*pstr)
    {
        SysFreeString(*pstr);
        *pstr = NULL;
    }

    if(header->byte_len != 0xffffffff)
        *pstr = SysAllocStringByteLen((char*)(header + 1), header->byte_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);
    if (*pstr)
    {
        SysFreeString(*pstr);
        *pstr = NULL;
    }
}

/* VARIANT */

typedef struct
{
    DWORD clSize;
    DWORD rpcReserverd;
    USHORT vt;
    USHORT wReserved1;
    USHORT wReserved2;
    USHORT wReserved3;
    DWORD switch_is;
} variant_wire_t;

static unsigned int get_type_size(ULONG *pFlags, VARIANT *pvar)
{
    if (V_VT(pvar) & VT_ARRAY) return 4;

    switch (V_VT(pvar) & ~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:
        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(BSTR);
    case VT_VARIANT:
        return sizeof(VARIANT);
    case VT_UNKNOWN:
    case VT_DISPATCH:
    case VT_RECORD:
        return 0;
    default:
        FIXME("unhandled VT %d\n", V_VT(pvar));
        return 0;
    }
}

static unsigned int get_type_alignment(ULONG *pFlags, VARIANT *pvar)
{
    unsigned int size = get_type_size(pFlags, pvar);
    if(V_VT(pvar) & VT_BYREF) return 3;
    if(size == 0) return 0;
    if(size <= 4) return size - 1;
    return 7;
}

static unsigned interface_variant_size(ULONG *pFlags, REFIID riid, IUnknown *punk)
{
  ULONG size;
  HRESULT hr;
  /* find the buffer size of the marshalled dispatch interface */
  hr = CoGetMarshalSizeMax(&size, riid, punk, LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
  if (FAILED(hr)) {
    if (!punk)
      WARN("NULL dispatch pointer\n");
    else
      ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%x\n", hr);
    return 0;
  }
  size += sizeof(ULONG); /* we have to store the buffersize in the stream */
  TRACE("wire-size extra of dispatch 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. returns Buffer on failure, new position otherwise */
static unsigned char* interface_variant_marshal(ULONG *pFlags, unsigned char *Buffer, REFIID riid, IUnknown *punk)
{
  IStream *working; 
  HGLOBAL working_mem;
  void *working_memlocked;
  unsigned char *oldpos;
  ULONG size;
  HRESULT hr;
  
  TRACE("pFlags=%d, Buffer=%p, pUnk=%p\n", *pFlags, Buffer, punk);

  oldpos = Buffer;
  
  /* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers.
   * We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer.
   * in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object,
   * but that would be overkill here, hence this implementation. We save the size because the unmarshal
   * code has no way to know how long the marshalled buffer is. */

  size = interface_variant_size(pFlags, riid, punk);
  
  working_mem = GlobalAlloc(0, size);
  if (!working_mem) return oldpos;

  hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
  if (hr != S_OK) {
    GlobalFree(working_mem);
    return oldpos;
  }
  
  hr = CoMarshalInterface(working, riid, punk, LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
  if (hr != S_OK) {
    IStream_Release(working); /* this also releases the hglobal */
    return oldpos;
  }

  working_memlocked = GlobalLock(working_mem);
  memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */
  memcpy(Buffer + sizeof(ULONG), working_memlocked, size - sizeof(ULONG));
  GlobalUnlock(working_mem);

  IStream_Release(working);

  /* size includes the ULONG for the size written above */
  TRACE("done, size=%d\n", size);
  return Buffer + size;
}

/* helper: called for VT_DISPATCH / VT_UNKNOWN variants to unmarshal the buffer. returns Buffer on failure, new position otherwise */
static unsigned char *interface_variant_unmarshal(ULONG *pFlags, unsigned char *Buffer, REFIID riid, IUnknown **ppunk)
{
  IStream *working;
  HGLOBAL working_mem;
  void *working_memlocked;
  unsigned char *oldpos;
  ULONG size;
  HRESULT hr;
  
  TRACE("pFlags=%d, Buffer=%p, ppUnk=%p\n", *pFlags, Buffer, ppunk);

  oldpos = Buffer;

  /* get the buffersize */
  memcpy(&size, Buffer, sizeof(ULONG));
  TRACE("buffersize=%d\n", size);

  working_mem = GlobalAlloc(0, size);
  if (!working_mem) return oldpos;

  hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
  if (hr != S_OK) {
    GlobalFree(working_mem);
    return oldpos;
  }

  working_memlocked = GlobalLock(working_mem);
  
  /* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */
  memcpy(working_memlocked, Buffer + sizeof(ULONG), size);
  GlobalUnlock(working_mem);

  hr = CoUnmarshalInterface(working, riid, (void**)ppunk);
  if (hr != S_OK) {
    IStream_Release(working);
    return oldpos;
  }

  IStream_Release(working); /* this also frees the underlying hglobal */

  /* size includes the ULONG for the size written above */
  TRACE("done, processed=%d bytes\n", size);
  return Buffer + size;
}


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, pvar);
    ALIGN_LENGTH(Start, align);
    if(V_VT(pvar) == (VT_VARIANT | VT_BYREF))
        Start += 4;
    else
        Start += get_type_size(pFlags, 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->rpcReserverd = 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, pvar);
    align = get_type_alignment(pFlags, 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -