sync ole32 with wine 1.1.28
authorChristoph von Wittich <christoph_vw@reactos.org>
Mon, 24 Aug 2009 10:51:15 +0000 (10:51 +0000)
committerChristoph von Wittich <christoph_vw@reactos.org>
Mon, 24 Aug 2009 10:51:15 +0000 (10:51 +0000)
svn path=/trunk/; revision=42905

15 files changed:
reactos/dll/win32/ole32/clipboard.c
reactos/dll/win32/ole32/comcat.c
reactos/dll/win32/ole32/compobj.c
reactos/dll/win32/ole32/compobj_private.h
reactos/dll/win32/ole32/defaulthandler.c
reactos/dll/win32/ole32/errorinfo.c
reactos/dll/win32/ole32/ftmarshal.c
reactos/dll/win32/ole32/marshal.c
reactos/dll/win32/ole32/ole2.c
reactos/dll/win32/ole32/ole32.spec
reactos/dll/win32/ole32/stg_prop.c
reactos/dll/win32/ole32/stg_stream.c
reactos/dll/win32/ole32/storage32.c
reactos/dll/win32/ole32/storage32.h
reactos/dll/win32/ole32/stubmanager.c

index 1e72ec2..7f19d16 100644 (file)
@@ -744,6 +744,30 @@ static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *
     return hr;
 }
 
+static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
+{
+    HENHMETAFILE copy;
+    HRESULT hr;
+    FORMATETC mem_fmt;
+    STGMEDIUM med;
+
+    *mem = NULL;
+
+    mem_fmt = *fmt;
+    mem_fmt.tymed = TYMED_ENHMF;
+
+    hr = IDataObject_GetData(data, &mem_fmt, &med);
+    if(FAILED(hr)) return hr;
+
+    copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
+    if(copy) *mem = (HGLOBAL)copy;
+    else hr = E_FAIL;
+
+    ReleaseStgMedium(&med);
+
+    return hr;
+}
+
 /***********************************************************************
  *                render_format
  *
@@ -773,6 +797,10 @@ static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
     {
         hr = get_data_from_global(data, fmt, &clip_data);
     }
+    else if(fmt->tymed & TYMED_ENHMF)
+    {
+        hr = get_data_from_enhmetafile(data, fmt, &clip_data);
+    }
     else
     {
         FIXME("Unhandled tymed %x\n", fmt->tymed);
@@ -997,8 +1025,7 @@ static HRESULT get_priv_data(ole_priv_data **data)
         {
             char buf[100];
             GetClipboardFormatNameA(cf, buf, sizeof(buf));
-            TRACE("\tcf %04x %s\n", cf, buf);
-            ;
+            TRACE("cf %04x %s\n", cf, buf);
         }
         TRACE("count %d\n", count);
         size += count * sizeof(ret->entries[0]);
@@ -1106,6 +1133,22 @@ static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
     return hr;
 }
 
+/************************************************************************
+ *                    get_stgmed_for_emf
+ *
+ * Returns a stg medium with an enhanced metafile based on the handle
+ */
+static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
+{
+    med->pUnkForRelease = NULL;
+    med->tymed = TYMED_NULL;
+
+    med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
+    if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
+    med->tymed = TYMED_ENHMF;
+    return S_OK;
+}
+
 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
 {
     const WCHAR *str1, *str2;
@@ -1195,6 +1238,8 @@ static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
         hr = get_stgmed_for_global(h, med);
     else if(mask & TYMED_ISTREAM)
         hr = get_stgmed_for_stream(h, med);
+    else if(mask & TYMED_ENHMF)
+        hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
     else
     {
         FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
index cee1ebb..b8060bd 100644 (file)
@@ -278,7 +278,7 @@ static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface(
     LPVOID *ppvObj)
 {
     ComCatMgrImpl *This = (ComCatMgrImpl *)iface;
-    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+    TRACE("%s\n",debugstr_guid(riid));
 
     if (ppvObj == NULL) return E_POINTER;
 
@@ -515,7 +515,7 @@ static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc(
     HKEY key;
     HRESULT res;
 
-    TRACE("\n\tCATID:\t%s\n\tLCID:\t%X\n",debugstr_guid(rcatid), lcid);
+    TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid), lcid);
 
     if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG;
 
@@ -596,12 +596,12 @@ static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories(
 
     if (WINE_TRACE_ON(ole)) {
        ULONG count;
-       TRACE("\n\tCLSID:\t%s\n\tImplemented %u\n",debugstr_guid(rclsid),cImplemented);
+       TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid),cImplemented);
        for (count = 0; count < cImplemented; ++count)
-           TRACE("\t\t%s\n",debugstr_guid(&rgcatidImpl[count]));
-       TRACE("\tRequired %u\n",cRequired);
+           TRACE("    %s\n",debugstr_guid(&rgcatidImpl[count]));
+       TRACE("Required %u\n",cRequired);
        for (count = 0; count < cRequired; ++count)
-           TRACE("\t\t%s\n",debugstr_guid(&rgcatidReq[count]));
+           TRACE("    %s\n",debugstr_guid(&rgcatidReq[count]));
     }
 
     if ((cImplemented && rgcatidImpl == NULL) ||
@@ -637,7 +637,7 @@ static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass(
                          'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
                          'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
 
-    TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid));
+    TRACE("%s\n",debugstr_guid(rclsid));
 
     if (rclsid == NULL || ppenumCATID == NULL)
        return E_POINTER;
@@ -659,7 +659,7 @@ static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass(
                          'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
                          'r', 'i', 'e', 's', 0 };
 
-    TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid));
+    TRACE("%s\n",debugstr_guid(rclsid));
 
     if (rclsid == NULL || ppenumCATID == NULL)
        return E_POINTER;
