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

📄 usrmarshal.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(ole);

/* FIXME: not supposed to be here */

const CLSID CLSID_PSDispatch = {
  0x20420, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
};

static CStdPSFactoryBuffer PSFactoryBuffer;

CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer)

extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo;

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(unsigned long *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 */
/* I'm not sure how this is supposed to work yet */

unsigned long WINAPI CLEANLOCALSTORAGE_UserSize(unsigned long *pFlags, unsigned long Start, CLEANLOCALSTORAGE *pstg)
{
  return Start + sizeof(DWORD);
}

unsigned char * WINAPI CLEANLOCALSTORAGE_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstg)
{
  *(DWORD*)Buffer = 0;
  return Buffer + sizeof(DWORD);
}

unsigned char * WINAPI CLEANLOCALSTORAGE_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstr)
{
  return Buffer + sizeof(DWORD);
}

void WINAPI CLEANLOCALSTORAGE_UserFree(unsigned long *pFlags, CLEANLOCALSTORAGE *pstr)
{
}

/* BSTR */

unsigned long WINAPI BSTR_UserSize(unsigned long *pFlags, unsigned long Start, BSTR *pstr)
{
  TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr);
  if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
  Start += sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (SysStringLen(*pstr) - 1);
  TRACE("returning %ld\n", Start);
  return Start;
}

unsigned char * WINAPI BSTR_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr)
{
  wireBSTR str = (wireBSTR)Buffer;

  TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
  if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
  str->fFlags = 0;
  str->clSize = SysStringLen(*pstr);
  if (str->clSize)
    memcpy(&str->asData, *pstr, sizeof(OLECHAR) * str->clSize);
  return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1);
}

unsigned char * WINAPI BSTR_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr)
{
  wireBSTR str = (wireBSTR)Buffer;
  TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr);
  if (str->clSize) {
    SysReAllocStringLen(pstr, (OLECHAR*)&str->asData, str->clSize);
  }
  else if (*pstr) {
    SysFreeString(*pstr);
    *pstr = NULL;
  }
  if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr));
  return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1);
}

void WINAPI BSTR_UserFree(unsigned long *pFlags, BSTR *pstr)
{
  TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr);
  if (*pstr) {
    SysFreeString(*pstr);
    *pstr = NULL;
  }
}

/* VARIANT */
/* I'm not too sure how to do this yet */

#define VARIANT_wiresize sizeof(struct _wireVARIANT)

static unsigned wire_size(VARTYPE vt)
{
  if (vt & VT_ARRAY) return 0;

  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:
    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:
  case VT_VARIANT:
  case VT_UNKNOWN:
  case VT_DISPATCH:
  case VT_SAFEARRAY:
  case VT_RECORD:
    return 0;
  default:
    FIXME("unhandled VT %d\n", vt);
    return 0;
  }
}