@@ -719,7 +719,7 @@ static HRESULT WINAPI COMCAT_IClassFactory_QueryInterface(
     REFIID riid,
     LPVOID *ppvObj)
 {
-    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+    TRACE("%s\n",debugstr_guid(riid));
 
     if (ppvObj == NULL) return E_POINTER;
 
@@ -760,7 +760,7 @@ static HRESULT WINAPI COMCAT_IClassFactory_CreateInstance(
     LPVOID *ppvObj)
 {
     HRESULT res;
-    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+    TRACE("%s\n",debugstr_guid(riid));
 
     if (ppvObj == NULL) return E_POINTER;
 
@@ -834,7 +834,7 @@ static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface(
     REFIID riid,
     LPVOID *ppvObj)
 {
-    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+    TRACE("%s\n",debugstr_guid(riid));
 
     if (ppvObj == NULL) return E_POINTER;
 
@@ -1017,7 +1017,7 @@ static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_QueryInterface(
     REFIID riid,
     LPVOID *ppvObj)
 {
-    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+    TRACE("%s\n",debugstr_guid(riid));
 
     if (ppvObj == NULL) return E_POINTER;
 
@@ -1203,7 +1203,7 @@ static HRESULT WINAPI COMCAT_CATID_IEnumGUID_QueryInterface(
     REFIID riid,
     LPVOID *ppvObj)
 {
-    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+    TRACE("%s\n",debugstr_guid(riid));
 
     if (ppvObj == NULL) return E_POINTER;
 
index 154c18d..b2013cf 100644 (file)
@@ -52,6 +52,7 @@
 #include "winerror.h"
 #include "winreg.h"
 #include "winuser.h"
+#define USE_COM_CONTEXT_DEF
 #include "objbase.h"
 #include "ole2.h"
 #include "ole2ver.h"
@@ -71,11 +72,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
  * This section defines variables internal to the COM module.
  */
 
-static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
-                                            DWORD dwClsContext, LPUNKNOWN*  ppUnk);
-static void COM_RevokeAllClasses(const struct apartment *apt);
-static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
-
 static APARTMENT *MTA; /* protected by csApartment */
 static APARTMENT *MainApartment; /* the first STA apartment */
 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
@@ -182,61 +178,147 @@ struct apartment_loaded_dll
 
 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
                                        '0','x','#','#','#','#','#','#','#','#',' ',0};
-static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
-static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
-                                        BOOL apartment_threaded,
-                                        REFCLSID rclsid, REFIID riid, void **ppv);
-static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
 
-static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
-static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
-static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
+/*****************************************************************************
+ * This section contains OpenDllList implementation
+ */
 
-static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
+static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
+{
+    OpenDll *ptr;
+    OpenDll *ret = NULL;
+    EnterCriticalSection(&csOpenDllList);
+    LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
+    {
+        if (!strcmpiW(library_name, ptr->library_name) &&
+            (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
+        {
+            ret = ptr;
+            break;
+        }
+    }
+    LeaveCriticalSection(&csOpenDllList);
+    return ret;
+}
 
-static void COMPOBJ_InitProcess( void )
+/* caller must ensure that library_name is not already in the open dll list */
+static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
 {
-    WNDCLASSW wclass;
+    OpenDll *entry;
+    int len;
+    HRESULT hr = S_OK;
+    HANDLE hLibrary;
+    DllCanUnloadNowFunc DllCanUnloadNow;
+    DllGetClassObjectFunc DllGetClassObject;
 
-    /* Dispatching to the correct thread in an apartment is done through
-     * window messages rather than RPC transports. When an interface is
-     * marshalled into another apartment in the same process, a window of the
-     * following class is created. The *caller* of CoMarshalInterface (i.e., the
-     * application) is responsible for pumping the message loop in that thread.
-     * The WM_USER messages which point to the RPCs are then dispatched to
-     * apartment_wndproc by the user's code from the apartment in which the
-     * interface was unmarshalled.
-     */
-    memset(&wclass, 0, sizeof(wclass));
-    wclass.lpfnWndProc = apartment_wndproc;
-    wclass.hInstance = hProxyDll;
-    wclass.lpszClassName = wszAptWinClass;
-    RegisterClassW(&wclass);
+    TRACE("\n");
+
+    *ret = COMPOBJ_DllList_Get(library_name);
+    if (*ret) return S_OK;
+
+    /* do this outside the csOpenDllList to avoid creating a lock dependency on
+     * the loader lock */
+    hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+    if (!hLibrary)
+    {
+        ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
+        /* failure: DLL could not be loaded */
+        return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
+    }
+
+    DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
+    /* Note: failing to find DllCanUnloadNow is not a failure */
+    DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
+    if (!DllGetClassObject)
+    {
+        /* failure: the dll did not export DllGetClassObject */
+        ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
+        FreeLibrary(hLibrary);
+        return CO_E_DLLNOTFOUND;
+    }
+
+    EnterCriticalSection( &csOpenDllList );
+
+    *ret = COMPOBJ_DllList_Get(library_name);
+    if (*ret)
+    {
+        /* another caller to this function already added the dll while we
+         * weren't in the critical section */
+        FreeLibrary(hLibrary);
+    }
+    else
+    {
+        len = strlenW(library_name);
+        entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
+        if (entry)
+            entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
+        if (entry && entry->library_name)
+        {
+            memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
+            entry->library = hLibrary;
+            entry->refs = 1;
+            entry->DllCanUnloadNow = DllCanUnloadNow;
+            entry->DllGetClassObject = DllGetClassObject;
+            list_add_tail(&openDllList, &entry->entry);
+        }
+        else
+        {
+            HeapFree(GetProcessHeap(), 0, entry);
+            hr = E_OUTOFMEMORY;
+            FreeLibrary(hLibrary);
+        }
+        *ret = entry;
+    }
+
+    LeaveCriticalSection( &csOpenDllList );
+
+    return hr;
 }
 
-static void COMPOBJ_UninitProcess( void )
+/* pass FALSE for free_entry to release a reference without destroying the
+ * entry if it reaches zero or TRUE otherwise */
+static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
 {
-    UnregisterClassW(wszAptWinClass, hProxyDll);
+    if (!InterlockedDecrement(&entry->refs) && free_entry)
+    {
+        EnterCriticalSection(&csOpenDllList);
+        list_remove(&entry->entry);
+        LeaveCriticalSection(&csOpenDllList);
+
+        TRACE("freeing %p\n", entry->library);
+        FreeLibrary(entry->library);
+
+        HeapFree(GetProcessHeap(), 0, entry->library_name);
+        HeapFree(GetProcessHeap(), 0, entry);
+    }
 }
 
-static void COM_TlsDestroy(void)
+/* frees memory associated with active dll list */
+static void COMPOBJ_DllList_Free(void)
 {
-    struct oletls *info = NtCurrentTeb()->ReservedForOle;
-    if (info)
+    OpenDll *entry, *cursor2;
+    EnterCriticalSection(&csOpenDllList);
+    LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
     {
-        if (info->apt) apartment_release(info->apt);
-        if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
-        if (info->state) IUnknown_Release(info->state);
-        if (info->spy) IUnknown_Release(info->spy);
-        HeapFree(GetProcessHeap(), 0, info);
-        NtCurrentTeb()->ReservedForOle = NULL;
+        list_remove(&entry->entry);
+
+        HeapFree(GetProcessHeap(), 0, entry->library_name);
+        HeapFree(GetProcessHeap(), 0, entry);
     }
+    LeaveCriticalSection(&csOpenDllList);
 }
 
 /******************************************************************************
  * Manage apartments.
  */
 
+static DWORD apartment_addref(struct apartment *apt)
+{
+    DWORD refs = InterlockedIncrement(&apt->refs);
+    TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
+    return refs;
+}
+
 /* allocates memory and fills in the necessary fields for a new apartment
  * object. must be called inside apartment cs */
 static APARTMENT *apartment_construct(DWORD model)
@@ -335,11 +417,146 @@ static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
     return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
 }
 
-DWORD apartment_addref(struct apartment *apt)
+static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
 {
-    DWORD refs = InterlockedIncrement(&apt->refs);
-    TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
-    return refs;
+    list_remove(&curClass->entry);
+
+    if (curClass->runContext & CLSCTX_LOCAL_SERVER)
+        RPC_StopLocalServer(curClass->RpcRegistration);
+
+    /*
+     * Release the reference to the class object.
+     */
+    IUnknown_Release(curClass->classObject);
+
+    if (curClass->pMarshaledData)
+    {
+        LARGE_INTEGER zero;
+        memset(&zero, 0, sizeof(zero));
+        IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
+        CoReleaseMarshalData(curClass->pMarshaledData);
+        IStream_Release(curClass->pMarshaledData);
+    }
+
+    HeapFree(GetProcessHeap(), 0, curClass);
+}
+
+static void COM_RevokeAllClasses(const struct apartment *apt)
+{
+  RegisteredClass *curClass, *cursor;
+
+  EnterCriticalSection( &csRegisteredClassList );
+
+  LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
+  {
+    if (curClass->apartment_id == apt->oxid)
+      COM_RevokeRegisteredClassObject(curClass);
+  }
+
+  LeaveCriticalSection( &csRegisteredClassList );
+}
+
+/***********************************************************************
+ *           CoRevokeClassObject [OLE32.@]
+ *
+ * Removes a class object from the class registry.
+ *
+ * PARAMS
+ *  dwRegister [I] Cookie returned from CoRegisterClassObject().
+ *
+ * RETURNS
+ *  Success: S_OK.
+ *  Failure: HRESULT code.
+ *
+ * NOTES
+ *  Must be called from the same apartment that called CoRegisterClassObject(),
+ *  otherwise it will fail with RPC_E_WRONG_THREAD.
+ *
+ * SEE ALSO
+ *  CoRegisterClassObject
+ */
+HRESULT WINAPI CoRevokeClassObject(
+        DWORD dwRegister)
+{
+  HRESULT hr = E_INVALIDARG;
+  RegisteredClass *curClass;
+  APARTMENT *apt;
+
+  TRACE("(%08x)\n",dwRegister);
+
+  apt = COM_CurrentApt();
+  if (!apt)
+  {
+    ERR("COM was not initialized\n");
+    return CO_E_NOTINITIALIZED;
+  }
+
+  EnterCriticalSection( &csRegisteredClassList );
+
+  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
+  {
+    /*
+     * Check if we have a match on the cookie.
+     */
+    if (curClass->dwCookie == dwRegister)
+    {
+      if (curClass->apartment_id == apt->oxid)
+      {
+          COM_RevokeRegisteredClassObject(curClass);
+          hr = S_OK;
+      }
+      else
+      {
+          ERR("called from wrong apartment, should be called from %s\n",
+              wine_dbgstr_longlong(curClass->apartment_id));
+          hr = RPC_E_WRONG_THREAD;
+      }
+      break;
+    }
+  }
+
+  LeaveCriticalSection( &csRegisteredClassList );
+
+  return hr;
+}
+
+/* frees unused libraries loaded by apartment_getclassobject by calling the
+ * DLL's DllCanUnloadNow entry point */
+static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
+{
+    struct apartment_loaded_dll *entry, *next;
+    EnterCriticalSection(&apt->cs);
+    LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
+    {
+       if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
+        {
+            DWORD real_delay = delay;
+
+            if (real_delay == INFINITE)
+            {
+                /* DLLs that return multi-threaded objects aren't unloaded
+                 * straight away to cope for programs that have races between
+                 * last object destruction and threads in the DLLs that haven't
+                 * finished, despite DllCanUnloadNow returning S_OK */
+                if (entry->multi_threaded)
+                    real_delay = 10 * 60 * 1000; /* 10 minutes */
+                else
+                    real_delay = 0;
+            }
+
+            if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
+            {
+                list_remove(&entry->entry);
+                COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
+                HeapFree(GetProcessHeap(), 0, entry);
+            }
+            else
+                entry->unload_time = GetTickCount() + real_delay;
+        }
+        else if (entry->unload_time)
+            entry->unload_time = 0;
+    }
+    LeaveCriticalSection(&apt->cs);
 }
 
 DWORD apartment_release(struct apartment *apt)
@@ -502,21 +719,121 @@ static APARTMENT *apartment_find_multi_threaded(void)
     APARTMENT *result = NULL;
     struct list *cursor;
 
-    EnterCriticalSection(&csApartment);
+    EnterCriticalSection(&csApartment);
+
+    LIST_FOR_EACH( cursor, &apts )
+    {
+        struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
+        if (apt->multi_threaded)
+        {
+            result = apt;
+            apartment_addref(result);
+            break;
+        }
+    }
+
+    LeaveCriticalSection(&csApartment);
+    return result;
+}
+
+/* gets the specified class object by loading the appropriate DLL, if
+ * necessary and calls the DllGetClassObject function for the DLL */
+static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
+                                        BOOL apartment_threaded,
+                                        REFCLSID rclsid, REFIID riid, void **ppv)
+{
+    static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
+    HRESULT hr = S_OK;
+    BOOL found = FALSE;
+    struct apartment_loaded_dll *apartment_loaded_dll;
+
+    if (!strcmpiW(dllpath, wszOle32))
+    {
+        /* we don't need to control the lifetime of this dll, so use the local
+         * implementation of DllGetClassObject directly */
+        TRACE("calling ole32!DllGetClassObject\n");
+        hr = DllGetClassObject(rclsid, riid, ppv);
+
+        if (hr != S_OK)
+            ERR("DllGetClassObject returned error 0x%08x\n", hr);
+
+        return hr;
+    }
+
+    EnterCriticalSection(&apt->cs);
+
+    LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
+        if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
+        {
+            TRACE("found %s already loaded\n", debugstr_w(dllpath));
+            found = TRUE;
+            break;
+        }
+
+    if (!found)
+    {
+        apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
+        if (!apartment_loaded_dll)
+            hr = E_OUTOFMEMORY;
+        if (SUCCEEDED(hr))
+        {
+            apartment_loaded_dll->unload_time = 0;
+            apartment_loaded_dll->multi_threaded = FALSE;
+            hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
+            if (FAILED(hr))
+                HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
+        }
+        if (SUCCEEDED(hr))
+        {
+            TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
+            list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
+        }
+    }
+
+    LeaveCriticalSection(&apt->cs);
+
+    if (SUCCEEDED(hr))
+    {
+        /* one component being multi-threaded overrides any number of
+         * apartment-threaded components */
+        if (!apartment_threaded)
+            apartment_loaded_dll->multi_threaded = TRUE;
+
+        TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
+        /* OK: get the ClassObject */
+        hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
+
+        if (hr != S_OK)
+            ERR("DllGetClassObject returned error 0x%08x\n", hr);
+    }
+
+    return hr;
+}
 
-    LIST_FOR_EACH( cursor, &apts )
-    {
-        struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
-        if (apt->multi_threaded)
-        {
-            result = apt;
-            apartment_addref(result);
-            break;
-        }
-    }
+/***********************************************************************
+ *     COM_RegReadPath [internal]
+ *
+ *     Reads a registry value and expands it when necessary
+ */
+static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
+{
+       DWORD ret;
+       HKEY key;
+       DWORD keytype;
+       WCHAR src[MAX_PATH];
+       DWORD dwLength = dstlen * sizeof(WCHAR);
 
-    LeaveCriticalSection(&csApartment);
-    return result;
+       if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
+          if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
+            if (keytype == REG_EXPAND_SZ) {
+              if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
+            } else {
+              lstrcpynW(dst, src, dstlen);
+            }
+         }
+          RegCloseKey (key);
+       }
+       return ret;
 }
 
 struct host_object_params
@@ -781,246 +1098,44 @@ void apartment_joinmta(void)
     COM_CurrentInfo()->apt = MTA;
 }
 
-/* gets the specified class object by loading the appropriate DLL, if
- * necessary and calls the DllGetClassObject function for the DLL */
-static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
-                                        BOOL apartment_threaded,
-                                        REFCLSID rclsid, REFIID riid, void **ppv)
-{
-    static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
-    HRESULT hr = S_OK;
-    BOOL found = FALSE;
-    struct apartment_loaded_dll *apartment_loaded_dll;
-
-    if (!strcmpiW(dllpath, wszOle32))
-    {
-        /* we don't need to control the lifetime of this dll, so use the local
-         * implementation of DllGetClassObject directly */
-        TRACE("calling ole32!DllGetClassObject\n");
-        hr = DllGetClassObject(rclsid, riid, ppv);
-
-        if (hr != S_OK)
-            ERR("DllGetClassObject returned error 0x%08x\n", hr);
-
-        return hr;
-    }
-
-    EnterCriticalSection(&apt->cs);
-
-    LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
-        if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
-        {
-            TRACE("found %s already loaded\n", debugstr_w(dllpath));
-            found = TRUE;
-            break;
-        }
-
-    if (!found)
-    {
-        apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
-        if (!apartment_loaded_dll)
-            hr = E_OUTOFMEMORY;
-        if (SUCCEEDED(hr))
-        {
-            apartment_loaded_dll->unload_time = 0;
-            apartment_loaded_dll->multi_threaded = FALSE;
-            hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
-            if (FAILED(hr))
-                HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
-        }
-        if (SUCCEEDED(hr))
-        {
-            TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
-            list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
-        }
-    }
-
-    LeaveCriticalSection(&apt->cs);
-
-    if (SUCCEEDED(hr))
-    {
-        /* one component being multi-threaded overrides any number of
-         * apartment-threaded components */
-        if (!apartment_threaded)
-            apartment_loaded_dll->multi_threaded = TRUE;
-
-        TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
-        /* OK: get the ClassObject */
-        hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
-
-        if (hr != S_OK)
-            ERR("DllGetClassObject returned error 0x%08x\n", hr);
-    }
-
-    return hr;
-}
-
-/* frees unused libraries loaded by apartment_getclassobject by calling the
- * DLL's DllCanUnloadNow entry point */
-static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
-{
-    struct apartment_loaded_dll *entry, *next;
-    EnterCriticalSection(&apt->cs);
-    LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
-    {
-       if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
-        {
-            DWORD real_delay = delay;
-
-            if (real_delay == INFINITE)
-            {
-                /* DLLs that return multi-threaded objects aren't unloaded
-                 * straight away to cope for programs that have races between
-                 * last object destruction and threads in the DLLs that haven't
-                 * finished, despite DllCanUnloadNow returning S_OK */
-                if (entry->multi_threaded)
-                    real_delay = 10 * 60 * 1000; /* 10 minutes */
-                else
-                    real_delay = 0;
-            }
-
-            if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
-            {
-                list_remove(&entry->entry);
-                COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
-                HeapFree(GetProcessHeap(), 0, entry);
-            }
-            else
-                entry->unload_time = GetTickCount() + real_delay;
-        }
-        else if (entry->unload_time)
-            entry->unload_time = 0;
-    }
-    LeaveCriticalSection(&apt->cs);
-}
-
-/*****************************************************************************
- * This section contains OpenDllList implementation
- */
-
-/* caller must ensure that library_name is not already in the open dll list */
-static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
+static void COMPOBJ_InitProcess( void )
 {
-    OpenDll *entry;
-    int len;
-    HRESULT hr = S_OK;
-    HANDLE hLibrary;
-    DllCanUnloadNowFunc DllCanUnloadNow;
-    DllGetClassObjectFunc DllGetClassObject;
-
-    TRACE("\n");
-
-    *ret = COMPOBJ_DllList_Get(library_name);
-    if (*ret) return S_OK;
-
-    /* do this outside the csOpenDllList to avoid creating a lock dependency on
-     * the loader lock */
-    hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
-    if (!hLibrary)
-    {
-        ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
-        /* failure: DLL could not be loaded */
-        return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
-    }
-
-    DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
-    /* Note: failing to find DllCanUnloadNow is not a failure */
-    DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
-    if (!DllGetClassObject)
-    {
-        /* failure: the dll did not export DllGetClassObject */
-        ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
-        FreeLibrary(hLibrary);
-        return CO_E_DLLNOTFOUND;
-    }
-
-    EnterCriticalSection( &csOpenDllList );
-
-    *ret = COMPOBJ_DllList_Get(library_name);
-    if (*ret)
-    {
-        /* another caller to this function already added the dll while we
-         * weren't in the critical section */
-        FreeLibrary(hLibrary);
-    }
-    else
-    {
-        len = strlenW(library_name);
-        entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
-        if (entry)
-            entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
-        if (entry && entry->library_name)
-        {
-            memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
-            entry->library = hLibrary;
-            entry->refs = 1;
-            entry->DllCanUnloadNow = DllCanUnloadNow;
-            entry->DllGetClassObject = DllGetClassObject;
-            list_add_tail(&openDllList, &entry->entry);
-        }
-        else
-        {
-            HeapFree(GetProcessHeap(), 0, entry);
-            hr = E_OUTOFMEMORY;
-            FreeLibrary(hLibrary);
-        }
-        *ret = entry;
-    }
-
-    LeaveCriticalSection( &csOpenDllList );
-
-    return hr;
-}
+    WNDCLASSW wclass;
 