static unsigned interface_variant_size(unsigned long *pFlags, REFIID riid, VARIANT *pvar)
{
  ULONG size;
  HRESULT hr;
  /* find the buffer size of the marshalled dispatch interface */
  hr = CoGetMarshalSizeMax(&size, riid, V_UNKNOWN(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
  if (FAILED(hr)) {
    if (!V_DISPATCH(pvar))
      WARN("NULL dispatch pointer\n");
    else
      ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%lx\n", hr);
    return 0;
  }
  size += sizeof(ULONG); /* we have to store the buffersize in the stream */
  TRACE("wire-size extra of dispatch variant is %ld\n", size);
  return size;
}

static unsigned wire_extra(unsigned long *pFlags, VARIANT *pvar)
{
  if (V_ISARRAY(pvar)) {
    FIXME("wire-size safearray\n");
    return 0;
  }
  switch (V_VT(pvar)) {
  case VT_BSTR:
    return BSTR_UserSize(pFlags, 0, &V_BSTR(pvar));
  case VT_BSTR | VT_BYREF:
    return BSTR_UserSize(pFlags, 0, V_BSTRREF(pvar));
  case VT_SAFEARRAY:
  case VT_SAFEARRAY | VT_BYREF:
    FIXME("wire-size safearray\n");
    return 0;
  case VT_VARIANT | VT_BYREF:
    return VARIANT_UserSize(pFlags, 0, V_VARIANTREF(pvar));
  case VT_UNKNOWN:
    return interface_variant_size(pFlags, &IID_IUnknown, pvar);
  case VT_DISPATCH:
    return interface_variant_size(pFlags, &IID_IDispatch, pvar);
  case VT_RECORD:
    FIXME("wire-size record\n");
    return 0;
  default:
    return 0;
  }
}

/* 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(unsigned long *pFlags, unsigned char *Buffer, REFIID riid, VARIANT *pvar)
{
  IStream *working; 
  HGLOBAL working_mem;
  void *working_memlocked;
  unsigned char *oldpos;
  ULONG size;
  HRESULT hr;
  
  TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);

  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 = wire_extra(pFlags, pvar);
  
  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, V_UNKNOWN(pvar), 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 */
  Buffer += sizeof(ULONG);
  memcpy(Buffer, working_memlocked, size);
  GlobalUnlock(working_mem);

  IStream_Release(working);

  TRACE("done, size=%ld\n", sizeof(ULONG) + size);
  return Buffer + sizeof(ULONG) + 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(unsigned long *pFlags, unsigned char *Buffer, REFIID riid, VARIANT *pvar)
{
  IStream *working;
  HGLOBAL working_mem;
  void *working_memlocked;
  unsigned char *oldpos;
  ULONG size;
  HRESULT hr;
  
  TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar);

  oldpos = Buffer;
  
  /* get the buffersize */
  memcpy(&size, Buffer, sizeof(ULONG));
  TRACE("buffersize=%ld\n", size);
  Buffer += sizeof(ULONG);
  
  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, size);
  GlobalUnlock(working_mem);

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

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

  TRACE("done, processed=%ld bytes\n", sizeof(ULONG) + size);
  return Buffer + sizeof(ULONG) + size;
}


unsigned long WINAPI VARIANT_UserSize(unsigned long *pFlags, unsigned long Start, VARIANT *pvar)
{
  TRACE("(%lx,%ld,%p)\n", *pFlags, Start, pvar);
  TRACE("vt=%04x\n", V_VT(pvar));
  Start += VARIANT_wiresize + wire_extra(pFlags, pvar);
  TRACE("returning %ld\n", Start);
  return Start;
}

unsigned char * WINAPI VARIANT_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar)
{
  wireVARIANT var = (wireVARIANT)Buffer;
  unsigned size, extra;
  unsigned char *Pos = Buffer + VARIANT_wiresize;

  TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar);
  TRACE("vt=%04x\n", V_VT(pvar));

  memset(var, 0, sizeof(*var));
  var->clSize = sizeof(*var);
  var->vt = pvar->n1.n2.vt;

  var->rpcReserved = var->vt;
  if ((var->vt & VT_ARRAY) ||
      ((var->vt & VT_TYPEMASK) == VT_SAFEARRAY))
    var->vt = VT_ARRAY | (var->vt & VT_BYREF);

  if (var->vt == VT_DECIMAL) {
    /* special case because decVal is on a different level */
    var->u.decVal = pvar->n1.decVal;
    return Pos;
  }

  size = wire_size(V_VT(pvar));
  extra = wire_extra(pFlags, pvar);
  var->wReserved1 = pvar->n1.n2.wReserved1;
  var->wReserved2 = pvar->n1.n2.wReserved2;
  var->wReserved3 = pvar->n1.n2.wReserved3;
  if (size) {
    if (var->vt & VT_BYREF)
      memcpy(&var->u.cVal, pvar->n1.n2.n3.byref, size);
    else
      memcpy(&var->u.cVal, &pvar->n1.n2.n3, size);
  }
  if (!extra) return Pos;

  switch (var->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_DISPATCH | VT_BYREF:
    FIXME("handle DISPATCH by ref\n");
    break;
  case VT_UNKNOWN:
    /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
    Pos = interface_variant_marshal(pFlags, Pos, &IID_IUnknown, pvar);
    break;
  case VT_DISPATCH:
    /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
    Pos = interface_variant_marshal(pFlags, Pos, &IID_IDispatch, pvar);
    break;
  case VT_RECORD:
    FIXME("handle BRECORD by val\n");
    break;
  case VT_RECORD | VT_BYREF:
    FIXME("handle BRECORD by ref\n");
    break;
  default:
    FIXME("handle unknown complex type\n");
    break;
  }
  var->clSize = Pos - Buffer;
  TRACE("marshalled size=%ld\n", var->clSize);
  return Pos;
}