-static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
-{
-    OpenDll *ptr;
-    OpenDll *ret = NULL;
-    EnterCriticalSection(&csOpenDllList);
-    LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
-    {
-        if (!strcmpiW(library_name, ptr->library_name) &&
-            (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
-        {
-            ret = ptr;
-            break;
-        }
-    }
-    LeaveCriticalSection(&csOpenDllList);
-    return ret;
+    /* Dispatching to the correct thread in an apartment is done through
+     * window messages rather than RPC transports. When an interface is
+     * marshalled into another apartment in the same process, a window of the
+     * following class is created. The *caller* of CoMarshalInterface (i.e., the
+     * application) is responsible for pumping the message loop in that thread.
+     * The WM_USER messages which point to the RPCs are then dispatched to
+     * apartment_wndproc by the user's code from the apartment in which the
+     * interface was unmarshalled.
+     */
+    memset(&wclass, 0, sizeof(wclass));
+    wclass.lpfnWndProc = apartment_wndproc;
+    wclass.hInstance = hProxyDll;
+    wclass.lpszClassName = wszAptWinClass;
+    RegisterClassW(&wclass);
 }
 
-/* pass FALSE for free_entry to release a reference without destroying the
- * entry if it reaches zero or TRUE otherwise */
-static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
+static void COMPOBJ_UninitProcess( void )
 {
-    if (!InterlockedDecrement(&entry->refs) && free_entry)
-    {
-        EnterCriticalSection(&csOpenDllList);
-        list_remove(&entry->entry);
-        LeaveCriticalSection(&csOpenDllList);
-
-        TRACE("freeing %p\n", entry->library);
-        FreeLibrary(entry->library);
-
-        HeapFree(GetProcessHeap(), 0, entry->library_name);
-        HeapFree(GetProcessHeap(), 0, entry);
-    }
+    UnregisterClassW(wszAptWinClass, hProxyDll);
 }
 
-/* frees memory associated with active dll list */
-static void COMPOBJ_DllList_Free(void)
+static void COM_TlsDestroy(void)
 {
-    OpenDll *entry, *cursor2;
-    EnterCriticalSection(&csOpenDllList);
-    LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
+    struct oletls *info = NtCurrentTeb()->ReservedForOle;
+    if (info)
     {
-        list_remove(&entry->entry);
-
-        HeapFree(GetProcessHeap(), 0, entry->library_name);
-        HeapFree(GetProcessHeap(), 0, entry);
+        if (info->apt) apartment_release(info->apt);
+        if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
+        if (info->state) IUnknown_Release(info->state);
+        if (info->spy) IUnknown_Release(info->spy);
+        if (info->context_token) IObjContext_Release(info->context_token);
+        HeapFree(GetProcessHeap(), 0, info);
+        NtCurrentTeb()->ReservedForOle = NULL;
     }
-    LeaveCriticalSection(&csOpenDllList);
 }
 
 /******************************************************************************
@@ -2031,135 +2146,6 @@ HRESULT WINAPI CoRegisterClassObject(
   return S_OK;
 }
 
-static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
-{
-    list_remove(&curClass->entry);
-
-    if (curClass->runContext & CLSCTX_LOCAL_SERVER)
-        RPC_StopLocalServer(curClass->RpcRegistration);
-
-    /*
-     * Release the reference to the class object.
-     */
-    IUnknown_Release(curClass->classObject);
-
-    if (curClass->pMarshaledData)
-    {
-        LARGE_INTEGER zero;
-        memset(&zero, 0, sizeof(zero));
-        IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
-        CoReleaseMarshalData(curClass->pMarshaledData);
-        IStream_Release(curClass->pMarshaledData);
-    }
-
-    HeapFree(GetProcessHeap(), 0, curClass);
-}
-
-static void COM_RevokeAllClasses(const struct apartment *apt)
-{
-  RegisteredClass *curClass, *cursor;
-
-  EnterCriticalSection( &csRegisteredClassList );
-
-  LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
-  {
-    if (curClass->apartment_id == apt->oxid)
-      COM_RevokeRegisteredClassObject(curClass);
-  }
-
-  LeaveCriticalSection( &csRegisteredClassList );
-}
-
-/***********************************************************************
- *           CoRevokeClassObject [OLE32.@]
- *
- * Removes a class object from the class registry.
- *
- * PARAMS
- *  dwRegister [I] Cookie returned from CoRegisterClassObject().
- *
- * RETURNS
- *  Success: S_OK.
- *  Failure: HRESULT code.
- *
- * NOTES
- *  Must be called from the same apartment that called CoRegisterClassObject(),
- *  otherwise it will fail with RPC_E_WRONG_THREAD.
- *
- * SEE ALSO
- *  CoRegisterClassObject
- */
-HRESULT WINAPI CoRevokeClassObject(
-        DWORD dwRegister)
-{
-  HRESULT hr = E_INVALIDARG;
-  RegisteredClass *curClass;
-  APARTMENT *apt;
-
-  TRACE("(%08x)\n",dwRegister);
-
-  apt = COM_CurrentApt();
-  if (!apt)
-  {
-    ERR("COM was not initialized\n");
-    return CO_E_NOTINITIALIZED;
-  }
-
-  EnterCriticalSection( &csRegisteredClassList );
-
-  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
-  {
-    /*
-     * Check if we have a match on the cookie.
-     */
-    if (curClass->dwCookie == dwRegister)
-    {
-      if (curClass->apartment_id == apt->oxid)
-      {
-          COM_RevokeRegisteredClassObject(curClass);
-          hr = S_OK;
-      }
-      else
-      {
-          ERR("called from wrong apartment, should be called from %s\n",
-              wine_dbgstr_longlong(curClass->apartment_id));
-          hr = RPC_E_WRONG_THREAD;
-      }
-      break;
-    }
-  }
-
-  LeaveCriticalSection( &csRegisteredClassList );
-
-  return hr;
-}
-
-/***********************************************************************
- *     COM_RegReadPath [internal]
- *
- *     Reads a registry value and expands it when necessary
- */
-static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
-{
-       DWORD ret;
-       HKEY key;
-       DWORD keytype;
-       WCHAR src[MAX_PATH];
-       DWORD dwLength = dstlen * sizeof(WCHAR);
-
-       if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
-          if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
-            if (keytype == REG_EXPAND_SZ) {
-              if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
-            } else {
-              lstrcpynW(dst, src, dstlen);
-            }
-         }
-          RegCloseKey (key);
-       }
-       return ret;
-}
-
 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
 {
     static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
@@ -2265,7 +2251,7 @@ HRESULT WINAPI CoGetClassObject(
     APARTMENT  *apt;
     BOOL release_apt = FALSE;
 
-    TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
+    TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
 
     if (!ppv)
         return E_INVALIDARG;
@@ -2283,8 +2269,8 @@ HRESULT WINAPI CoGetClassObject(
     }
 
     if (pServerInfo) {
-       FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
-       FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
+       FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
+              debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
     }
 
     /*
@@ -3748,6 +3734,7 @@ typedef struct Context
 {
     const IComThreadingInfoVtbl *lpVtbl;
     const IContextCallbackVtbl  *lpCallbackVtbl;
+    const IObjContextVtbl  *lpContextVtbl;
     LONG refs;
     APTTYPE apttype;
 } Context;
@@ -3762,6 +3749,11 @@ static inline Context *impl_from_IContextCallback( IContextCallback *iface )
         return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
 }
 
+static inline Context *impl_from_IObjContext( IObjContext *iface )
+{
+        return (Context *)((char*)iface - FIELD_OFFSET(Context, lpContextVtbl));
+}
+
 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
 {
     *ppv = NULL;
@@ -3770,10 +3762,15 @@ static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
         IsEqualIID(riid, &IID_IUnknown))
     {
         *ppv = &iface->lpVtbl;
-    } else if (IsEqualIID(riid, &IID_IContextCallback))
+    }
+    else if (IsEqualIID(riid, &IID_IContextCallback))
     {
         *ppv = &iface->lpCallbackVtbl;
     }
+    else if (IsEqualIID(riid, &IID_IObjContext))
+    {
+        *ppv = &iface->lpContextVtbl;
+    }
 
     if (*ppv)
     {
@@ -3903,6 +3900,115 @@ static const IContextCallbackVtbl Context_Callback_Vtbl =
     Context_CC_ContextCallback
 };
 
+static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
+{
+    Context *This = impl_from_IObjContext(iface);
+    return Context_QueryInterface(This, riid, ppv);
+}
+
+static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    return Context_AddRef(This);
+}
+
+static ULONG WINAPI Context_OC_Release(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    return Context_Release(This);
+}
+
+static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
+{
+    Context *This = impl_from_IObjContext(iface);
+
+    FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
+{
+    Context *This = impl_from_IObjContext(iface);
+
+    FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
+{
+    Context *This = impl_from_IObjContext(iface);
+
+    FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
+{
+    Context *This = impl_from_IObjContext(iface);
+
+    FIXME("(%p/%p)->(%p)\n", This, iface, props);
+    return E_NOTIMPL;
+}
+
+static void WINAPI Context_OC_Reserved1(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static void WINAPI Context_OC_Reserved2(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static void WINAPI Context_OC_Reserved3(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static void WINAPI Context_OC_Reserved4(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static void WINAPI Context_OC_Reserved5(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static void WINAPI Context_OC_Reserved6(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static void WINAPI Context_OC_Reserved7(IObjContext *iface)
+{
+    Context *This = impl_from_IObjContext(iface);
+    FIXME("(%p/%p)\n", This, iface);
+}
+
+static const IObjContextVtbl Context_Object_Vtbl =
+{
+    Context_OC_QueryInterface,
+    Context_OC_AddRef,
+    Context_OC_Release,
+    Context_OC_SetProperty,
+    Context_OC_RemoveProperty,
+    Context_OC_GetProperty,
+    Context_OC_EnumContextProps,
+    Context_OC_Reserved1,
+    Context_OC_Reserved2,
+    Context_OC_Reserved3,
+    Context_OC_Reserved4,
+    Context_OC_Reserved5,
+    Context_OC_Reserved6,
+    Context_OC_Reserved7
+};
 
 /***********************************************************************
  *           CoGetObjectContext [OLE32.@]
@@ -3928,8 +4034,12 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
     *ppv = NULL;
     if (!apt)
     {
-        ERR("apartment not initialised\n");
-        return CO_E_NOTINITIALIZED;
+        if (!(apt = apartment_find_multi_threaded()))
+        {
+            ERR("apartment not initialised\n");
+            return CO_E_NOTINITIALIZED;
+        }
+        apartment_release(apt);
     }
 
     context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
@@ -3938,6 +4048,7 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
 
     context->lpVtbl = &Context_Threading_Vtbl;
     context->lpCallbackVtbl = &Context_Callback_Vtbl;
+    context->lpContextVtbl = &Context_Object_Vtbl;
     context->refs = 1;
     if (apt->multi_threaded)
         context->apttype = APTTYPE_MTA;
@@ -3959,12 +4070,40 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
 {
     struct oletls *info = COM_CurrentInfo();
-    static int calls;
-    if(!(calls++)) FIXME( "stub\n" );
+
+    TRACE("(%p)\n", token);
+
     if (!info)
         return E_OUTOFMEMORY;
-    if (token) *token = info->context_token;
-    return E_NOTIMPL;
+
+    if (!info->apt)
+    {
+        APARTMENT *apt;
+        if (!(apt = apartment_find_multi_threaded()))
+        {
+            ERR("apartment not initialised\n");
+            return CO_E_NOTINITIALIZED;
+        }
+        apartment_release(apt);
+    }
+
+    if (!token)
+        return E_POINTER;
+
+    if (!info->context_token)
+    {
+        HRESULT hr;
+        IObjContext *ctx;
+
+        hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
+        if (FAILED(hr)) return hr;
+        info->context_token = ctx;
+    }
+
+    *token = (ULONG_PTR)info->context_token;
+    TRACE("apt->context_token=%p\n", info->context_token);
+
+    return S_OK;
 }
 
 
index a7c6dfa..fb05934 100644 (file)
@@ -183,7 +183,7 @@ struct oletls
     LONG             pending_call_count_client; /* number of client calls pending */
     LONG             pending_call_count_server; /* number of server calls pending */
     DWORD            unknown;
-    ULONG_PTR        context_token; /* (+38h on x86) */
+    IObjContext     *context_token; /* (+38h on x86) */
     IUnknown        *call_state;    /* current call context (+3Ch on x86) */
     DWORD            unknown2[46];
     IUnknown        *cancel_object; /* cancel object set by CoSetCancelObject (+F8h on x86) */
@@ -203,7 +203,6 @@ HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv);
 
 /* Stub Manager */
 
-ULONG stub_manager_int_addref(struct stub_manager *This);
 ULONG stub_manager_int_release(struct stub_manager *This);
 struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object);
 ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak);
@@ -253,7 +252,6 @@ void OLEDD_UnInitialize(void);
 
 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref);
 APARTMENT *apartment_findfromtid(DWORD tid);
-DWORD apartment_addref(struct apartment *apt);
 DWORD apartment_release(struct apartment *apt);
 HRESULT apartment_disconnectproxies(struct apartment *apt);
 void apartment_disconnectobject(struct apartment *apt, void *object);
index b85002a..4102d50 100644 (file)
@@ -137,6 +137,11 @@ struct DefaultHandler
   /* storage passed to Load or InitNew */
   IStorage *storage;
   enum storage_state storage_state;
+
+  /* optional class factory for object */
+  IClassFactory *pCFObject;
+  /* TRUE if acting as an inproc server instead of an inproc handler */
+  BOOL inproc_server;
 };
 
 typedef struct DefaultHandler DefaultHandler;
@@ -223,6 +228,12 @@ static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface(
     if (FAILED(hr)) FIXME("interface %s not implemented by data cache\n", debugstr_guid(riid));
     return hr;
   }
+  else if (This->inproc_server && This->pOleDelegate)
+  {
+    HRESULT hr = IUnknown_QueryInterface(This->pOleDelegate, riid, ppvObject);
+    if (SUCCEEDED(hr))
+      return hr;
+  }
 
   /* Check that we obtained an interface. */
   if (*ppvObject == NULL)
@@ -1901,7 +1912,9 @@ static const IPersistStorageVtbl DefaultHandler_IPersistStorage_VTable =
  */
 static DefaultHandler* DefaultHandler_Construct(
   REFCLSID  clsid,
-  LPUNKNOWN pUnkOuter)
+  LPUNKNOWN pUnkOuter,
+  DWORD flags,
+  IClassFactory *pCF)
 {
   DefaultHandler* This = NULL;
   HRESULT hr;
@@ -1918,6 +1931,8 @@ static DefaultHandler* DefaultHandler_Construct(
   This->lpvtblIAdviseSink = &DefaultHandler_IAdviseSink_VTable;
   This->lpvtblIPersistStorage = &DefaultHandler_IPersistStorage_VTable;
 
+  This->inproc_server = (flags & EMBDHLP_INPROC_SERVER) ? TRUE : FALSE;
+
   /*
    * Start with one reference count. The caller of this function
    * must release the interface pointer when it is done.
@@ -1964,6 +1979,30 @@ static DefaultHandler* DefaultHandler_Construct(
   This->storage = NULL;
   This->storage_state = storage_state_uninitialised;
 
+  if (This->inproc_server && !(flags & EMBDHLP_DELAYCREATE))
+  {
+    HRESULT hr;
+    This->pCFObject = NULL;
+    if (pCF)
+      hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IOleObject, (void **)&This->pOleDelegate);
+    else
+      hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+                            &IID_IOleObject, (void **)&This->pOleDelegate);
+    if (SUCCEEDED(hr))
+      hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage, (void **)&This->pPSDelegate);
+    if (SUCCEEDED(hr))
+      hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IDataObject, (void **)&This->pDataDelegate);
+    if (SUCCEEDED(hr))
+      This->object_state = object_state_running;
+    if (FAILED(hr))
+      WARN("object creation failed with error %08x\n", hr);
+  }
+  else
+  {
+    This->pCFObject = pCF;
+    if (pCF) IClassFactory_AddRef(pCF);
+  }
+
   return This;
 }
 
@@ -2011,22 +2050,30 @@ static void DefaultHandler_Destroy(
     This->storage = NULL;
   }
 
+  if (This->pCFObject)
+  {
+    IClassFactory_Release(This->pCFObject);
+    This->pCFObject = NULL;
+  }
+
   HeapFree(GetProcessHeap(), 0, This);
 }
 
 /******************************************************************************
- * OleCreateDefaultHandler [OLE32.@]
+ * OleCreateEmbeddingHelper [OLE32.@]
  */
-HRESULT WINAPI OleCreateDefaultHandler(
+HRESULT WINAPI OleCreateEmbeddingHelper(
   REFCLSID  clsid,
   LPUNKNOWN pUnkOuter,
+  DWORD     flags,
+  IClassFactory *pCF,
   REFIID    riid,
   LPVOID*   ppvObj)
 {
   DefaultHandler* newHandler = NULL;
   HRESULT         hr         = S_OK;
 
-  TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj);
+  TRACE("(%s, %p, %08x, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, flags, pCF, debugstr_guid(riid), ppvObj);
 
   if (!ppvObj)
     return E_POINTER;
@@ -2045,7 +2092,7 @@ HRESULT WINAPI OleCreateDefaultHandler(
   /*
    * Try to construct a new instance of the class.
    */
-  newHandler = DefaultHandler_Construct(clsid, pUnkOuter);
+  newHandler = DefaultHandler_Construct(clsid, pUnkOuter, flags, pCF);
 
   if (!newHandler)
     return E_OUTOFMEMORY;
@@ -2063,3 +2110,15 @@ HRESULT WINAPI OleCreateDefaultHandler(
 
   return hr;
 }
+
+
+/******************************************************************************
+ * OleCreateDefaultHandler [OLE32.@]
+ */
+HRESULT WINAPI OleCreateDefaultHandler(REFCLSID clsid, LPUNKNOWN pUnkOuter,
+                                       REFIID riid, LPVOID* ppvObj)
+{
+    TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter,debugstr_guid(riid), ppvObj);
+    return OleCreateEmbeddingHelper(clsid, pUnkOuter, EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW,
+                                    NULL, riid, ppvObj);
+}
index 64b81ff..f69635b 100644 (file)
@@ -191,7 +191,7 @@ static HRESULT WINAPI IErrorInfoImpl_QueryInterface(
        VOID**     ppvoid)
 {
        ErrorInfoImpl *This = impl_from_IErrorInfo(iface);
-       TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvoid);
+       TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvoid);
 
        *ppvoid = NULL;
 
index f82410e..1380285 100644 (file)
@@ -110,7 +110,7 @@ FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv)
 
     FTMarshalImpl *This = impl_from_IMarshal(iface);
 
-    TRACE ("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid (riid), ppv);
+    TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppv);
     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppv);
 }
 