unsigned char * WINAPI VARIANT_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar)
{
  wireVARIANT var = (wireVARIANT)Buffer;
  unsigned size;
  unsigned char *Pos = Buffer + VARIANT_wiresize;

  TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar);
  VariantInit(pvar);
  pvar->n1.n2.vt = var->rpcReserved;
  TRACE("marshalled: clSize=%ld, vt=%04x\n", var->clSize, var->vt);
  TRACE("vt=%04x\n", V_VT(pvar));
  TRACE("reserved: %d, %d, %d\n", var->wReserved1, var->wReserved2, var->wReserved3);
  TRACE("val: %ld\n", var->u.lVal);

  if (var->vt == VT_DECIMAL) {
    /* special case because decVal is on a different level */
    pvar->n1.decVal = var->u.decVal;
    return Pos;
  }

  size = wire_size(V_VT(pvar));
  pvar->n1.n2.wReserved1 = var->wReserved1;
  pvar->n1.n2.wReserved2 = var->wReserved2;
  pvar->n1.n2.wReserved3 = var->wReserved3;
  if (size) {
    if (var->vt & VT_BYREF) {
      pvar->n1.n2.n3.byref = CoTaskMemAlloc(size);
      memcpy(pvar->n1.n2.n3.byref, &var->u.cVal, size);
    }
    else
      memcpy(&pvar->n1.n2.n3, &var->u.cVal, size);
  }
  if (var->clSize <= VARIANT_wiresize) return Pos;

  switch (var->vt) {
  case VT_BSTR:
    Pos = BSTR_UserUnmarshal(pFlags, Pos, &V_BSTR(pvar));
    break;
  case VT_BSTR | VT_BYREF:
    pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(BSTR));
    *(BSTR*)pvar->n1.n2.n3.byref = NULL;
    Pos = BSTR_UserUnmarshal(pFlags, Pos, V_BSTRREF(pvar));
    break;
  case VT_VARIANT | VT_BYREF:
    pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(VARIANT));
    Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar));
    break;
  case VT_RECORD:
    FIXME("handle BRECORD by val\n");
    break;
  case VT_RECORD | VT_BYREF:
    FIXME("handle BRECORD by ref\n");
    break;
  case VT_UNKNOWN:
    Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IUnknown, pvar);
    break;
  case VT_DISPATCH:
    Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IDispatch, pvar);
    break;
  case VT_DISPATCH | VT_BYREF:
    FIXME("handle DISPATCH by ref\n");
  default:
    FIXME("handle unknown complex type\n");
    break;
  }
  if (Pos != Buffer + var->clSize) {
    ERR("size difference during unmarshal\n");
  }
  return Buffer + var->clSize;
}

void WINAPI VARIANT_UserFree(unsigned long *pFlags, VARIANT *pvar)
{
  VARTYPE vt = V_VT(pvar);
  PVOID ref = NULL;

  TRACE("(%lx,%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;

  switch (vt) {
  case VT_BSTR | VT_BYREF:
    BSTR_UserFree(pFlags, ref);
    break;
  case VT_VARIANT | VT_BYREF:
    VARIANT_UserFree(pFlags, ref);
    break;
  case VT_RECORD | VT_BYREF:
    FIXME("handle BRECORD by ref\n");
    break;
  case VT_UNKNOWN:
  case VT_DISPATCH:
    IUnknown_Release(V_UNKNOWN(pvar));
    break;
  default:
    FIXME("handle unknown complex type\n");
    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;
}

⌨️ 快捷键说明

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