index 0066153..3703de9 100644 (file)
@@ -431,7 +431,7 @@ static HRESULT WINAPI Proxy_MarshalInterface(
 
         if (SUCCEEDED(hr))
         {
-            TRACE("writing stdobjref:\n\tflags = %04x\n\tcPublicRefs = %d\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
+            TRACE("writing stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
                 stdobjref.flags, stdobjref.cPublicRefs,
                 wine_dbgstr_longlong(stdobjref.oxid),
                 wine_dbgstr_longlong(stdobjref.oid),
@@ -1239,7 +1239,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
 
     assert(apt);
 
-    TRACE("stdobjref:\n\tflags = %04x\n\tcPublicRefs = %d\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
+    TRACE("stdobjref: flags = %04x cPublicRefs = %d oxid = %s oid = %s ipid = %s\n",
         stdobjref->flags, stdobjref->cPublicRefs,
         wine_dbgstr_longlong(stdobjref->oxid),
         wine_dbgstr_longlong(stdobjref->oid),
index fe00066..3b87aac 100644 (file)
@@ -570,7 +570,7 @@ HRESULT WINAPI OleQueryLinkFromData(
   IDataObject* pSrcDataObject)
 {
   FIXME("(%p),stub!\n", pSrcDataObject);
-  return S_OK;
+  return S_FALSE;
 }
 
 /***********************************************************************
index b9e5c4c..97f2f3d 100644 (file)
 @ stub OleConvertOLESTREAMToIStorageEx
 @ stdcall OleCreate(ptr ptr long ptr ptr ptr ptr)
 @ stdcall OleCreateDefaultHandler(ptr ptr ptr ptr)
-@ stub OleCreateEmbeddingHelper
+@ stdcall OleCreateEmbeddingHelper(ptr ptr long ptr ptr ptr)
 @ stub OleCreateEx
 @ stdcall OleCreateFromData(ptr ptr long ptr ptr ptr ptr)
 @ stdcall OleCreateFromDataEx(ptr ptr long long long ptr ptr ptr ptr ptr ptr ptr)
index 381e079..9bf9481 100644 (file)
@@ -1477,6 +1477,25 @@ static void PropertyStorage_MakePropertyIdOffset(DWORD propid, DWORD dwOffset,
      offsetof(PROPERTYIDOFFSET, dwOffset), dwOffset);
 }
 
+static inline HRESULT PropertStorage_WriteWStringToStream(IStream *stm,
+ LPCWSTR str, DWORD len, DWORD *written)
+{
+#ifdef WORDS_BIGENDIAN
+    WCHAR *leStr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    HRESULT hr;
+
+    if (!leStr)
+        return E_OUTOFMEMORY;
+    memcpy(leStr, str, len * sizeof(WCHAR));
+    PropertyStorage_ByteSwapString(leStr, len);
+    hr = IStream_Write(stm, leStr, len, written);
+    HeapFree(GetProcessHeap(), 0, leStr);
+    return hr;
+#else
+    return IStream_Write(stm, str, len, written);
+#endif
+}
+
 struct DictionaryClosure
 {
     HRESULT hr;
@@ -1508,15 +1527,11 @@ static BOOL PropertyStorage_DictionaryWriter(const void *key,
         if (FAILED(c->hr))
             goto end;
         c->bytesWritten += sizeof(DWORD);
-        /* Rather than allocate a copy, I'll swap the string to little-endian
-         * in-place, write it, then swap it back.
-         */
-        PropertyStorage_ByteSwapString(key, keyLen);
-        c->hr = IStream_Write(This->stm, key, keyLen, &count);
-        PropertyStorage_ByteSwapString(key, keyLen);
+        c->hr = PropertStorage_WriteWStringToStream(This->stm, key, keyLen,
+         &count);
         if (FAILED(c->hr))
             goto end;
-        c->bytesWritten += keyLen;
+        c->bytesWritten += keyLen * sizeof(WCHAR);
         if (keyLen % sizeof(DWORD))
         {
             c->hr = IStream_Write(This->stm, &pad,
index 9acd414..36486f9 100644 (file)
@@ -232,6 +232,7 @@ static void StgStreamImpl_OpenBlockChain(
       {
        This->smallBlockChain = SmallBlockChainStream_Construct(
                                                                This->parentStorage->ancestorStorage,
+                                                               NULL,
                                                                This->ownerProperty);
       }
       else
@@ -536,8 +537,6 @@ static HRESULT WINAPI StgStreamImpl_Seek(
  *
  * It will change the size of a stream.
  *
- * TODO: Switch from small blocks to big blocks and vice versa.
- *
  * See the documentation of IStream for more info.
  */
 static HRESULT WINAPI StgStreamImpl_SetSize(
@@ -591,6 +590,7 @@ static HRESULT WINAPI StgStreamImpl_SetSize(
     {
       This->smallBlockChain = SmallBlockChainStream_Construct(
                                     This->parentStorage->ancestorStorage,
+                                    NULL,
                                     This->ownerProperty);
     }
     else
@@ -624,6 +624,19 @@ static HRESULT WINAPI StgStreamImpl_SetSize(
                                 &This->smallBlockChain);
     }
   }
+  else if ( (This->bigBlockChain!=0) &&
+            (curProperty.size.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) )
+  {
+    if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK)
+    {
+      /*
+       * Transform the big block chain into a small block chain
+       */
+      This->smallBlockChain = Storage32Impl_BigBlocksToSmallBlocks(
+                                This->parentStorage->ancestorStorage,
+                                &This->bigBlockChain);
+    }
+  }
 
   if (This->smallBlockChain!=0)
   {
index 212c1ff..4a27317 100644 (file)
@@ -104,6 +104,7 @@ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This);
 static ULONG BlockChainStream_GetCount(BlockChainStream* This);
 
 static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
+static ULONG SmallBlockChainStream_GetHeadOfChain(SmallBlockChainStream* This);
 static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
     ULONG blockIndex, ULONG offset, DWORD value);
 static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl*  This,
@@ -3586,9 +3587,13 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
   } while (cbTotalRead.QuadPart < size.QuadPart);
   HeapFree(GetProcessHeap(),0,buffer);
 
+  size.u.HighPart = 0;
+  size.u.LowPart  = 0;
+
   if (FAILED(resRead) || FAILED(resWrite))
   {
     ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
+    BlockChainStream_SetSize(bbTempChain, size);
     BlockChainStream_Destroy(bbTempChain);
     return NULL;
   }
@@ -3597,8 +3602,6 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
    * Destroy the small block chain.
    */
   propertyIndex = (*ppsbChain)->ownerPropertyIndex;
-  size.u.HighPart = 0;
-  size.u.LowPart  = 0;
   SmallBlockChainStream_SetSize(*ppsbChain, size);
   SmallBlockChainStream_Destroy(*ppsbChain);
   *ppsbChain = 0;
@@ -3625,6 +3628,86 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
   return bigBlockChain;
 }
 
+/******************************************************************************
+ *              Storage32Impl_BigBlocksToSmallBlocks
+ *
+ * This method will convert a big block chain to a small block chain.
+ * The big block chain will be destroyed on success.
+ */
+SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
+                           StorageImpl* This,
+                           BlockChainStream** ppbbChain)
+{
+    ULARGE_INTEGER size, offset, cbTotalRead;
+    ULONG cbRead, cbWritten, propertyIndex, sbHeadOfChain = BLOCK_END_OF_CHAIN;
+    HRESULT resWrite = S_OK, resRead;
+    StgProperty chainProperty;
+    BYTE* buffer;
+    SmallBlockChainStream* sbTempChain;
+
+    TRACE("%p %p\n", This, ppbbChain);
+
+    sbTempChain = SmallBlockChainStream_Construct(This, &sbHeadOfChain,
+            PROPERTY_NULL);
+
+    if(!sbTempChain)
+        return NULL;
+
+    size = BlockChainStream_GetSize(*ppbbChain);
+    SmallBlockChainStream_SetSize(sbTempChain, size);
+
+    offset.u.HighPart = 0;
+    offset.u.LowPart = 0;
+    cbTotalRead.QuadPart = 0;
+    buffer = HeapAlloc(GetProcessHeap(), 0, This->bigBlockSize);
+    do
+    {
+        resRead = BlockChainStream_ReadAt(*ppbbChain, offset,
+                This->bigBlockSize, buffer, &cbRead);
+
+        if(FAILED(resRead))
+            break;
+
+        if(cbRead > 0)
+        {
+            cbTotalRead.QuadPart += cbRead;
+
+            resWrite = SmallBlockChainStream_WriteAt(sbTempChain, offset,
+                    cbRead, buffer, &cbWritten);
+
+            if(FAILED(resWrite))
+                break;
+
+            offset.u.LowPart += This->bigBlockSize;
+        }
+    }while(cbTotalRead.QuadPart < size.QuadPart);
+    HeapFree(GetProcessHeap(), 0, buffer);
+
+    size.u.HighPart = 0;
+    size.u.LowPart = 0;
+
+    if(FAILED(resRead) || FAILED(resWrite))
+    {
+        ERR("conversion failed: resRead = 0x%08x, resWrite = 0x%08x\n", resRead, resWrite);
+        SmallBlockChainStream_SetSize(sbTempChain, size);
+        SmallBlockChainStream_Destroy(sbTempChain);
+        return NULL;
+    }
+
+    /* destroy the original big block chain */
+    propertyIndex = (*ppbbChain)->ownerPropertyIndex;
+    BlockChainStream_SetSize(*ppbbChain, size);
+    BlockChainStream_Destroy(*ppbbChain);
+    *ppbbChain = NULL;
+
+    StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
+    chainProperty.startingBlock = sbHeadOfChain;
+    StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
+
+    SmallBlockChainStream_Destroy(sbTempChain);
+    return SmallBlockChainStream_Construct(This, NULL, propertyIndex);
+}
+
 static void StorageInternalImpl_Destroy( StorageBaseImpl *iface)
 {
   StorageInternalImpl* This = (StorageInternalImpl*) iface;
@@ -4577,7 +4660,6 @@ HRESULT BlockChainStream_ReadAt(BlockChainStream* This,
  *      BlockChainStream_WriteAt
  *
  * Writes the specified number of bytes to this chain at the specified offset.
- * bytesWritten may be NULL.
  * Will fail if not all specified number of bytes have been written.
  */
 HRESULT BlockChainStream_WriteAt(BlockChainStream* This,
@@ -4929,6 +5011,7 @@ static ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
 
 SmallBlockChainStream* SmallBlockChainStream_Construct(
   StorageImpl* parentStorage,
+  ULONG*         headOfStreamPlaceHolder,
   ULONG          propertyIndex)
 {
   SmallBlockChainStream* newStream;
@@ -4936,6 +5019,7 @@ SmallBlockChainStream* SmallBlockChainStream_Construct(
   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
 
   newStream->parentStorage      = parentStorage;
+  newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
   newStream->ownerPropertyIndex = propertyIndex;
 
   return newStream;
@@ -4958,6 +5042,9 @@ static ULONG SmallBlockChainStream_GetHeadOfChain(
   StgProperty chainProperty;
   BOOL      readSuccessful;
 
+  if (This->headOfStreamPlaceHolder != NULL)
+    return *(This->headOfStreamPlaceHolder);
+
   if (This->ownerPropertyIndex)
   {
     readSuccessful = StorageImpl_ReadProperty(
@@ -5320,7 +5407,6 @@ HRESULT SmallBlockChainStream_ReadAt(
  *       SmallBlockChainStream_WriteAt
  *
  * Writes the specified number of bytes to this chain at the specified offset.
- * bytesWritten may be NULL.
  * Will fail if not all specified number of bytes have been written.
  */
 HRESULT SmallBlockChainStream_WriteAt(
@@ -5360,9 +5446,6 @@ HRESULT SmallBlockChainStream_WriteAt(
 
   /*
    * Start writing the buffer.
-   *
-   * Here, I'm casting away the constness on the buffer variable
-   * This is OK since we don't intend to modify that buffer.
    */
   *bytesWritten   = 0;
   bufferWalker = buffer;
@@ -5509,26 +5592,32 @@ static BOOL SmallBlockChainStream_Enlarge(
   blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
 
   /*
-   * Empty chain
+   * Empty chain. Create the head.
    */
   if (blockIndex == BLOCK_END_OF_CHAIN)
   {
+    blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
+    SmallBlockChainStream_SetNextBlockInChain(
+        This,
+        blockIndex,
+        BLOCK_END_OF_CHAIN);
 
-    StgProperty chainProp;
-
-    StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
-                               &chainProp);
+    if (This->headOfStreamPlaceHolder != NULL)
+    {
+      *(This->headOfStreamPlaceHolder) = blockIndex;
+    }
+    else
+    {
+      StgProperty chainProp;
 
-    chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
+      StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
+                                   &chainProp);
 
-    StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
-                                &chainProp);
+      chainProp.startingBlock = blockIndex;
 
-    blockIndex = chainProp.startingBlock;
-    SmallBlockChainStream_SetNextBlockInChain(
-      This,
-      blockIndex,
-      BLOCK_END_OF_CHAIN);
+      StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
+                                  &chainProp);
+    }
   }
 
   currentBlock = blockIndex;
@@ -5603,6 +5692,32 @@ BOOL SmallBlockChainStream_SetSize(
   return TRUE;
 }
 
+/******************************************************************************
+ *       SmallBlockChainStream_GetCount
+ *
+ * Returns the number of small blocks that comprises this chain.
+ * This is not the size of the stream as the last block may not be full!
+ *
+ */
+static ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
+{
+    ULONG blockIndex;
+    ULONG count = 0;
+
+    blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+    while(blockIndex != BLOCK_END_OF_CHAIN)
+    {
+        count++;
+
+        if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This,
+                        blockIndex, &blockIndex)))
+            return 0;
+    }
+
+    return count;
+}
+
 /******************************************************************************
  *      SmallBlockChainStream_GetSize
  *
@@ -5612,6 +5727,17 @@ static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
 {
   StgProperty chainProperty;
 
+  if(This->headOfStreamPlaceHolder != NULL)
+  {
+    ULARGE_INTEGER result;
+    result.u.HighPart = 0;
+
+    result.u.LowPart = SmallBlockChainStream_GetCount(This) *
+        This->parentStorage->smallBlockSize;
+
+    return result;
+  }
+
   StorageImpl_ReadProperty(
     This->parentStorage,
     This->ownerPropertyIndex,
index 4be0631..fc4af32 100644 (file)
@@ -306,6 +306,10 @@ BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
                       StorageImpl* This,
                       SmallBlockChainStream** ppsbChain);
 
+SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
+                      StorageImpl* This,
+                      BlockChainStream** ppbbChain);
+
 /****************************************************************************
  * StgStreamImpl definitions.
  *
@@ -464,14 +468,16 @@ struct SmallBlockChainStream
 {
   StorageImpl* parentStorage;
   ULONG          ownerPropertyIndex;
+  ULONG*         headOfStreamPlaceHolder;
 };
 
 /*
  * Methods of the SmallBlockChainStream class.
  */
 SmallBlockChainStream* SmallBlockChainStream_Construct(
-              StorageImpl* parentStorage,
-              ULONG          propertyIndex);
+           StorageImpl*   parentStorage,
+           ULONG*         headOfStreamPlaceHolder,
+           ULONG          propertyIndex);
 
 void SmallBlockChainStream_Destroy(
               SmallBlockChainStream* This);
index 0aa80fa..12813c6 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
-static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub);
-static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid);
+
+/* generates an ipid in the following format (similar to native version):
+ * Data1 = apartment-local ipid counter
+ * Data2 = apartment creator thread ID
+ * Data3 = process ID
+ * Data4 = random value
+ */
+static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
+{
+    HRESULT hr;
+    hr = UuidCreate(ipid);
+    if (FAILED(hr))
+    {
+        ERR("couldn't create IPID for stub manager %p\n", m);
+        UuidCreateNil(ipid);
+        return hr;
+    }
+
+    ipid->Data1 = InterlockedIncrement(&m->apt->ipidc);
+    ipid->Data2 = (USHORT)m->apt->tid;
+    ipid->Data3 = (USHORT)GetCurrentProcessId();
+    return S_OK;
+}
+
+/* registers a new interface stub COM object with the stub manager and returns registration record */
+struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, MSHLFLAGS flags)
+{
+    struct ifstub *stub;
+    HRESULT hr;
+
+    TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s\n",
+          wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid));
+
+    stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub));
+    if (!stub) return NULL;
+
+    hr = RPC_CreateServerChannel(&stub->chan);
+    if (hr != S_OK)
+    {
+        HeapFree(GetProcessHeap(), 0, stub);
+        return NULL;
+    }
+
+    stub->stubbuffer = sb;
+    if (sb) IRpcStubBuffer_AddRef(sb);
+
+    IUnknown_AddRef(iptr);
+    stub->iface = iptr;
+    stub->flags = flags;
+    stub->iid = *iid;
+
+    /* FIXME: find a cleaner way of identifying that we are creating an ifstub
+     * for the remunknown interface */
+    if (flags & MSHLFLAGSP_REMUNKNOWN)
+        stub->ipid = m->oxid_info.ipidRemUnknown;
+    else
+        generate_ipid(m, &stub->ipid);
+
+    EnterCriticalSection(&m->lock);
+    list_add_head(&m->ifstubs, &stub->entry);
+    /* every normal marshal is counted so we don't allow more than we should */
+    if (flags & MSHLFLAGS_NORMAL) m->norm_refs++;
+    LeaveCriticalSection(&m->lock);
+
+    TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid));
+
+    return stub;
+}
+
+static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub)
+{
+    TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid));
+
+    list_remove(&ifstub->entry);
+
+    RPC_UnregisterInterface(&ifstub->iid);
+
+    if (ifstub->stubbuffer) IUnknown_Release(ifstub->stubbuffer);
+    IUnknown_Release(ifstub->iface);
+    IRpcChannelBuffer_Release(ifstub->chan);
+
+    HeapFree(GetProcessHeap(), 0, ifstub);
+}
+
+static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid)
+{
+    struct list    *cursor;
+    struct ifstub  *result = NULL;
+
+    EnterCriticalSection(&m->lock);
+    LIST_FOR_EACH( cursor, &m->ifstubs )
+    {
+        struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry );
+
+        if (IsEqualGUID(ipid, &ifstub->ipid))
+        {
+            result = ifstub;
+            break;
+        }
+    }
+    LeaveCriticalSection(&m->lock);
+
+    return result;
+}
+
+struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags)
+{
+    struct ifstub  *result = NULL;
+    struct ifstub  *ifstub;
+
+    EnterCriticalSection(&m->lock);
+    LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry )
+    {
+        if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags))
+        {
+            result = ifstub;
+            break;
+        }
+    }
+    LeaveCriticalSection(&m->lock);
+
+    return result;
+}
 
 /* creates a new stub manager and adds it into the apartment. caller must
  * release stub manager when it is no longer required. the apartment and
@@ -129,6 +250,44 @@ static void stub_manager_delete(struct stub_manager *m)
     HeapFree(GetProcessHeap(), 0, m);
 }
 
+/* increments the internal refcount */
+static ULONG stub_manager_int_addref(struct stub_manager *This)
+{
+    ULONG refs;
+
+    EnterCriticalSection(&This->apt->cs);
+    refs = ++This->refs;
+    LeaveCriticalSection(&This->apt->cs);
+
+    TRACE("before %d\n", refs - 1);
+
+    return refs;
+}
+
+/* decrements the internal refcount */
+ULONG stub_manager_int_release(struct stub_manager *This)
+{
+    ULONG refs;
+    APARTMENT *apt = This->apt;
+
+    EnterCriticalSection(&apt->cs);
+    refs = --This->refs;
+
+    TRACE("after %d\n", refs);
+
+    /* remove from apartment so no other thread can access it... */
+    if (!refs)
+        list_remove(&This->entry);
+
+    LeaveCriticalSection(&apt->cs);
+
+    /* ... so now we can delete it without being inside the apartment critsec */
+    if (!refs)
+        stub_manager_delete(This);
+
+    return refs;
+}
+
 /* gets the stub manager associated with an object - caller must have
  * a reference to the apartment while a reference to the stub manager is held.
  * it must also call release on the stub manager when it is no longer needed */
@@ -214,44 +373,6 @@ struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid)
     return result;
 }
 
-/* increments the internal refcount */
-ULONG stub_manager_int_addref(struct stub_manager *This)
-{
-    ULONG refs;
-
-    EnterCriticalSection(&This->apt->cs);
-    refs = ++This->refs;
-    LeaveCriticalSection(&This->apt->cs);
-
-    TRACE("before %d\n", refs - 1);
-
-    return refs;
-}
-
-/* decrements the internal refcount */
-ULONG stub_manager_int_release(struct stub_manager *This)
-{
-    ULONG refs;
-    APARTMENT *apt = This->apt;
-
-    EnterCriticalSection(&apt->cs);
-    refs = --This->refs;
-
-    TRACE("after %d\n", refs);
-
-    /* remove from apartment so no other thread can access it... */
-    if (!refs)
-        list_remove(&This->entry);
-
-    LeaveCriticalSection(&apt->cs);
-
-    /* ... so now we can delete it without being inside the apartment critsec */
-    if (!refs)
-        stub_manager_delete(This);
-
-    return refs;
-}
-
 /* add some external references (ie from a client that unmarshaled an ifptr) */
 ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak)
 {
@@ -297,46 +418,6 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tablewea
     return rc;
 }
 
-static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid)
-{
-    struct list    *cursor;
-    struct ifstub  *result = NULL;
-    
-    EnterCriticalSection(&m->lock);
-    LIST_FOR_EACH( cursor, &m->ifstubs )
-    {
-        struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry );
-
-        if (IsEqualGUID(ipid, &ifstub->ipid))
-        {
-            result = ifstub;
-            break;
-        }
-    }
-    LeaveCriticalSection(&m->lock);
-
-    return result;
-}
-
-struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags)
-{
-    struct ifstub  *result = NULL;
-    struct ifstub  *ifstub;
-
-    EnterCriticalSection(&m->lock);
-    LIST_FOR_EACH_ENTRY( ifstub, &m->ifstubs, struct ifstub, entry )
-    {
-        if (IsEqualIID(iid, &ifstub->iid) && (ifstub->flags == flags))
-        {
-            result = ifstub;
-            break;
-        }
-    }
-    LeaveCriticalSection(&m->lock);
-
-    return result;
-}
-
 /* gets the stub manager associated with an ipid - caller must have
  * a reference to the apartment while a reference to the stub manager is held.
  * it must also call release on the stub manager when it is no longer needed */
@@ -426,89 +507,6 @@ HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt,
     }
 }
 
-/* generates an ipid in the following format (similar to native version):
- * Data1 = apartment-local ipid counter
- * Data2 = apartment creator thread ID
- * Data3 = process ID
- * Data4 = random value
- */
-static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid)
-{
-    HRESULT hr;
-    hr = UuidCreate(ipid);
-    if (FAILED(hr))
-    {
-        ERR("couldn't create IPID for stub manager %p\n", m);
-        UuidCreateNil(ipid);
-        return hr;
-    }
-
-    ipid->Data1 = InterlockedIncrement(&m->apt->ipidc);
-    ipid->Data2 = (USHORT)m->apt->tid;
-    ipid->Data3 = (USHORT)GetCurrentProcessId();
-    return S_OK;
-}
-
-/* registers a new interface stub COM object with the stub manager and returns registration record */
-struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, MSHLFLAGS flags)
-{
-    struct ifstub *stub;
-    HRESULT hr;
-
-    TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s\n",
-          wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid));
-
-    stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub));
-    if (!stub) return NULL;
-
-    hr = RPC_CreateServerChannel(&stub->chan);
-    if (hr != S_OK)
-    {
-        HeapFree(GetProcessHeap(), 0, stub);
-        return NULL;
-    }
-
-    stub->stubbuffer = sb;
-    if (sb) IRpcStubBuffer_AddRef(sb);
-
-    IUnknown_AddRef(iptr);
-    stub->iface = iptr;
-    stub->flags = flags;
-    stub->iid = *iid;
-
-    /* FIXME: find a cleaner way of identifying that we are creating an ifstub
-     * for the remunknown interface */
-    if (flags & MSHLFLAGSP_REMUNKNOWN)
-        stub->ipid = m->oxid_info.ipidRemUnknown;
-    else
-        generate_ipid(m, &stub->ipid);
-
-    EnterCriticalSection(&m->lock);
-    list_add_head(&m->ifstubs, &stub->entry);
-    /* every normal marshal is counted so we don't allow more than we should */
-    if (flags & MSHLFLAGS_NORMAL) m->norm_refs++;
-    LeaveCriticalSection(&m->lock);
-
-    TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid));
-
-    return stub;
-}
-
-static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub)
-{
-    TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid));
-
-    list_remove(&ifstub->entry);
-
-    RPC_UnregisterInterface(&ifstub->iid);
-
-    if (ifstub->stubbuffer) IUnknown_Release(ifstub->stubbuffer);
-    IUnknown_Release(ifstub->iface);
-    IRpcChannelBuffer_Release(ifstub->chan);
-
-    HeapFree(GetProcessHeap(), 0, ifstub);
-}
-
 /* returns TRUE if it is possible to unmarshal, FALSE otherwise. */
 BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid)
 {