[ros-diffs] [cwittich] 47405: [OLE32] sync to wine 1.2 RC2

cwittich at svn.reactos.org cwittich at svn.reactos.org
Sat May 29 13:34:58 CEST 2010


Author: cwittich
Date: Sat May 29 13:34:57 2010
New Revision: 47405

URL: http://svn.reactos.org/svn/reactos?rev=47405&view=rev
Log:
[OLE32]
sync to wine 1.2 RC2

Modified:
    trunk/reactos/dll/win32/ole32/clipboard.c
    trunk/reactos/dll/win32/ole32/comcat.c
    trunk/reactos/dll/win32/ole32/compobj.c
    trunk/reactos/dll/win32/ole32/compositemoniker.c
    trunk/reactos/dll/win32/ole32/defaulthandler.c
    trunk/reactos/dll/win32/ole32/hglobalstream.c
    trunk/reactos/dll/win32/ole32/ifs.c
    trunk/reactos/dll/win32/ole32/marshal.c
    trunk/reactos/dll/win32/ole32/moniker.c
    trunk/reactos/dll/win32/ole32/ole2.c
    trunk/reactos/dll/win32/ole32/stg_prop.c
    trunk/reactos/dll/win32/ole32/storage32.c
    trunk/reactos/dll/win32/ole32/storage32.h
    trunk/reactos/dll/win32/ole32/usrmarshal.c

Modified: trunk/reactos/dll/win32/ole32/clipboard.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/clipboard.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/clipboard.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/clipboard.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -1266,9 +1266,9 @@
     ole_priv_data_entry *entry;
     TYMED supported;
 
+    if ( !fmt || !med ) return E_INVALIDARG;
+
     TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
-
-    if ( !fmt || !med ) return E_INVALIDARG;
 
     if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
 

Modified: trunk/reactos/dll/win32/ole32/comcat.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/comcat.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/comcat.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/comcat.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -232,18 +232,20 @@
     LPCWSTR string;
 
     /* Check that every given category is implemented by class. */
-    res = RegOpenKeyExW(key, impl_keyname, 0, KEY_READ, &subkey);
-    if (res != ERROR_SUCCESS) return S_FALSE;
-    for (string = categories->impl_strings; *string; string += 39) {
-	HKEY catkey;
-	res = RegOpenKeyExW(subkey, string, 0, 0, &catkey);
-	if (res != ERROR_SUCCESS) {
-	    RegCloseKey(subkey);
-	    return S_FALSE;
+    if (*categories->impl_strings) {
+	res = RegOpenKeyExW(key, impl_keyname, 0, KEY_READ, &subkey);
+	if (res != ERROR_SUCCESS) return S_FALSE;
+	for (string = categories->impl_strings; *string; string += 39) {
+	    HKEY catkey;
+	    res = RegOpenKeyExW(subkey, string, 0, 0, &catkey);
+	    if (res != ERROR_SUCCESS) {
+		RegCloseKey(subkey);
+		return S_FALSE;
+	    }
+	    RegCloseKey(catkey);
 	}
-	RegCloseKey(catkey);
-    }
-    RegCloseKey(subkey);
+	RegCloseKey(subkey);
+    }
 
     /* Check that all categories required by class are given. */
     res = RegOpenKeyExW(key, req_keyname, 0, KEY_READ, &subkey);

Modified: trunk/reactos/dll/win32/ole32/compobj.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/compobj.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/compobj.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/compobj.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -4156,7 +4156,6 @@
 	break;
 
     case DLL_PROCESS_DETACH:
-        OLEDD_UnInitialize();
         COMPOBJ_UninitProcess();
         RPC_UnregisterAllChannelHooks();
         COMPOBJ_DllList_Free();

Modified: trunk/reactos/dll/win32/ole32/compositemoniker.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/compositemoniker.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/compositemoniker.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/compositemoniker.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -445,7 +445,6 @@
 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
                IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
 {
-    HRESULT   res;
     IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
     IEnumMoniker *enumMoniker;
 
@@ -462,8 +461,8 @@
         IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
         IEnumMoniker_Release(enumMoniker);
 
-        res=CreateAntiMoniker(&antiMk);
-        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+        CreateAntiMoniker(&antiMk);
+        IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
         IMoniker_Release(antiMk);
 
         return IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
@@ -479,8 +478,8 @@
         IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
         IEnumMoniker_Release(enumMoniker);
 
-        res=CreateAntiMoniker(&antiMk);
-        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+        CreateAntiMoniker(&antiMk);
+        IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
         IMoniker_Release(antiMk);
 
         /* If any of the components  reduces itself, the method returns S_OK and passes back a composite */

Modified: trunk/reactos/dll/win32/ole32/defaulthandler.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/defaulthandler.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/defaulthandler.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/defaulthandler.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -365,7 +365,7 @@
   if (This->clientSite)
     IOleClientSite_AddRef(This->clientSite);
 
-  return S_OK;
+  return hr;
 }
 
 /************************************************************************

Modified: trunk/reactos/dll/win32/ole32/hglobalstream.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/hglobalstream.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/hglobalstream.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/hglobalstream.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -370,12 +370,6 @@
 
   TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart,
 	dlibMove.u.LowPart, dwOrigin, plibNewPosition);
-
-  if (dlibMove.u.LowPart >= 0x80000000)
-  {
-    hr = STG_E_SEEKERROR;
-    goto end;
-  }
 
   /*
    * The file pointer is moved depending on the given "function"
@@ -405,9 +399,18 @@
   newPosition.u.HighPart = 0;
   newPosition.u.LowPart += dlibMove.QuadPart;
 
+  if (dlibMove.u.LowPart >= 0x80000000 &&
+      newPosition.u.LowPart >= dlibMove.u.LowPart)
+  {
+    /* We tried to seek backwards and went past the start. */
+    hr = STG_E_SEEKERROR;
+    goto end;
+  }
+
+  This->currentPosition = newPosition;
+
 end:
-  if (plibNewPosition) *plibNewPosition = newPosition;
-  This->currentPosition = newPosition;
+  if (plibNewPosition) *plibNewPosition = This->currentPosition;
 
   return hr;
 }

Modified: trunk/reactos/dll/win32/ole32/ifs.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/ifs.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/ifs.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/ifs.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -501,7 +501,7 @@
         }
 	LeaveCriticalSection(&IMalloc32_SpyCS);
 
-	return S_OK;
+	return hres;
 }
 
 /******************************************************************************

Modified: trunk/reactos/dll/win32/ole32/marshal.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/marshal.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/marshal.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/marshal.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -1214,16 +1214,13 @@
     RPC_StartRemoting(apt);
 
     hres = marshal_object(apt, &stdobjref, riid, pv, mshlflags);
-    if (hres)
+    if (hres != S_OK)
     {
         ERR("Failed to create ifstub, hres=0x%x\n", hres);
         return hres;
     }
 
-    hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
-    if (hres) return hres;
-
-    return S_OK;
+    return IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
 }
 
 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
@@ -1321,10 +1318,10 @@
 
     /* read STDOBJREF from wire */
     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
-    if (hres) return STG_E_READFAULT;
+    if (hres != S_OK) return STG_E_READFAULT;
 
     hres = apartment_getoxid(apt, &oxid);
-    if (hres) return hres;
+    if (hres != S_OK) return hres;
 
     /* check if we're marshalling back to ourselves */
     if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid)))
@@ -1374,7 +1371,7 @@
     if (stubmgr) stub_manager_int_release(stubmgr);
     if (stub_apt) apartment_release(stub_apt);
 
-    if (hres) WARN("Failed with error 0x%08x\n", hres);
+    if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
     else TRACE("Successfully created proxy %p\n", *ppv);
 
     return hres;
@@ -1392,7 +1389,7 @@
     TRACE("iface=%p, pStm=%p\n", iface, pStm);
     
     hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res);
-    if (hres) return STG_E_READFAULT;
+    if (hres != S_OK) return STG_E_READFAULT;
 
     TRACE("oxid = %s, oid = %s, ipid = %s\n",
         wine_dbgstr_longlong(stdobjref.oxid),
@@ -1516,7 +1513,7 @@
     if (!pUnk)
         return E_POINTER;
     hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal);
-    if (hr)
+    if (hr != S_OK)
         hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext,
                                   mshlFlags, pMarshal);
     return hr;
@@ -1537,7 +1534,7 @@
 
     /* read common OBJREF header */
     hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
-    if (hr || (res != FIELD_OFFSET(OBJREF, u_objref)))
+    if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
     {
         ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
         return STG_E_READFAULT;
@@ -1566,7 +1563,7 @@
         /* read constant sized OR_CUSTOM data from stream */
         hr = IStream_Read(stream, &objref.u_objref.u_custom,
                           custom_header_size, &res);
-        if (hr || (res != custom_header_size))
+        if (hr != S_OK || (res != custom_header_size))
         {
             ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
             return STG_E_READFAULT;
@@ -1583,7 +1580,7 @@
         return RPC_E_INVALID_OBJREF;
     }
 
-    if (hr)
+    if (hr != S_OK)
         ERR("Failed to create marshal, 0x%08x\n", hr);
 
     return hr;
@@ -1618,12 +1615,12 @@
     CLSID marshaler_clsid;
 
     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
-    if (hr)
+    if (hr != S_OK)
         return hr;
 
     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
                                     pvDestContext, mshlFlags, &marshaler_clsid);
-    if (hr)
+    if (hr != S_OK)
     {
         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
         IMarshal_Release(pMarshal);
@@ -1711,7 +1708,7 @@
 
     /* get the marshaler for the specified interface */
     hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal);
-    if (hr)
+    if (hr != S_OK)
     {
         ERR("Failed to get marshaller, 0x%08x\n", hr);
         return hr;
@@ -1719,7 +1716,7 @@
 
     hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext,
                                     pvDestContext, mshlFlags, &marshaler_clsid);
-    if (hr)
+    if (hr != S_OK)
     {
         ERR("IMarshal::GetUnmarshalClass failed, 0x%08x\n", hr);
         goto cleanup;
@@ -1733,7 +1730,7 @@
 
         /* write the common OBJREF header to the stream */
         hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL);
-        if (hr)
+        if (hr != S_OK)
         {
             ERR("Failed to write OBJREF header to stream, 0x%08x\n", hr);
             goto cleanup;
@@ -1749,7 +1746,7 @@
         hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext,
                                         pvDestContext, mshlFlags,
                                         &objref.u_objref.u_custom.size);
-        if (hr)
+        if (hr != S_OK)
         {
             ERR("Failed to get max size of marshal data, error 0x%08x\n", hr);
             goto cleanup;
@@ -1757,7 +1754,7 @@
         /* write constant sized common header and OR_CUSTOM data into stream */
         hr = IStream_Write(pStream, &objref,
                           FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
-        if (hr)
+        if (hr != S_OK)
         {
             ERR("Failed to write OR_CUSTOM header to stream with 0x%08x\n", hr);
             goto cleanup;
@@ -1769,7 +1766,7 @@
     hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext,
                                    pvDestContext, mshlFlags);
 
-    if (hr)
+    if (hr != S_OK)
     {
         ERR("Failed to marshal the interface %s, %x\n", debugstr_guid(riid), hr);
         goto cleanup;
@@ -1821,7 +1818,7 @@
 
     /* call the helper object to do the actual unmarshaling */
     hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
-    if (hr)
+    if (hr != S_OK)
         ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
 
     if (hr == S_OK)
@@ -1831,7 +1828,7 @@
         {
             TRACE("requested interface != marshalled interface, additional QI needed\n");
             hr = IUnknown_QueryInterface(object, riid, ppv);
-            if (hr)
+            if (hr != S_OK)
                 ERR("Couldn't query for interface %s, hr = 0x%08x\n",
                     debugstr_guid(riid), hr);
             IUnknown_Release(object);
@@ -1885,7 +1882,7 @@
 
     /* call the helper object to do the releasing of marshal data */
     hr = IMarshal_ReleaseMarshalData(pMarshal, pStream);
-    if (hr)
+    if (hr != S_OK)
         ERR("IMarshal::ReleaseMarshalData failed with error 0x%08x\n", hr);
 
     IMarshal_Release(pMarshal);

Modified: trunk/reactos/dll/win32/ole32/moniker.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/moniker.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/moniker.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/moniker.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -1109,7 +1109,13 @@
 
     TRACE("(%p, %s, %p, %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
 
-    if (!(IsValidInterface((LPUNKNOWN) pbc)))
+    if (!pbc || !IsValidInterface((LPUNKNOWN) pbc))
+        return E_INVALIDARG;
+
+    if (!szDisplayName || !*szDisplayName)
+        return E_INVALIDARG;
+
+    if (!pchEaten || !ppmk)
         return E_INVALIDARG;
 
     *pchEaten = 0;

Modified: trunk/reactos/dll/win32/ole32/ole2.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/ole2.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/ole2.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/ole2.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -57,13 +57,6 @@
  * These are static/global variables and internal data structures that the
  * OLE module uses to maintain it's state.
  */
-typedef struct tagDropTargetNode
-{
-  HWND          hwndTarget;
-  IDropTarget*  dropTarget;
-  struct list   entry;
-} DropTargetNode;
-
 typedef struct tagTrackerWindowInfo
 {
   IDataObject* dataObject;
@@ -110,12 +103,25 @@
 /*
  * Name of our registered window class.
  */
-static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
+static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
+  {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
 
 /*
- * This is the head of the Drop target container.
- */
-static struct list targetListHead = LIST_INIT(targetListHead);
+ * Name of menu descriptor property.
+ */
+static const WCHAR prop_olemenuW[] =
+  {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
+
+/* property to store IDropTarget pointer */
+static const WCHAR prop_oledroptarget[] =
+  {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
+
+static const WCHAR clsidfmtW[] =
+  {'C','L','S','I','D','\\','{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
+   '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x',
+    '%','0','2','x','%','0','2','x','}','\\',0};
+
+static const WCHAR emptyW[] = { 0 };
 
 /******************************************************************************
  * These are the prototypes of miscellaneous utility methods
@@ -144,21 +150,11 @@
 /******************************************************************************
  * These are the prototypes of the utility methods used for OLE Drag n Drop
  */
-static void            OLEDD_Initialize(void);
-static DropTargetNode* OLEDD_FindDropTarget(
-                         HWND hwndOfTarget);
-static void            OLEDD_FreeDropTarget(DropTargetNode*, BOOL);
-static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
-			 HWND   hwnd,
-			 UINT   uMsg,
-			 WPARAM wParam,
-			 LPARAM   lParam);
-static void OLEDD_TrackMouseMove(
-                         TrackerWindowInfo* trackerInfo);
-static void OLEDD_TrackStateChange(
-                         TrackerWindowInfo* trackerInfo);
+static void OLEDD_Initialize(void);
+static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo);
+static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
 static DWORD OLEDD_GetButtonState(void);
-
 
 /******************************************************************************
  *		OleBuildVersion [OLE32.@]
@@ -270,14 +266,22 @@
         return 0;
 }
 
+/***
+ * OLEDD_FindDropTarget()
+ *
+ * Returns IDropTarget pointer registered for this window.
+ */
+static inline IDropTarget* OLEDD_FindDropTarget(HWND hwnd)
+{
+  return GetPropW(hwnd, prop_oledroptarget);
+}
+
 /***********************************************************************
  *           RegisterDragDrop (OLE32.@)
  */
-HRESULT WINAPI RegisterDragDrop(
-	HWND hwnd,
-	LPDROPTARGET pDropTarget)
-{
-  DropTargetNode* dropTargetInfo;
+HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
+{
+  DWORD pid = 0;
 
   TRACE("(%p,%p)\n", hwnd, pDropTarget);
 
@@ -296,32 +300,20 @@
     return DRAGDROP_E_INVALIDHWND;
   }
 
-  /*
-   * First, check if the window is already registered.
-   */
-  dropTargetInfo = OLEDD_FindDropTarget(hwnd);
-
-  if (dropTargetInfo!=NULL)
+  /* block register for other processes windows */
+  GetWindowThreadProcessId(hwnd, &pid);
+  if (pid != GetCurrentProcessId())
+  {
+    FIXME("register for another process windows is disabled\n");
+    return DRAGDROP_E_INVALIDHWND;
+  }
+
+  /* check if the window is already registered */
+  if (OLEDD_FindDropTarget(hwnd))
     return DRAGDROP_E_ALREADYREGISTERED;
 
-  /*
-   * If it's not there, we can add it. We first create a node for it.
-   */
-  dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
-
-  if (dropTargetInfo==NULL)
-    return E_OUTOFMEMORY;
-
-  dropTargetInfo->hwndTarget     = hwnd;
-
-  /*
-   * Don't forget that this is an interface pointer, need to nail it down since
-   * we keep a copy of it.
-   */
   IDropTarget_AddRef(pDropTarget);
-  dropTargetInfo->dropTarget  = pDropTarget;
-
-  list_add_tail(&targetListHead, &dropTargetInfo->entry);
+  SetPropW(hwnd, prop_oledroptarget, pDropTarget);
 
   return S_OK;
 }
@@ -329,10 +321,9 @@
 /***********************************************************************
  *           RevokeDragDrop (OLE32.@)
  */
-HRESULT WINAPI RevokeDragDrop(
-	HWND hwnd)
-{
-  DropTargetNode* dropTargetInfo;
+HRESULT WINAPI RevokeDragDrop(HWND hwnd)
+{
+  IDropTarget* droptarget;
 
   TRACE("(%p)\n", hwnd);
 
@@ -342,18 +333,12 @@
     return DRAGDROP_E_INVALIDHWND;
   }
 
-  /*
-   * First, check if the window is already registered.
-   */
-  dropTargetInfo = OLEDD_FindDropTarget(hwnd);
-
-  /*
-   * If it ain't in there, it's an error.
-   */
-  if (dropTargetInfo==NULL)
+  /* no registration data */
+  if (!(droptarget = OLEDD_FindDropTarget(hwnd)))
     return DRAGDROP_E_NOTREGISTERED;
 
-  OLEDD_FreeDropTarget(dropTargetInfo, TRUE);
+  IDropTarget_Release(droptarget);
+  RemovePropW(hwnd, prop_oledroptarget);
 
   return S_OK;
 }
@@ -371,13 +356,12 @@
 	DWORD dwFormOfType,
 	LPOLESTR* pszUserType)
 {
-  char    keyName[60];
+  WCHAR   keyName[60];
   DWORD   dwKeyType;
   DWORD   cbData;
   HKEY    clsidKey;
   LONG    hres;
-  LPSTR   buffer;
-  HRESULT retVal;
+
   /*
    * Initialize the out parameter.
    */
@@ -386,17 +370,17 @@
   /*
    * Build the key name we're looking for
    */
-  sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
-           clsid->Data1, clsid->Data2, clsid->Data3,
-           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
-           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
-
-  TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType);
+  sprintfW( keyName, clsidfmtW,
+            clsid->Data1, clsid->Data2, clsid->Data3,
+            clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
+            clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
+
+  TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwFormOfType, pszUserType);
 
   /*
    * Open the class id Key
    */
-  hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
+  hres = RegOpenKeyW(HKEY_CLASSES_ROOT,
 		     keyName,
 		     &clsidKey);
 
@@ -408,8 +392,8 @@
    */
   cbData = 0;
 
-  hres = RegQueryValueExA(clsidKey,
-			  "",
+  hres = RegQueryValueExW(clsidKey,
+			  emptyW,
 			  NULL,
 			  &dwKeyType,
 			  NULL,
@@ -424,7 +408,7 @@
   /*
    * Allocate a buffer for the registry value.
    */
-  *pszUserType = CoTaskMemAlloc(cbData*2);
+  *pszUserType = CoTaskMemAlloc(cbData);
 
   if (*pszUserType==NULL)
   {
@@ -432,41 +416,24 @@
     return E_OUTOFMEMORY;
   }
 
-  buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
-
-  if (buffer == NULL)
-  {
-    RegCloseKey(clsidKey);
-    CoTaskMemFree(*pszUserType);
-    *pszUserType=NULL;
-    return E_OUTOFMEMORY;
-  }
-
-  hres = RegQueryValueExA(clsidKey,
-			  "",
+  hres = RegQueryValueExW(clsidKey,
+			  emptyW,
 			  NULL,
 			  &dwKeyType,
-			  (LPBYTE) buffer,
+			  (LPBYTE) *pszUserType,
 			  &cbData);
 
   RegCloseKey(clsidKey);
 
-
-  if (hres!=ERROR_SUCCESS)
+  if (hres != ERROR_SUCCESS)
   {
     CoTaskMemFree(*pszUserType);
-    *pszUserType=NULL;
-
-    retVal = REGDB_E_READREGDB;
-  }
-  else
-  {
-    MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
-    retVal = S_OK;
-  }
-  HeapFree(GetProcessHeap(), 0, buffer);
-
-  return retVal;
+    *pszUserType = NULL;
+
+    return REGDB_E_READREGDB;
+  }
+
+  return S_OK;
 }
 
 /***********************************************************************
@@ -478,17 +445,19 @@
   DWORD       dwOKEffect,    /* [in] effects allowed by the source */
   DWORD       *pdwEffect)    /* [out] ptr to effects of the source */
 {
+  static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
   TrackerWindowInfo trackerInfo;
   HWND            hwndTrackWindow;
   MSG             msg;
 
-  TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
+  TRACE("(%p, %p, %d, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
+
+  if (!pDataObject || !pDropSource || !pdwEffect)
+      return E_INVALIDARG;
 
   /*
    * Setup the drag n drop tracking window.
    */
-  if (!IsValidInterface((LPUNKNOWN)pDropSource))
-      return E_INVALIDARG;
 
   trackerInfo.dataObject        = pDataObject;
   trackerInfo.dropSource        = pDropSource;
@@ -500,12 +469,12 @@
   trackerInfo.curTargetHWND     = 0;
   trackerInfo.curDragTarget     = 0;
 
-  hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, "TrackerWindow",
+  hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
                                   WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
                                   CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
                                   &trackerInfo);
 
-  if (hwndTrackWindow!=0)
+  if (hwndTrackWindow)
   {
     /*
      * Capture the mouse input
@@ -517,7 +486,7 @@
     /*
      * Pump messages. All mouse input should go to the capture window.
      */
-    while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
+    while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
     {
       trackerInfo.curMousePos.x = msg.pt.x;
       trackerInfo.curMousePos.y = msg.pt.y;
@@ -548,7 +517,7 @@
 	/*
 	 * Dispatch the messages only when it's not a keyboard message.
 	 */
-	DispatchMessageA(&msg);
+	DispatchMessageW(&msg);
       }
     }
 
@@ -584,7 +553,9 @@
   DWORD    dwAspect,
   DWORD*   pdwStatus)
 {
-  char    keyName[60];
+  static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0};
+  static const WCHAR dfmtW[] = {'%','d',0};
+  WCHAR   keyName[60];
   HKEY    clsidKey;
   HKEY    miscStatusKey;
   HKEY    aspectKey;
@@ -598,17 +569,17 @@
   /*
    * Build the key name we're looking for
    */
-  sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
-           clsid->Data1, clsid->Data2, clsid->Data3,
-           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
-           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
-
-  TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus);
+  sprintfW( keyName, clsidfmtW,
+            clsid->Data1, clsid->Data2, clsid->Data3,
+            clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
+            clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
+
+  TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwAspect, pdwStatus);
 
   /*
    * Open the class id Key
    */
-  result = RegOpenKeyA(HKEY_CLASSES_ROOT,
+  result = RegOpenKeyW(HKEY_CLASSES_ROOT,
 		       keyName,
 		       &clsidKey);
 
@@ -618,8 +589,8 @@
   /*
    * Get the MiscStatus
    */
-  result = RegOpenKeyA(clsidKey,
-		       "MiscStatus",
+  result = RegOpenKeyW(clsidKey,
+		       miscstatusW,
 		       &miscStatusKey);
 
 
@@ -637,9 +608,9 @@
   /*
    * Open the key specific to the requested aspect.
    */
-  sprintf(keyName, "%d", dwAspect);
-
-  result = RegOpenKeyA(miscStatusKey,
+  sprintfW(keyName, dfmtW, dwAspect);
+
+  result = RegOpenKeyW(miscStatusKey,
 		       keyName,
 		       &aspectKey);
 
@@ -1180,7 +1151,7 @@
  */
 static BOOL OLEMenu_InstallHooks( DWORD tid )
 {
-  OleMenuHookItem *pHookItem = NULL;
+  OleMenuHookItem *pHookItem;
 
   /* Create an entry for the hook table */
   if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
@@ -1189,15 +1160,16 @@
 
   pHookItem->tid = tid;
   pHookItem->hHeap = GetProcessHeap();
+  pHookItem->CallWndProc_hHook = NULL;
 
   /* Install a thread scope message hook for WH_GETMESSAGE */
-  pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
+  pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
                                                0, GetCurrentThreadId() );
   if ( !pHookItem->GetMsg_hHook )
     goto CLEANUP;
 
   /* Install a thread scope message hook for WH_CALLWNDPROC */
-  pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
+  pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
                                                     0, GetCurrentThreadId() );
   if ( !pHookItem->CallWndProc_hHook )
     goto CLEANUP;
@@ -1271,7 +1243,7 @@
  */
 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
 {
-  OleMenuHookItem *pHookItem = NULL;
+  OleMenuHookItem *pHookItem;
 
   /* Do a simple linear search for an entry whose tid matches ours.
    * We really need a map but efficiency is not a concern here. */
@@ -1376,7 +1348,7 @@
  */
 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
 {
-  LPCWPSTRUCT pMsg = NULL;
+  LPCWPSTRUCT pMsg;
   HOLEMENU hOleMenu = 0;
   OleMenuDescriptor *pOleMenuDescriptor = NULL;
   OleMenuHookItem *pHookItem = NULL;
@@ -1395,7 +1367,7 @@
    * If the window has an OLEMenu property we may need to dispatch
    * the menu message to its active objects window instead. */
 
-  hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
+  hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
   if ( !hOleMenu )
     goto NEXTHOOK;
 
@@ -1413,7 +1385,7 @@
       pOleMenuDescriptor->bIsServerItem = FALSE;
 
       /* Send this message to the server as well */
-      SendMessageA( pOleMenuDescriptor->hwndActiveObject,
+      SendMessageW( pOleMenuDescriptor->hwndActiveObject,
                   pMsg->message, pMsg->wParam, pMsg->lParam );
       goto NEXTHOOK;
     }
@@ -1454,7 +1426,7 @@
   /* If the message was for the server dispatch it accordingly */
   if ( pOleMenuDescriptor->bIsServerItem )
   {
-    SendMessageA( pOleMenuDescriptor->hwndActiveObject,
+    SendMessageW( pOleMenuDescriptor->hwndActiveObject,
                   pMsg->message, pMsg->wParam, pMsg->lParam );
   }
 
@@ -1481,7 +1453,7 @@
  */
 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
 {
-  LPMSG pMsg = NULL;
+  LPMSG pMsg;
   HOLEMENU hOleMenu = 0;
   OleMenuDescriptor *pOleMenuDescriptor = NULL;
   OleMenuHookItem *pHookItem = NULL;
@@ -1500,7 +1472,7 @@
    * If the window has an OLEMenu property we may need to dispatch
    * the menu message to its active objects window instead. */
 
-  hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
+  hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
   if ( !hOleMenu )
     goto NEXTHOOK;
 
@@ -1671,7 +1643,7 @@
     pOleMenuDescriptor = NULL;
 
     /* Add a menu descriptor windows property to the frame window */
-    SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
+    SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
 
     /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
     if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
@@ -1684,7 +1656,7 @@
       return E_FAIL;
 
     /* Remove the menu descriptor property from the frame window */
-    RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
+    RemovePropW( hwndFrame, prop_olemenuW );
   }
 
   return S_OK;
@@ -1870,9 +1842,9 @@
  */
 static void OLEDD_Initialize(void)
 {
-    WNDCLASSA wndClass;
-
-    ZeroMemory (&wndClass, sizeof(WNDCLASSA));
+    WNDCLASSW wndClass;
+
+    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
     wndClass.style         = CS_GLOBALCLASS;
     wndClass.lpfnWndProc   = OLEDD_DragTrackerWindowProc;
     wndClass.cbClsExtra    = 0;
@@ -1881,58 +1853,7 @@
     wndClass.hbrBackground = 0;
     wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
 
-    RegisterClassA (&wndClass);
-}
-
-/***
- * OLEDD_FreeDropTarget()
- *
- * Frees the drag and drop data structure
- */
-static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target)
-{
-  list_remove(&dropTargetInfo->entry);
-  if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget);
-  HeapFree(GetProcessHeap(), 0, dropTargetInfo);
-}
-
-/***
- * OLEDD_UnInitialize()
- *
- * Releases the OLE drag and drop data structures.
- */
-void OLEDD_UnInitialize(void)
-{
-  /*
-   * Simply empty the list.
-   */
-  while (!list_empty(&targetListHead))
-  {
-    DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry);
-    OLEDD_FreeDropTarget(curNode, FALSE);
-  }
-}
-
-/***
- * OLEDD_FindDropTarget()
- *
- * Finds information about the drop target.
- */
-static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
-{
-  DropTargetNode*  curNode;
-
-  /*
-   * Iterate the list to find the HWND value.
-   */
-  LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry)
-    if (hwndOfTarget==curNode->hwndTarget)
-      return curNode;
-
-  /*
-   * If we get here, the item is not in the list
-   */
-  return NULL;
+    RegisterClassW (&wndClass);
 }
 
 /***
@@ -1958,7 +1879,7 @@
     {
       LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
 
-      SetWindowLongPtrA(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
+      SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
       SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
 
       break;
@@ -1989,7 +1910,7 @@
   /*
    * This is a window proc after all. Let's call the default.
    */
-  return DefWindowProcA (hwnd, uMsg, wParam, lParam);
+  return DefWindowProcW (hwnd, uMsg, wParam, lParam);
 }
 
 /***
@@ -2038,46 +1959,65 @@
   }
   else
   {
-    DropTargetNode* newDropTargetNode = 0;
-
     /*
      * If we changed window, we have to notify our old target and check for
      * the new one.
      */
-    if (trackerInfo->curDragTarget!=0)
-    {
+    if (trackerInfo->curDragTarget)
       IDropTarget_DragLeave(trackerInfo->curDragTarget);
-    }
 
     /*
      * Make sure we're hovering over a window.
      */
-    if (hwndNewTarget!=0)
+    if (hwndNewTarget)
     {
       /*
        * Find-out if there is a drag target under the mouse
        */
-      HWND nexttar = hwndNewTarget;
+      HWND next_target_wnd = hwndNewTarget;
+      IDropTarget *new_target;
+      DWORD pid;
+
       trackerInfo->curTargetHWND = hwndNewTarget;
 
       do {
-	newDropTargetNode = OLEDD_FindDropTarget(nexttar);
-      } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
-      if(nexttar) hwndNewTarget = nexttar;
-
-      trackerInfo->curDragTargetHWND = hwndNewTarget;
-      trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
+	new_target = OLEDD_FindDropTarget(next_target_wnd);
+      } while (!new_target && (next_target_wnd = GetParent(next_target_wnd)));
+
+      if (next_target_wnd) hwndNewTarget = next_target_wnd;
+
+      GetWindowThreadProcessId(hwndNewTarget, &pid);
+      if (pid != GetCurrentProcessId())
+      {
+        FIXME("drop to another process window is unsupported\n");
+        trackerInfo->curDragTargetHWND = 0;
+        trackerInfo->curTargetHWND     = 0;
+        trackerInfo->curDragTarget     = 0;
+      }
+      else
+      {
+        trackerInfo->curDragTargetHWND = hwndNewTarget;
+        trackerInfo->curDragTarget     = new_target;
+      }
 
       /*
        * If there is, notify it that we just dragged-in
        */
-      if (trackerInfo->curDragTarget!=0)
+      if (trackerInfo->curDragTarget)
       {
-	IDropTarget_DragEnter(trackerInfo->curDragTarget,
-			      trackerInfo->dataObject,
-                              trackerInfo->dwKeyState,
-                              trackerInfo->curMousePos,
-			      trackerInfo->pdwEffect);
+        hr = IDropTarget_DragEnter(trackerInfo->curDragTarget,
+                                   trackerInfo->dataObject,
+                                   trackerInfo->dwKeyState,
+                                   trackerInfo->curMousePos,
+                                   trackerInfo->pdwEffect);
+
+        /* failed DragEnter() means invalid target */
+        if (hr != S_OK)
+        {
+          trackerInfo->curDragTargetHWND = 0;
+          trackerInfo->curTargetHWND     = 0;
+          trackerInfo->curDragTarget     = 0;
+        }
       }
     }
     else
@@ -2110,24 +2050,28 @@
    * when that's the case, we must display the standard drag and drop
    * cursors.
    */
-  if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
-  {
+  if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
+  {
+    HCURSOR hCur;
+
     if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
     {
-      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(1)));
+      hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(1));
     }
     else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
     {
-      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(2)));
+      hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(2));
     }
     else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
     {
-      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(3)));
+      hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(3));
     }
     else
     {
-      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(0)));
-    }
+      hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(0));
+    }
+
+    SetCursor(hCur);
   }
 }
 
@@ -2174,7 +2118,7 @@
      * If we end-up over a target, drop the object in the target or
      * inform the target that the operation was cancelled.
      */
-    if (trackerInfo->curDragTarget!=0)
+    if (trackerInfo->curDragTarget)
     {
       switch (trackerInfo->returnValue)
       {
@@ -2183,14 +2127,16 @@
 	 * the drop target that we just dropped the object in it.
 	 */
         case DRAGDROP_S_DROP:
-	{
-	  IDropTarget_Drop(trackerInfo->curDragTarget,
-			   trackerInfo->dataObject,
-                           trackerInfo->dwKeyState,
-                           trackerInfo->curMousePos,
-			   trackerInfo->pdwEffect);
-	  break;
-	}
+          if (*trackerInfo->pdwEffect != DROPEFFECT_NONE)
+            IDropTarget_Drop(trackerInfo->curDragTarget,
+                             trackerInfo->dataObject,
+                             trackerInfo->dwKeyState,
+                             trackerInfo->curMousePos,
+                             trackerInfo->pdwEffect);
+          else
+            IDropTarget_DragLeave(trackerInfo->curDragTarget);
+          break;
+
 	/*
 	 * If the source told us that we should cancel, fool the drop
 	 * target by telling it that the mouse left it's window.
@@ -2256,13 +2202,13 @@
   HKEY   regKey,
   DWORD* pdwValue)
 {
-  char  buffer[20];
+  WCHAR buffer[20];
+  DWORD cbData = sizeof(buffer);
   DWORD dwKeyType;
-  DWORD cbData = 20;
   LONG  lres;
 
-  lres = RegQueryValueExA(regKey,
-			  "",
+  lres = RegQueryValueExW(regKey,
+			  emptyW,
 			  NULL,
 			  &dwKeyType,
 			  (LPBYTE)buffer,
@@ -2278,7 +2224,7 @@
       case REG_EXPAND_SZ:
       case REG_MULTI_SZ:
       case REG_SZ:
-	*pdwValue = (DWORD)strtoul(buffer, NULL, 10);
+	*pdwValue = (DWORD)strtoulW(buffer, NULL, 10);
 	break;
     }
   }

Modified: trunk/reactos/dll/win32/ole32/stg_prop.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/stg_prop.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/stg_prop.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/stg_prop.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -1314,6 +1314,13 @@
     hr = PropertyStorage_ReadFmtIdOffsetFromStream(This->stm, &fmtOffset);
     if (FAILED(hr))
         goto end;
+    if (!IsEqualGUID(&fmtOffset.fmtid, &FMTID_DocSummaryInformation) &&
+        !IsEqualGUID(&fmtOffset.fmtid, &FMTID_SummaryInformation))
+    {
+        WARN("not reading unknown fmtid %s\n", debugstr_guid(&fmtOffset.fmtid));
+        hr = S_FALSE;
+        goto end;
+    }
     if (fmtOffset.dwOffset > stat.cbSize.u.LowPart)
     {
         WARN("invalid offset %d (stream length is %d)\n", fmtOffset.dwOffset,

Modified: trunk/reactos/dll/win32/ole32/storage32.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/storage32.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/storage32.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/storage32.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -118,17 +118,61 @@
 static BOOL StorageBaseImpl_IsStreamOpen(StorageBaseImpl * stg, DirRef streamEntry);
 static BOOL StorageBaseImpl_IsStorageOpen(StorageBaseImpl * stg, DirRef storageEntry);
 
+typedef struct TransactedDirEntry
+{
+  /* If applicable, a reference to the original DirEntry in the transacted
+   * parent. If this is a newly-created entry, DIRENTRY_NULL. */
+  DirRef transactedParentEntry;
+
+  /* True if this entry is being used. */
+  int inuse;
+
+  /* True if data is up to date. */
+  int read;
+
+  /* True if this entry has been modified. */
+  int dirty;
+
+  /* True if this entry's stream has been modified. */
+  int stream_dirty;
+
+  /* True if this entry has been deleted in the transacted storage, but the
+   * delete has not yet been committed. */
+  int deleted;
+
+  /* If this entry's stream has been modified, a reference to where the stream
+   * is stored in the snapshot file. */
+  DirRef stream_entry;
+
+  /* This directory entry's data, including any changes that have been made. */
+  DirEntry data;
+
+  /* A reference to the parent of this node. This is only valid while we are
+   * committing changes. */
+  DirRef parent;
+
+  /* A reference to a newly-created entry in the transacted parent. This is
+   * always equal to transactedParentEntry except when committing changes. */
+  DirRef newTransactedParentEntry;
+} TransactedDirEntry;
+
 /****************************************************************************
- * Transacted storage object that reads/writes a snapshot file.
+ * Transacted storage object.
  */
 typedef struct TransactedSnapshotImpl
 {
   struct StorageBaseImpl base;
 
   /*
-   * Changes are temporarily saved to the snapshot.
-   */
-  StorageBaseImpl *snapshot;
+   * Modified streams are temporarily saved to the scratch file.
+   */
+  StorageBaseImpl *scratch;
+
+  /* The directory structure is kept here, so that we can track how these
+   * entries relate to those in the parent storage. */
+  TransactedDirEntry *entries;
+  ULONG entries_size;
+  ULONG firstFreeEntry;
 
   /*
    * Changes are committed to the transacted parent.
@@ -1291,46 +1335,6 @@
   memset(&emptyData, 0, RAW_DIRENTRY_SIZE);
 
   hr = StorageImpl_WriteRawDirEntry(storage, index, emptyData);
-
-  return hr;
-}
-
-
-/***************************************************************************
- *
- * Internal Method
- *
- * Destroy an entry, its attached data, and all entries reachable from it.
- */
-static HRESULT DestroyReachableEntries(
-  StorageBaseImpl *base,
-  DirRef index)
-{
-  HRESULT hr = S_OK;
-  DirEntry data;
-  ULARGE_INTEGER zero;
-
-  zero.QuadPart = 0;
-
-  if (index != DIRENTRY_NULL)
-  {
-    hr = StorageBaseImpl_ReadDirEntry(base, index, &data);
-
-    if (SUCCEEDED(hr))
-      hr = DestroyReachableEntries(base, data.dirRootEntry);
-
-    if (SUCCEEDED(hr))
-      hr = DestroyReachableEntries(base, data.leftChild);
-
-    if (SUCCEEDED(hr))
-      hr = DestroyReachableEntries(base, data.rightChild);
-
-    if (SUCCEEDED(hr))
-      hr = StorageBaseImpl_StreamSetSize(base, index, zero);
-
-    if (SUCCEEDED(hr))
-      hr = StorageBaseImpl_DestroyDirEntry(base, index);
-  }
 
   return hr;
 }
@@ -2347,6 +2351,21 @@
   return &This->blockChainCache[free_index];
 }
 
+static void StorageImpl_DeleteCachedBlockChainStream(StorageImpl *This, DirRef index)
+{
+  int i;
+
+  for (i=0; i<BLOCKCHAIN_CACHE_SIZE; i++)
+  {
+    if (This->blockChainCache[i] && This->blockChainCache[i]->ownerDirEntry == index)
+    {
+      BlockChainStream_Destroy(This->blockChainCache[i]);
+      This->blockChainCache[i] = NULL;
+      return;
+    }
+  }
+}
+
 static HRESULT StorageImpl_StreamReadAt(StorageBaseImpl *base, DirRef index,
   ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
 {
@@ -2536,6 +2555,30 @@
 
     return hr;
   }
+}
+
+static HRESULT StorageImpl_StreamLink(StorageBaseImpl *base, DirRef dst,
+  DirRef src)
+{
+  StorageImpl *This = (StorageImpl*)base;
+  DirEntry dst_data, src_data;
+  HRESULT hr;
+
+  hr = StorageImpl_ReadDirEntry(This, dst, &dst_data);
+
+  if (SUCCEEDED(hr))
+    hr = StorageImpl_ReadDirEntry(This, src, &src_data);
+
+  if (SUCCEEDED(hr))
+  {
+    StorageImpl_DeleteCachedBlockChainStream(This, src);
+    dst_data.startingBlock = src_data.startingBlock;
+    dst_data.size = src_data.size;
+
+    hr = StorageImpl_WriteDirEntry(This, dst, &dst_data);
+  }
+
+  return hr;
 }
 
 /*
@@ -2573,7 +2616,8 @@
   StorageImpl_DestroyDirEntry,
   StorageImpl_StreamReadAt,
   StorageImpl_StreamWriteAt,
-  StorageImpl_StreamSetSize
+  StorageImpl_StreamSetSize,
+  StorageImpl_StreamLink
 };
 
 static HRESULT StorageImpl_Construct(
@@ -3540,6 +3584,9 @@
                     buffer,
                     &bytesRead);
 
+  if (bytesRead != RAW_DIRENTRY_SIZE)
+    return STG_E_READFAULT;
+
   return hr;
 }
 
@@ -3885,6 +3932,11 @@
 
         offset.u.LowPart += cbRead;
     }
+    else
+    {
+        resRead = STG_E_READFAULT;
+        break;
+    }
   } while (cbTotalRead.QuadPart < size.QuadPart);
   HeapFree(GetProcessHeap(),0,buffer);
 
@@ -3983,6 +4035,11 @@
 
             offset.u.LowPart += cbRead;
         }
+        else
+        {
+            resRead = STG_E_READFAULT;
+            break;
+        }
     }while(cbTotalRead.QuadPart < size.QuadPart);
     HeapFree(GetProcessHeap(), 0, buffer);
 
@@ -4011,40 +4068,384 @@
     return SmallBlockChainStream_Construct(This, NULL, streamEntryRef);
 }
 
-static HRESULT CreateSnapshotFile(StorageBaseImpl* original, StorageBaseImpl **snapshot)
+static HRESULT StorageBaseImpl_CopyStream(
+  StorageBaseImpl *dst, DirRef dst_entry,
+  StorageBaseImpl *src, DirRef src_entry)
 {
   HRESULT hr;
-  DirEntry parentData, snapshotData;
-
-  hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_DELETEONRELEASE,
-      0, (IStorage**)snapshot);
+  BYTE data[4096];
+  DirEntry srcdata;
+  ULARGE_INTEGER bytes_copied;
+  ULONG bytestocopy, bytesread, byteswritten;
+
+  hr = StorageBaseImpl_ReadDirEntry(src, src_entry, &srcdata);
 
   if (SUCCEEDED(hr))
   {
-    hr = StorageBaseImpl_ReadDirEntry(original,
-      original->storageDirEntry, &parentData);
+    hr = StorageBaseImpl_StreamSetSize(dst, dst_entry, srcdata.size);
+
+    bytes_copied.QuadPart = 0;
+    while (bytes_copied.QuadPart < srcdata.size.QuadPart && SUCCEEDED(hr))
+    {
+      bytestocopy = min(4096, srcdata.size.QuadPart - bytes_copied.QuadPart);
+
+      hr = StorageBaseImpl_StreamReadAt(src, src_entry, bytes_copied, bytestocopy,
+        data, &bytesread);
+      if (SUCCEEDED(hr) && bytesread != bytestocopy) hr = STG_E_READFAULT;
+
+      if (SUCCEEDED(hr))
+        hr = StorageBaseImpl_StreamWriteAt(dst, dst_entry, bytes_copied, bytestocopy,
+          data, &byteswritten);
+      if (SUCCEEDED(hr))
+      {
+        if (byteswritten != bytestocopy) hr = STG_E_WRITEFAULT;
+        bytes_copied.QuadPart += byteswritten;
+      }
+    }
+  }
+
+  return hr;
+}
+
+static DirRef TransactedSnapshotImpl_FindFreeEntry(TransactedSnapshotImpl *This)
+{
+  DirRef result=This->firstFreeEntry;
+
+  while (result < This->entries_size && This->entries[result].inuse)
+    result++;
+
+  if (result == This->entries_size)
+  {
+    ULONG new_size = This->entries_size * 2;
+    TransactedDirEntry *new_entries;
+
+    new_entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * new_size);
+    if (!new_entries) return DIRENTRY_NULL;
+
+    memcpy(new_entries, This->entries, sizeof(TransactedDirEntry) * This->entries_size);
+    HeapFree(GetProcessHeap(), 0, This->entries);
+
+    This->entries = new_entries;
+    This->entries_size = new_size;
+  }
+
+  This->entries[result].inuse = 1;
+
+  This->firstFreeEntry = result+1;
+
+  return result;
+}
+
+static DirRef TransactedSnapshotImpl_CreateStubEntry(
+  TransactedSnapshotImpl *This, DirRef parentEntryRef)
+{
+  DirRef stubEntryRef;
+  TransactedDirEntry *entry;
+
+  stubEntryRef = TransactedSnapshotImpl_FindFreeEntry(This);
+
+  if (stubEntryRef != DIRENTRY_NULL)
+  {
+    entry = &This->entries[stubEntryRef];
+
+    entry->newTransactedParentEntry = entry->transactedParentEntry = parentEntryRef;
+
+    entry->read = 0;
+  }
+
+  return stubEntryRef;
+}
+
+static HRESULT TransactedSnapshotImpl_EnsureReadEntry(
+  TransactedSnapshotImpl *This, DirRef entry)
+{
+  HRESULT hr=S_OK;
+  DirEntry data;
+
+  if (!This->entries[entry].read)
+  {
+    hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
+        This->entries[entry].transactedParentEntry,
+        &data);
+
+    if (SUCCEEDED(hr) && data.leftChild != DIRENTRY_NULL)
+    {
+      data.leftChild = TransactedSnapshotImpl_CreateStubEntry(This, data.leftChild);
+
+      if (data.leftChild == DIRENTRY_NULL)
+        hr = E_OUTOFMEMORY;
+    }
+
+    if (SUCCEEDED(hr) && data.rightChild != DIRENTRY_NULL)
+    {
+      data.rightChild = TransactedSnapshotImpl_CreateStubEntry(This, data.rightChild);
+
+      if (data.rightChild == DIRENTRY_NULL)
+        hr = E_OUTOFMEMORY;
+    }
+
+    if (SUCCEEDED(hr) && data.dirRootEntry != DIRENTRY_NULL)
+    {
+      data.dirRootEntry = TransactedSnapshotImpl_CreateStubEntry(This, data.dirRootEntry);
+
+      if (data.dirRootEntry == DIRENTRY_NULL)
+        hr = E_OUTOFMEMORY;
+    }
 
     if (SUCCEEDED(hr))
-      hr = StorageBaseImpl_ReadDirEntry((*snapshot),
-        (*snapshot)->storageDirEntry, &snapshotData);
+    {
+      memcpy(&This->entries[entry].data, &data, sizeof(DirEntry));
+      This->entries[entry].read = 1;
+    }
+  }
+
+  return hr;
+}
+
+static HRESULT TransactedSnapshotImpl_MakeStreamDirty(
+  TransactedSnapshotImpl *This, DirRef entry)
+{
+  HRESULT hr = S_OK;
+
+  if (!This->entries[entry].stream_dirty)
+  {
+    DirEntry new_entrydata;
+
+    memset(&new_entrydata, 0, sizeof(DirEntry));
+    new_entrydata.name[0] = 'S';
+    new_entrydata.sizeOfNameString = 1;
+    new_entrydata.stgType = STGTY_STREAM;
+    new_entrydata.startingBlock = BLOCK_END_OF_CHAIN;
+    new_entrydata.leftChild = DIRENTRY_NULL;
+    new_entrydata.rightChild = DIRENTRY_NULL;
+    new_entrydata.dirRootEntry = DIRENTRY_NULL;
+
+    hr = StorageBaseImpl_CreateDirEntry(This->scratch, &new_entrydata,
+      &This->entries[entry].stream_entry);
+
+    if (SUCCEEDED(hr) && This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
+    {
+      hr = StorageBaseImpl_CopyStream(
+        This->scratch, This->entries[entry].stream_entry,
+        This->transactedParent, This->entries[entry].transactedParentEntry);
+
+      if (FAILED(hr))
+        StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[entry].stream_entry);
+    }
 
     if (SUCCEEDED(hr))
-    {
-      memcpy(snapshotData.name, parentData.name, sizeof(snapshotData.name));
-      snapshotData.sizeOfNameString = parentData.sizeOfNameString;
-      snapshotData.stgType = parentData.stgType;
-      snapshotData.clsid = parentData.clsid;
-      snapshotData.ctime = parentData.ctime;
-      snapshotData.mtime = parentData.mtime;
-      hr = StorageBaseImpl_WriteDirEntry((*snapshot),
-        (*snapshot)->storageDirEntry, &snapshotData);
-    }
-
-    if (SUCCEEDED(hr))
-      hr = IStorage_CopyTo((IStorage*)original, 0, NULL, NULL,
-          (IStorage*)(*snapshot));
-
-    if (FAILED(hr)) IStorage_Release((IStorage*)(*snapshot));
+      This->entries[entry].stream_dirty = 1;
+
+    if (This->entries[entry].transactedParentEntry != DIRENTRY_NULL)
+    {
+      /* Since this entry is modified, and we aren't using its stream data, we
+       * no longer care about the original entry. */
+      DirRef delete_ref;
+      delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[entry].transactedParentEntry);
+
+      if (delete_ref != DIRENTRY_NULL)
+        This->entries[delete_ref].deleted = 1;
+
+      This->entries[entry].transactedParentEntry = This->entries[entry].newTransactedParentEntry = DIRENTRY_NULL;
+    }
+  }
+
+  return hr;
+}
+
+/* Find the first entry in a depth-first traversal. */
+static DirRef TransactedSnapshotImpl_FindFirstChild(
+  TransactedSnapshotImpl* This, DirRef parent)
+{
+  DirRef cursor, prev;
+  TransactedDirEntry *entry;
+
+  cursor = parent;
+  entry = &This->entries[cursor];
+  while (entry->read)
+  {
+    if (entry->data.leftChild != DIRENTRY_NULL)
+    {
+      prev = cursor;
+      cursor = entry->data.leftChild;
+      entry = &This->entries[cursor];
+      entry->parent = prev;
+    }
+    else if (entry->data.rightChild != DIRENTRY_NULL)
+    {
+      prev = cursor;
+      cursor = entry->data.rightChild;
+      entry = &This->entries[cursor];
+      entry->parent = prev;
+    }
+    else if (entry->data.dirRootEntry != DIRENTRY_NULL)
+    {
+      prev = cursor;
+      cursor = entry->data.dirRootEntry;
+      entry = &This->entries[cursor];
+      entry->parent = prev;
+    }
+    else
+      break;
+  }
+
+  return cursor;
+}
+
+/* Find the next entry in a depth-first traversal. */
+static DirRef TransactedSnapshotImpl_FindNextChild(
+  TransactedSnapshotImpl* This, DirRef current)
+{
+  DirRef parent;
+  TransactedDirEntry *parent_entry;
+
+  parent = This->entries[current].parent;
+  parent_entry = &This->entries[parent];
+
+  if (parent != DIRENTRY_NULL && parent_entry->data.dirRootEntry != current)
+  {
+    if (parent_entry->data.rightChild != current && parent_entry->data.rightChild != DIRENTRY_NULL)
+    {
+      This->entries[parent_entry->data.rightChild].parent = parent;
+      return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.rightChild);
+    }
+
+    if (parent_entry->data.dirRootEntry != DIRENTRY_NULL)
+    {
+      This->entries[parent_entry->data.dirRootEntry].parent = parent;
+      return TransactedSnapshotImpl_FindFirstChild(This, parent_entry->data.dirRootEntry);
+    }
+  }
+
+  return parent;
+}
+
+/* Return TRUE if we've made a copy of this entry for committing to the parent. */
+static inline BOOL TransactedSnapshotImpl_MadeCopy(
+  TransactedSnapshotImpl* This, DirRef entry)
+{
+  return entry != DIRENTRY_NULL &&
+    This->entries[entry].newTransactedParentEntry != This->entries[entry].transactedParentEntry;
+}
+
+/* Destroy the entries created by CopyTree. */
+static void TransactedSnapshotImpl_DestroyTemporaryCopy(
+  TransactedSnapshotImpl* This, DirRef stop)
+{
+  DirRef cursor;
+  TransactedDirEntry *entry;
+  ULARGE_INTEGER zero;
+
+  zero.QuadPart = 0;
+
+  if (!This->entries[This->base.storageDirEntry].read)
+    return;
+
+  cursor = This->entries[This->base.storageDirEntry].data.dirRootEntry;
+
+  if (cursor == DIRENTRY_NULL)
+    return;
+
+  cursor = TransactedSnapshotImpl_FindFirstChild(This, cursor);
+
+  while (cursor != DIRENTRY_NULL && cursor != stop)
+  {
+    if (TransactedSnapshotImpl_MadeCopy(This, cursor))
+    {
+      entry = &This->entries[cursor];
+
+      if (entry->stream_dirty)
+        StorageBaseImpl_StreamSetSize(This->transactedParent,
+          entry->newTransactedParentEntry, zero);
+
+      StorageBaseImpl_DestroyDirEntry(This->transactedParent,
+        entry->newTransactedParentEntry);
+
+      entry->newTransactedParentEntry = entry->transactedParentEntry;
+    }
+
+    cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
+  }
+}
+
+/* Make a copy of our edited tree that we can use in the parent. */
+static HRESULT TransactedSnapshotImpl_CopyTree(TransactedSnapshotImpl* This)
+{
+  DirRef cursor;
+  TransactedDirEntry *entry;
+  HRESULT hr = S_OK;
+
+  cursor = This->base.storageDirEntry;
+  entry = &This->entries[cursor];
+  entry->parent = DIRENTRY_NULL;
+  entry->newTransactedParentEntry = entry->transactedParentEntry;
+
+  if (entry->data.dirRootEntry == DIRENTRY_NULL)
+    return S_OK;
+
+  This->entries[entry->data.dirRootEntry].parent = DIRENTRY_NULL;
+
+  cursor = TransactedSnapshotImpl_FindFirstChild(This, entry->data.dirRootEntry);
+  entry = &This->entries[cursor];
+
+  while (cursor != DIRENTRY_NULL)
+  {
+    /* Make a copy of this entry in the transacted parent. */
+    if (!entry->read ||
+        (!entry->dirty && !entry->stream_dirty &&
+         !TransactedSnapshotImpl_MadeCopy(This, entry->data.leftChild) &&
+         !TransactedSnapshotImpl_MadeCopy(This, entry->data.rightChild) &&
+         !TransactedSnapshotImpl_MadeCopy(This, entry->data.dirRootEntry)))
+      entry->newTransactedParentEntry = entry->transactedParentEntry;
+    else
+    {
+      DirEntry newData;
+
+      memcpy(&newData, &entry->data, sizeof(DirEntry));
+
+      newData.size.QuadPart = 0;
+      newData.startingBlock = BLOCK_END_OF_CHAIN;
+
+      if (newData.leftChild != DIRENTRY_NULL)
+        newData.leftChild = This->entries[newData.leftChild].newTransactedParentEntry;
+
+      if (newData.rightChild != DIRENTRY_NULL)
+        newData.rightChild = This->entries[newData.rightChild].newTransactedParentEntry;
+
+      if (newData.dirRootEntry != DIRENTRY_NULL)
+        newData.dirRootEntry = This->entries[newData.dirRootEntry].newTransactedParentEntry;
+
+      hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &newData,
+        &entry->newTransactedParentEntry);
+      if (FAILED(hr))
+      {
+        TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
+        return hr;
+      }
+
+      if (entry->stream_dirty)
+      {
+        hr = StorageBaseImpl_CopyStream(
+          This->transactedParent, entry->newTransactedParentEntry,
+          This->scratch, entry->stream_entry);
+      }
+      else if (entry->data.size.QuadPart)
+      {
+        hr = StorageBaseImpl_StreamLink(
+          This->transactedParent, entry->newTransactedParentEntry,
+          entry->transactedParentEntry);
+      }
+
+      if (FAILED(hr))
+      {
+        cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
+        TransactedSnapshotImpl_DestroyTemporaryCopy(This, cursor);
+        return hr;
+      }
+    }
+
+    cursor = TransactedSnapshotImpl_FindNextChild(This, cursor);
+    entry = &This->entries[cursor];
   }
 
   return hr;
@@ -4055,10 +4456,13 @@
   DWORD                  grfCommitFlags)  /* [in] */
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
+  TransactedDirEntry *root_entry;
+  DirRef i, dir_root_ref;
+  DirEntry data;
+  ULARGE_INTEGER zero;
   HRESULT hr;
-  DirEntry data, tempStorageData, snapshotRootData;
-  DirRef tempStorageEntry, oldDirRoot;
-  StorageInternalImpl *tempStorage;
+
+  zero.QuadPart = 0;
 
   TRACE("(%p,%x)\n", iface, grfCommitFlags);
 
@@ -4072,75 +4476,71 @@
    * needed in the rare situation where we have just enough free disk space to
    * overwrite the existing data. */
 
-  /* Create an orphaned storage in the parent for the new directory structure. */
-  memset(&data, 0, sizeof(data));
-  data.name[0] = 'D';
-  data.sizeOfNameString = 1;
-  data.stgType = STGTY_STORAGE;
-  data.leftChild = DIRENTRY_NULL;
-  data.rightChild = DIRENTRY_NULL;
-  data.dirRootEntry = DIRENTRY_NULL;
-  hr = StorageBaseImpl_CreateDirEntry(This->transactedParent, &data, &tempStorageEntry);
-
+  root_entry = &This->entries[This->base.storageDirEntry];
+
+  if (!root_entry->read)
+    return S_OK;
+
+  hr = TransactedSnapshotImpl_CopyTree(This);
   if (FAILED(hr)) return hr;
 
-  tempStorage = StorageInternalImpl_Construct(This->transactedParent,
-    STGM_READWRITE|STGM_SHARE_EXCLUSIVE, tempStorageEntry);
-  if (tempStorage)
-  {
-    hr = IStorage_CopyTo((IStorage*)This->snapshot, 0, NULL, NULL,
-        (IStorage*)tempStorage);
-
-    list_init(&tempStorage->ParentListEntry);
-
-    IStorage_Release((IStorage*) tempStorage);
-  }
+  if (root_entry->data.dirRootEntry == DIRENTRY_NULL)
+    dir_root_ref = DIRENTRY_NULL;
   else
-    hr = E_OUTOFMEMORY;
-
-  if (FAILED(hr))
-  {
-    DestroyReachableEntries(This->transactedParent, tempStorageEntry);
-    return hr;
-  }
+    dir_root_ref = This->entries[root_entry->data.dirRootEntry].newTransactedParentEntry;
 
   /* Update the storage to use the new data in one step. */
   hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
-    This->transactedParent->storageDirEntry, &data);
+    root_entry->transactedParentEntry, &data);
 
   if (SUCCEEDED(hr))
   {
-    hr = StorageBaseImpl_ReadDirEntry(This->transactedParent,
-      tempStorageEntry, &tempStorageData);
+    data.dirRootEntry = dir_root_ref;
+    data.clsid = root_entry->data.clsid;
+    data.ctime = root_entry->data.ctime;
+    data.mtime = root_entry->data.mtime;
+
+    hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
+      root_entry->transactedParentEntry, &data);
   }
 
   if (SUCCEEDED(hr))
   {
-    hr = StorageBaseImpl_ReadDirEntry(This->snapshot,
-      This->snapshot->storageDirEntry, &snapshotRootData);
-  }
-
-  if (SUCCEEDED(hr))
-  {
-    oldDirRoot = data.dirRootEntry;
-    data.dirRootEntry = tempStorageData.dirRootEntry;
-    data.clsid = snapshotRootData.clsid;
-    data.ctime = snapshotRootData.ctime;
-    data.mtime = snapshotRootData.mtime;
-
-    hr = StorageBaseImpl_WriteDirEntry(This->transactedParent,
-      This->transactedParent->storageDirEntry, &data);
-  }
-
-  if (SUCCEEDED(hr))
-  {
     /* Destroy the old now-orphaned data. */
-    DestroyReachableEntries(This->transactedParent, oldDirRoot);
-    StorageBaseImpl_DestroyDirEntry(This->transactedParent, tempStorageEntry);
+    for (i=0; i<This->entries_size; i++)
+    {
+      TransactedDirEntry *entry = &This->entries[i];
+      if (entry->inuse)
+      {
+        if (entry->deleted)
+        {
+          StorageBaseImpl_StreamSetSize(This->transactedParent,
+            entry->transactedParentEntry, zero);
+          StorageBaseImpl_DestroyDirEntry(This->transactedParent,
+            entry->transactedParentEntry);
+          memset(entry, 0, sizeof(TransactedDirEntry));
+          This->firstFreeEntry = min(i, This->firstFreeEntry);
+        }
+        else if (entry->read && entry->transactedParentEntry != entry->newTransactedParentEntry)
+        {
+          if (entry->transactedParentEntry != DIRENTRY_NULL)
+            StorageBaseImpl_DestroyDirEntry(This->transactedParent,
+              entry->transactedParentEntry);
+          if (entry->stream_dirty)
+          {
+            StorageBaseImpl_StreamSetSize(This->scratch, entry->stream_entry, zero);
+            StorageBaseImpl_DestroyDirEntry(This->scratch, entry->stream_entry);
+            entry->stream_dirty = 0;
+          }
+          entry->dirty = 0;
+          entry->transactedParentEntry = entry->newTransactedParentEntry;
+        }
+      }
+    }
   }
   else
   {
-    DestroyReachableEntries(This->transactedParent, tempStorageEntry);
+    TransactedSnapshotImpl_DestroyTemporaryCopy(This, DIRENTRY_NULL);
   }
 
   return hr;
@@ -4150,21 +4550,31 @@
   IStorage*            iface)
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
-  StorageBaseImpl *newSnapshot;
-  HRESULT hr;
+  ULARGE_INTEGER zero;
+  ULONG i;
 
   TRACE("(%p)\n", iface);
-
-  /* Create a new copy of the parent data. */
-  hr = CreateSnapshotFile(This->transactedParent, &newSnapshot);
-  if (FAILED(hr)) return hr;
 
   /* Destroy the open objects. */
   StorageBaseImpl_DeleteAll(&This->base);
 
-  /* Replace our current snapshot. */
-  IStorage_Release((IStorage*)This->snapshot);
-  This->snapshot = newSnapshot;
+  /* Clear out the scratch file. */
+  zero.QuadPart = 0;
+  for (i=0; i<This->entries_size; i++)
+  {
+    if (This->entries[i].stream_dirty)
+    {
+      StorageBaseImpl_StreamSetSize(This->scratch, This->entries[i].stream_entry,
+        zero);
+
+      StorageBaseImpl_DestroyDirEntry(This->scratch, This->entries[i].stream_entry);
+    }
+  }
+
+  memset(This->entries, 0, sizeof(TransactedDirEntry) * This->entries_size);
+
+  This->firstFreeEntry = 0;
+  This->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(This, This->transactedParent->storageDirEntry);
 
   return S_OK;
 }
@@ -4185,11 +4595,13 @@
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) iface;
 
-  TransactedSnapshotImpl_Invalidate(iface);
+  TransactedSnapshotImpl_Revert((IStorage*)iface);
 
   IStorage_Release((IStorage*)This->transactedParent);
 
-  IStorage_Release((IStorage*)This->snapshot);
+  IStorage_Release((IStorage*)This->scratch);
+
+  HeapFree(GetProcessHeap(), 0, This->entries);
 
   HeapFree(GetProcessHeap(), 0, This);
 }
@@ -4198,27 +4610,76 @@
   const DirEntry *newData, DirRef *index)
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
-
-  return StorageBaseImpl_CreateDirEntry(This->snapshot,
-    newData, index);
+  DirRef new_ref;
+  TransactedDirEntry *new_entry;
+
+  new_ref = TransactedSnapshotImpl_FindFreeEntry(This);
+  if (new_ref == DIRENTRY_NULL)
+    return E_OUTOFMEMORY;
+
+  new_entry = &This->entries[new_ref];
+
+  new_entry->newTransactedParentEntry = new_entry->transactedParentEntry = DIRENTRY_NULL;
+  new_entry->read = 1;
+  new_entry->dirty = 1;
+  memcpy(&new_entry->data, newData, sizeof(DirEntry));
+
+  *index = new_ref;
+
+  TRACE("%s l=%x r=%x d=%x <-- %x\n", debugstr_w(newData->name), newData->leftChild, newData->rightChild, newData->dirRootEntry, *index);
+
+  return S_OK;
 }
 
 static HRESULT TransactedSnapshotImpl_WriteDirEntry(StorageBaseImpl *base,
   DirRef index, const DirEntry *data)
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
-
-  return StorageBaseImpl_WriteDirEntry(This->snapshot,
-    index, data);
+  HRESULT hr;
+
+  TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
+
+  hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
+  if (FAILED(hr)) return hr;
+
+  memcpy(&This->entries[index].data, data, sizeof(DirEntry));
+
+  if (index != This->base.storageDirEntry)
+  {
+    This->entries[index].dirty = 1;
+
+    if (data->size.QuadPart == 0 &&
+        This->entries[index].transactedParentEntry != DIRENTRY_NULL)
+    {
+      /* Since this entry is modified, and we aren't using its stream data, we
+       * no longer care about the original entry. */
+      DirRef delete_ref;
+      delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
+
+      if (delete_ref != DIRENTRY_NULL)
+        This->entries[delete_ref].deleted = 1;
+
+      This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
+    }
+  }
+
+  return S_OK;
 }
 
 static HRESULT TransactedSnapshotImpl_ReadDirEntry(StorageBaseImpl *base,
   DirRef index, DirEntry *data)
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
-
-  return StorageBaseImpl_ReadDirEntry(This->snapshot,
-    index, data);
+  HRESULT hr;
+
+  hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
+  if (FAILED(hr)) return hr;
+
+  memcpy(data, &This->entries[index].data, sizeof(DirEntry));
+
+  TRACE("%x %s l=%x r=%x d=%x\n", index, debugstr_w(data->name), data->leftChild, data->rightChild, data->dirRootEntry);
+
+  return S_OK;
 }
 
 static HRESULT TransactedSnapshotImpl_DestroyDirEntry(StorageBaseImpl *base,
@@ -4226,8 +4687,21 @@
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
 
-  return StorageBaseImpl_DestroyDirEntry(This->snapshot,
-    index);
+  if (This->entries[index].transactedParentEntry == DIRENTRY_NULL ||
+      This->entries[index].data.size.QuadPart != 0)
+  {
+    /* If we deleted this entry while it has stream data. We must have left the
+     * data because some other entry is using it, and we need to leave the
+     * original entry alone. */
+    memset(&This->entries[index], 0, sizeof(TransactedDirEntry));
+    This->firstFreeEntry = min(index, This->firstFreeEntry);
+  }
+  else
+  {
+    This->entries[index].deleted = 1;
+  }
+
+  return S_OK;
 }
 
 static HRESULT TransactedSnapshotImpl_StreamReadAt(StorageBaseImpl *base,
@@ -4235,26 +4709,122 @@
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
 
-  return StorageBaseImpl_StreamReadAt(This->snapshot,
-    index, offset, size, buffer, bytesRead);
+  if (This->entries[index].stream_dirty)
+  {
+    return StorageBaseImpl_StreamReadAt(This->scratch,
+        This->entries[index].stream_entry, offset, size, buffer, bytesRead);
+  }
+  else if (This->entries[index].transactedParentEntry == DIRENTRY_NULL)
+  {
+    /* This stream doesn't live in the parent, and we haven't allocated storage
+     * for it yet */
+    *bytesRead = 0;
+    return S_OK;
+  }
+  else
+  {
+    return StorageBaseImpl_StreamReadAt(This->transactedParent,
+        This->entries[index].transactedParentEntry, offset, size, buffer, bytesRead);
+  }
 }
 
 static HRESULT TransactedSnapshotImpl_StreamWriteAt(StorageBaseImpl *base,
   DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
-
-  return StorageBaseImpl_StreamWriteAt(This->snapshot,
-    index, offset, size, buffer, bytesWritten);
+  HRESULT hr;
+
+  hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
+  if (FAILED(hr)) return hr;
+
+  hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
+  if (FAILED(hr)) return hr;
+
+  hr = StorageBaseImpl_StreamWriteAt(This->scratch,
+    This->entries[index].stream_entry, offset, size, buffer, bytesWritten);
+
+  if (SUCCEEDED(hr) && size != 0)
+    This->entries[index].data.size.QuadPart = max(
+        This->entries[index].data.size.QuadPart,
+        offset.QuadPart + size);
+
+  return hr;
 }
 
 static HRESULT TransactedSnapshotImpl_StreamSetSize(StorageBaseImpl *base,
   DirRef index, ULARGE_INTEGER newsize)
 {
   TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
-
-  return StorageBaseImpl_StreamSetSize(This->snapshot,
-    index, newsize);
+  HRESULT hr;
+
+  hr = TransactedSnapshotImpl_EnsureReadEntry(This, index);
+  if (FAILED(hr)) return hr;
+
+  if (This->entries[index].data.size.QuadPart == newsize.QuadPart)
+    return S_OK;
+
+  if (newsize.QuadPart == 0)
+  {
+    /* Destroy any parent references or entries in the scratch file. */
+    if (This->entries[index].stream_dirty)
+    {
+      ULARGE_INTEGER zero;
+      zero.QuadPart = 0;
+      StorageBaseImpl_StreamSetSize(This->scratch,
+        This->entries[index].stream_entry, zero);
+      StorageBaseImpl_DestroyDirEntry(This->scratch,
+        This->entries[index].stream_entry);
+      This->entries[index].stream_dirty = 0;
+    }
+    else if (This->entries[index].transactedParentEntry != DIRENTRY_NULL)
+    {
+      DirRef delete_ref;
+      delete_ref = TransactedSnapshotImpl_CreateStubEntry(This, This->entries[index].transactedParentEntry);
+
+      if (delete_ref != DIRENTRY_NULL)
+        This->entries[delete_ref].deleted = 1;
+
+      This->entries[index].transactedParentEntry = This->entries[index].newTransactedParentEntry = DIRENTRY_NULL;
+    }
+  }
+  else
+  {
+    hr = TransactedSnapshotImpl_MakeStreamDirty(This, index);
+    if (FAILED(hr)) return hr;
+
+    hr = StorageBaseImpl_StreamSetSize(This->scratch,
+      This->entries[index].stream_entry, newsize);
+  }
+
+  if (SUCCEEDED(hr))
+    This->entries[index].data.size = newsize;
+
+  return hr;
+}
+
+static HRESULT TransactedSnapshotImpl_StreamLink(StorageBaseImpl *base,
+  DirRef dst, DirRef src)
+{
+  TransactedSnapshotImpl* This = (TransactedSnapshotImpl*) base;
+  HRESULT hr;
+  TransactedDirEntry *dst_entry, *src_entry;
+
+  hr = TransactedSnapshotImpl_EnsureReadEntry(This, src);
+  if (FAILED(hr)) return hr;
+
+  hr = TransactedSnapshotImpl_EnsureReadEntry(This, dst);
+  if (FAILED(hr)) return hr;
+
+  dst_entry = &This->entries[dst];
+  src_entry = &This->entries[src];
+
+  dst_entry->stream_dirty = src_entry->stream_dirty;
+  dst_entry->stream_entry = src_entry->stream_entry;
+  dst_entry->transactedParentEntry = src_entry->transactedParentEntry;
+  dst_entry->newTransactedParentEntry = src_entry->newTransactedParentEntry;
+  dst_entry->data.size = src_entry->data.size;
+
+  return S_OK;
 }
 
 static const IStorageVtbl TransactedSnapshotImpl_Vtbl =
@@ -4289,7 +4859,8 @@
   TransactedSnapshotImpl_DestroyDirEntry,
   TransactedSnapshotImpl_StreamReadAt,
   TransactedSnapshotImpl_StreamWriteAt,
-  TransactedSnapshotImpl_StreamSetSize
+  TransactedSnapshotImpl_StreamSetSize,
+  TransactedSnapshotImpl_StreamLink
 };
 
 static HRESULT TransactedSnapshotImpl_Construct(StorageBaseImpl *parentStorage,
@@ -4317,17 +4888,35 @@
 
     (*result)->base.filename = parentStorage->filename;
 
-    /* Create a new temporary storage to act as the snapshot */
-    hr = CreateSnapshotFile(parentStorage, &(*result)->snapshot);
+    /* Create a new temporary storage to act as the scratch file. */
+    hr = StgCreateDocfile(NULL, STGM_READWRITE|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
+        0, (IStorage**)&(*result)->scratch);
 
     if (SUCCEEDED(hr))
     {
-        (*result)->base.storageDirEntry = (*result)->snapshot->storageDirEntry;
-
-        /* parentStorage already has 1 reference, which we take over here. */
-        (*result)->transactedParent = parentStorage;
-
-        parentStorage->transactedChild = (StorageBaseImpl*)*result;
+        ULONG num_entries = 20;
+
+        (*result)->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TransactedDirEntry) * num_entries);
+
+        (*result)->entries_size = num_entries;
+
+        (*result)->firstFreeEntry = 0;
+
+        if ((*result)->entries)
+        {
+            /* parentStorage already has 1 reference, which we take over here. */
+            (*result)->transactedParent = parentStorage;
+
+            parentStorage->transactedChild = (StorageBaseImpl*)*result;
+
+            (*result)->base.storageDirEntry = TransactedSnapshotImpl_CreateStubEntry(*result, parentStorage->storageDirEntry);
+        }
+        else
+        {
+            IStorage_Release((IStorage*)(*result)->scratch);
+
+            hr = E_OUTOFMEMORY;
+        }
     }
 
     if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, (*result));
@@ -4472,6 +5061,15 @@
 
   return StorageBaseImpl_StreamSetSize(This->parentStorage,
     index, newsize);
+}
+
+static HRESULT StorageInternalImpl_StreamLink(StorageBaseImpl *base,
+  DirRef dst, DirRef src)
+{
+  StorageInternalImpl* This = (StorageInternalImpl*) base;
+
+  return StorageBaseImpl_StreamLink(This->parentStorage,
+    dst, src);
 }
 
 /******************************************************************************
@@ -4833,7 +5431,8 @@
   StorageInternalImpl_DestroyDirEntry,
   StorageInternalImpl_StreamReadAt,
   StorageInternalImpl_StreamWriteAt,
-  StorageInternalImpl_StreamSetSize
+  StorageInternalImpl_StreamSetSize,
+  StorageInternalImpl_StreamLink
 };
 
 /******************************************************************************
@@ -5026,38 +5625,134 @@
 ** BlockChainStream implementation
 */
 
+/* Read and save the index of all blocks in this stream. */
+HRESULT BlockChainStream_UpdateIndexCache(BlockChainStream* This)
+{
+  ULONG  next_sector, next_offset;
+  HRESULT hr;
+  struct BlockChainRun *last_run;
+
+  if (This->indexCacheLen == 0)
+  {
+    last_run = NULL;
+    next_offset = 0;
+    next_sector = BlockChainStream_GetHeadOfChain(This);
+  }
+  else
+  {
+    last_run = &This->indexCache[This->indexCacheLen-1];
+    next_offset = last_run->lastOffset+1;
+    hr = StorageImpl_GetNextBlockInChain(This->parentStorage,
+        last_run->firstSector + last_run->lastOffset - last_run->firstOffset,
+        &next_sector);
+    if (FAILED(hr)) return hr;
+  }
+
+  while (next_sector != BLOCK_END_OF_CHAIN)
+  {
+    if (!last_run || next_sector != last_run->firstSector + next_offset - last_run->firstOffset)
+    {
+      /* Add the current block to the cache. */
+      if (This->indexCacheSize == 0)
+      {
+        This->indexCache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*16);
+        if (!This->indexCache) return E_OUTOFMEMORY;
+        This->indexCacheSize = 16;
+      }
+      else if (This->indexCacheSize == This->indexCacheLen)
+      {
+        struct BlockChainRun *new_cache;
+        ULONG new_size;
+
+        new_size = This->indexCacheSize * 2;
+        new_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(struct BlockChainRun)*new_size);
+        if (!new_cache) return E_OUTOFMEMORY;
+        memcpy(new_cache, This->indexCache, sizeof(struct BlockChainRun)*This->indexCacheLen);
+
+        HeapFree(GetProcessHeap(), 0, This->indexCache);
+        This->indexCache = new_cache;
+        This->indexCacheSize = new_size;
+      }
+
+      This->indexCacheLen++;
+      last_run = &This->indexCache[This->indexCacheLen-1];
+      last_run->firstSector = next_sector;
+      last_run->firstOffset = next_offset;
+    }
+
+    last_run->lastOffset = next_offset;
+
+    /* Find the next block. */
+    next_offset++;
+    hr = StorageImpl_GetNextBlockInChain(This->parentStorage, next_sector, &next_sector);
+    if (FAILED(hr)) return hr;
+  }
+
+  if (This->indexCacheLen)
+  {
+    This->tailIndex = last_run->firstSector + last_run->lastOffset - last_run->firstOffset;
+    This->numBlocks = last_run->lastOffset+1;
+  }
+  else
+  {
+    This->tailIndex = BLOCK_END_OF_CHAIN;
+    This->numBlocks = 0;
+  }
+
+  return S_OK;
+}
+
+/* Locate the nth block in this stream. */
+ULONG BlockChainStream_GetSectorOfOffset(BlockChainStream *This, ULONG offset)
+{
+  ULONG min_offset = 0, max_offset = This->numBlocks-1;
+  ULONG min_run = 0, max_run = This->indexCacheLen-1;
+
+  if (offset >= This->numBlocks)
+    return BLOCK_END_OF_CHAIN;
+
+  while (min_run < max_run)
+  {
+    ULONG run_to_check = min_run + (offset - min_offset) * (max_run - min_run) / (max_offset - min_offset);
+    if (offset < This->indexCache[run_to_check].firstOffset)
+    {
+      max_offset = This->indexCache[run_to_check].firstOffset-1;
+      max_run = run_to_check-1;
+    }
+    else if (offset > This->indexCache[run_to_check].lastOffset)
+    {
+      min_offset = This->indexCache[run_to_check].lastOffset+1;
+      min_run = run_to_check+1;
+    }
+    else
+      /* Block is in this run. */
+      min_run = max_run = run_to_check;
+  }
+
+  return This->indexCache[min_run].firstSector + offset - This->indexCache[min_run].firstOffset;
+}
+
 BlockChainStream* BlockChainStream_Construct(
   StorageImpl* parentStorage,
   ULONG*         headOfStreamPlaceHolder,
   DirRef         dirEntry)
 {
   BlockChainStream* newStream;
-  ULONG blockIndex;
 
   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
 
   newStream->parentStorage           = parentStorage;
   newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
   newStream->ownerDirEntry           = dirEntry;
-  newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
-  newStream->tailIndex               = BLOCK_END_OF_CHAIN;
-  newStream->numBlocks               = 0;
-
-  blockIndex = BlockChainStream_GetHeadOfChain(newStream);
-
-  while (blockIndex != BLOCK_END_OF_CHAIN)
-  {
-    newStream->numBlocks++;
-    newStream->tailIndex = blockIndex;
-
-    if(FAILED(StorageImpl_GetNextBlockInChain(
-	      parentStorage,
-	      blockIndex,
-	      &blockIndex)))
-    {
-      HeapFree(GetProcessHeap(), 0, newStream);
-      return NULL;
-    }
+  newStream->indexCache              = NULL;
+  newStream->indexCacheLen           = 0;
+  newStream->indexCacheSize          = 0;
+
+  if (FAILED(BlockChainStream_UpdateIndexCache(newStream)))
+  {
+    HeapFree(GetProcessHeap(), 0, newStream->indexCache);
+    HeapFree(GetProcessHeap(), 0, newStream);
+    return NULL;
   }
 
   return newStream;
@@ -5065,6 +5760,8 @@
 
 void BlockChainStream_Destroy(BlockChainStream* This)
 {
+  if (This)
+    HeapFree(GetProcessHeap(), 0, This->indexCache);
   HeapFree(GetProcessHeap(), 0, This);
 }
 
@@ -5105,27 +5802,10 @@
  *
  * Returns the number of blocks that comprises this chain.
  * This is not the size of the stream as the last block may not be full!
- *
  */
 static ULONG BlockChainStream_GetCount(BlockChainStream* This)
 {
-  ULONG blockIndex;
-  ULONG count = 0;
-
-  blockIndex = BlockChainStream_GetHeadOfChain(This);
-
-  while (blockIndex != BLOCK_END_OF_CHAIN)
-  {
-    count++;
-
-    if(FAILED(StorageImpl_GetNextBlockInChain(
-                   This->parentStorage,
-                   blockIndex,
-		   &blockIndex)))
-      return 0;
-  }
-
-  return count;
+  return This->numBlocks;
 }
 
 /******************************************************************************
@@ -5146,44 +5826,26 @@
   ULONG bytesToReadInBuffer;
   ULONG blockIndex;
   BYTE* bufferWalker;
+  ULARGE_INTEGER stream_size;
 
   TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
 
   /*
    * Find the first block in the stream that contains part of the buffer.
    */
-  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
-       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
-       (blockNoInSequence < This->lastBlockNoInSequence) )
-  {
-    blockIndex = BlockChainStream_GetHeadOfChain(This);
-    This->lastBlockNoInSequence = blockNoInSequence;
-  }
+  blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
+
+  *bytesRead   = 0;
+
+  stream_size = BlockChainStream_GetSize(This);
+  if (stream_size.QuadPart > offset.QuadPart)
+    size = min(stream_size.QuadPart - offset.QuadPart, size);
   else
-  {
-    ULONG temp = blockNoInSequence;
-
-    blockIndex = This->lastBlockNoInSequenceIndex;
-    blockNoInSequence -= This->lastBlockNoInSequence;
-    This->lastBlockNoInSequence = temp;
-  }
-
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
-  {
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
-      return STG_E_DOCFILECORRUPT;
-    blockNoInSequence--;
-  }
-
-  if ((blockNoInSequence > 0) && (blockIndex == BLOCK_END_OF_CHAIN))
-      return STG_E_DOCFILECORRUPT; /* We failed to find the starting block */
-
-  This->lastBlockNoInSequenceIndex = blockIndex;
+    return S_OK;
 
   /*
    * Start reading the buffer.
    */
-  *bytesRead   = 0;
   bufferWalker = buffer;
 
   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
@@ -5221,7 +5883,7 @@
         break;
   }
 
-  return (size == 0) ? S_OK : STG_E_READFAULT;
+  return S_OK;
 }
 
 /******************************************************************************
@@ -5245,31 +5907,7 @@
   /*
    * Find the first block in the stream that contains part of the buffer.
    */
-  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
-       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
-       (blockNoInSequence < This->lastBlockNoInSequence) )
-  {
-    blockIndex = BlockChainStream_GetHeadOfChain(This);
-    This->lastBlockNoInSequence = blockNoInSequence;
-  }
-  else
-  {
-    ULONG temp = blockNoInSequence;
-
-    blockIndex = This->lastBlockNoInSequenceIndex;
-    blockNoInSequence -= This->lastBlockNoInSequence;
-    This->lastBlockNoInSequence = temp;
-  }
-
-  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
-  {
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
-					      &blockIndex)))
-      return STG_E_DOCFILECORRUPT;
-    blockNoInSequence--;
-  }
-
-  This->lastBlockNoInSequenceIndex = blockIndex;
+  blockIndex = BlockChainStream_GetSectorOfOffset(This, blockNoInSequence);
 
   /* BlockChainStream_SetSize should have already been called to ensure we have
    * enough blocks in the chain to write into */
@@ -5330,15 +5968,8 @@
 static BOOL BlockChainStream_Shrink(BlockChainStream* This,
                                     ULARGE_INTEGER    newSize)
 {
-  ULONG blockIndex, extraBlock;
+  ULONG blockIndex;
   ULONG numBlocks;
-  ULONG count = 1;
-
-  /*
-   * Reset the last accessed block cache.
-   */
-  This->lastBlockNoInSequence = 0xFFFFFFFF;
-  This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
 
   /*
    * Figure out how many blocks are needed to contain the new size
@@ -5348,43 +5979,62 @@
   if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0)
     numBlocks++;
 
-  blockIndex = BlockChainStream_GetHeadOfChain(This);
-
-  /*
-   * Go to the new end of chain
-   */
-  while (count < numBlocks)
-  {
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
-					      &blockIndex)))
-      return FALSE;
-    count++;
-  }
-
-  /* Get the next block before marking the new end */
-  if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
-					    &extraBlock)))
-    return FALSE;
-
-  /* Mark the new end of chain */
-  StorageImpl_SetNextBlockInChain(
-    This->parentStorage,
-    blockIndex,
-    BLOCK_END_OF_CHAIN);
-
-  This->tailIndex = blockIndex;
+  if (numBlocks)
+  {
+    /*
+     * Go to the new end of chain
+     */
+    blockIndex = BlockChainStream_GetSectorOfOffset(This, numBlocks-1);
+
+    /* Mark the new end of chain */
+    StorageImpl_SetNextBlockInChain(
+      This->parentStorage,
+      blockIndex,
+      BLOCK_END_OF_CHAIN);
+
+    This->tailIndex = blockIndex;
+  }
+  else
+  {
+    if (This->headOfStreamPlaceHolder != 0)
+    {
+      *This->headOfStreamPlaceHolder = BLOCK_END_OF_CHAIN;
+    }
+    else
+    {
+      DirEntry chainEntry;
+      assert(This->ownerDirEntry != DIRENTRY_NULL);
+
+      StorageImpl_ReadDirEntry(
+        This->parentStorage,
+        This->ownerDirEntry,
+        &chainEntry);
+
+      chainEntry.startingBlock = BLOCK_END_OF_CHAIN;
+
+      StorageImpl_WriteDirEntry(
+        This->parentStorage,
+        This->ownerDirEntry,
+        &chainEntry);
+    }
+
+    This->tailIndex = BLOCK_END_OF_CHAIN;
+  }
+
   This->numBlocks = numBlocks;
 
   /*
    * Mark the extra blocks as free
    */
-  while (extraBlock != BLOCK_END_OF_CHAIN)
-  {
-    if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock,
-					      &blockIndex)))
-      return FALSE;
-    StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
-    extraBlock = blockIndex;
+  while (This->indexCacheLen && This->indexCache[This->indexCacheLen-1].lastOffset >= numBlocks)
+  {
+    struct BlockChainRun *last_run = &This->indexCache[This->indexCacheLen-1];
+    StorageImpl_FreeBigBlock(This->parentStorage,
+      last_run->firstSector + last_run->lastOffset - last_run->firstOffset);
+    if (last_run->lastOffset == last_run->firstOffset)
+      This->indexCacheLen--;
+    else
+      last_run->lastOffset--;
   }
 
   return TRUE;
@@ -5497,6 +6147,9 @@
     This->tailIndex = blockIndex;
     This->numBlocks = newNumBlocks;
   }
+
+  if (FAILED(BlockChainStream_UpdateIndexCache(This)))
+    return FALSE;
 
   return TRUE;
 }
@@ -5663,6 +6316,9 @@
               &buffer,
               &bytesRead);
 
+  if (SUCCEEDED(res) && bytesRead != sizeof(DWORD))
+    res = STG_E_READFAULT;
+
   if (SUCCEEDED(res))
   {
     StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain);
@@ -5734,6 +6390,9 @@
   ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
   HRESULT res = S_OK;
   ULONG smallBlocksPerBigBlock;
+  DirEntry rootEntry;
+  ULONG blocksRequired;
+  ULARGE_INTEGER old_size, size_required;
 
   offsetOfBlockInDepot.u.HighPart = 0;
 
@@ -5754,7 +6413,7 @@
     /*
      * If we run out of space for the small block depot, enlarge it
      */
-    if (SUCCEEDED(res))
+    if (SUCCEEDED(res) && bytesRead == sizeof(DWORD))
     {
       StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex);
 
@@ -5766,76 +6425,22 @@
       ULONG count =
         BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
 
-      ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
-      ULONG nextBlock, newsbdIndex;
       BYTE smallBlockDepot[MAX_BIG_BLOCK_SIZE];
-
-      nextBlock = sbdIndex;
-      while (nextBlock != BLOCK_END_OF_CHAIN)
-      {
-        sbdIndex = nextBlock;
-	StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock);
-      }
-
-      newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
-      if (sbdIndex != BLOCK_END_OF_CHAIN)
-        StorageImpl_SetNextBlockInChain(
-          This->parentStorage,
-          sbdIndex,
-          newsbdIndex);
-
-      StorageImpl_SetNextBlockInChain(
-        This->parentStorage,
-        newsbdIndex,
-        BLOCK_END_OF_CHAIN);
+      ULARGE_INTEGER newSize, offset;
+      ULONG bytesWritten;
+
+      newSize.QuadPart = (count + 1) * This->parentStorage->bigBlockSize;
+      BlockChainStream_Enlarge(This->parentStorage->smallBlockDepotChain, newSize);
 
       /*
        * Initialize all the small blocks to free
        */
       memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
-      StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot);
-
-      if (count == 0)
-      {
-        /*
-         * We have just created the small block depot.
-         */
-        DirEntry rootEntry;
-        ULONG sbStartIndex;
-
-        /*
-         * Save it in the header
-         */
-        This->parentStorage->smallBlockDepotStart = newsbdIndex;
-        StorageImpl_SaveFileHeader(This->parentStorage);
-
-        /*
-         * And allocate the first big block that will contain small blocks
-         */
-        sbStartIndex =
-          StorageImpl_GetNextFreeBigBlock(This->parentStorage);
-
-        StorageImpl_SetNextBlockInChain(
-          This->parentStorage,
-          sbStartIndex,
-          BLOCK_END_OF_CHAIN);
-
-        StorageImpl_ReadDirEntry(
-          This->parentStorage,
-          This->parentStorage->base.storageDirEntry,
-          &rootEntry);
-
-        rootEntry.startingBlock = sbStartIndex;
-        rootEntry.size.u.HighPart = 0;
-        rootEntry.size.u.LowPart  = This->parentStorage->bigBlockSize;
-
-        StorageImpl_WriteDirEntry(
-          This->parentStorage,
-          This->parentStorage->base.storageDirEntry,
-          &rootEntry);
-      }
-      else
-        StorageImpl_SaveFileHeader(This->parentStorage);
+      offset.QuadPart = count * This->parentStorage->bigBlockSize;
+      BlockChainStream_WriteAt(This->parentStorage->smallBlockDepotChain,
+        offset, This->parentStorage->bigBlockSize, smallBlockDepot, &bytesWritten);
+
+      StorageImpl_SaveFileHeader(This->parentStorage);
     }
   }
 
@@ -5847,30 +6452,29 @@
   /*
    * Verify if we have to allocate big blocks to contain small blocks
    */
-  if (blockIndex % smallBlocksPerBigBlock == 0)
-  {
-    DirEntry rootEntry;
-    ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
+  blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
+
+  size_required.QuadPart = blocksRequired * This->parentStorage->bigBlockSize;
+
+  old_size = BlockChainStream_GetSize(This->parentStorage->smallBlockRootChain);
+
+  if (size_required.QuadPart > old_size.QuadPart)
+  {
+    BlockChainStream_SetSize(
+      This->parentStorage->smallBlockRootChain,
+      size_required);
 
     StorageImpl_ReadDirEntry(
       This->parentStorage,
       This->parentStorage->base.storageDirEntry,
       &rootEntry);
 
-    if (rootEntry.size.u.LowPart <
-       (blocksRequired * This->parentStorage->bigBlockSize))
-    {
-      rootEntry.size.u.LowPart += This->parentStorage->bigBlockSize;
-
-      BlockChainStream_SetSize(
-        This->parentStorage->smallBlockRootChain,
-        rootEntry.size);
-
-      StorageImpl_WriteDirEntry(
-        This->parentStorage,
-        This->parentStorage->base.storageDirEntry,
-        &rootEntry);
-    }
+    rootEntry.size = size_required;
+
+    StorageImpl_WriteDirEntry(
+      This->parentStorage,
+      This->parentStorage->base.storageDirEntry,
+      &rootEntry);
   }
 
   return blockIndex;
@@ -5900,11 +6504,20 @@
   ULONG blockIndex;
   ULONG bytesReadFromBigBlockFile;
   BYTE* bufferWalker;
+  ULARGE_INTEGER stream_size;
 
   /*
    * This should never happen on a small block file.
    */
   assert(offset.u.HighPart==0);
+
+  *bytesRead   = 0;
+
+  stream_size = SmallBlockChainStream_GetSize(This);
+  if (stream_size.QuadPart > offset.QuadPart)
+    size = min(stream_size.QuadPart - offset.QuadPart, size);
+  else
+    return S_OK;
 
   /*
    * Find the first block in the stream that contains part of the buffer.
@@ -5922,7 +6535,6 @@
   /*
    * Start reading the buffer.
    */
-  *bytesRead   = 0;
   bufferWalker = buffer;
 
   while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
@@ -5956,6 +6568,9 @@
     if (FAILED(rc))
       return rc;
 
+    if (!bytesReadFromBigBlockFile)
+      return STG_E_DOCFILECORRUPT;
+
     /*
      * Step to the next big block.
      */
@@ -5969,7 +6584,7 @@
     offsetInBlock = (offsetInBlock + bytesReadFromBigBlockFile) % This->parentStorage->smallBlockSize;
   }
 
-  return (size == 0) ? S_OK : STG_E_READFAULT;
+  return S_OK;
 }
 
 /******************************************************************************

Modified: trunk/reactos/dll/win32/ole32/storage32.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/storage32.h?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/storage32.h [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/storage32.h [iso-8859-1] Sat May 29 13:34:57 2010
@@ -263,6 +263,7 @@
   HRESULT (*StreamReadAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,void*,ULONG*);
   HRESULT (*StreamWriteAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,const void*,ULONG*);
   HRESULT (*StreamSetSize)(StorageBaseImpl*,DirRef,ULARGE_INTEGER);
+  HRESULT (*StreamLink)(StorageBaseImpl*,DirRef,DirRef);
 };
 
 static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This)
@@ -318,6 +319,16 @@
   DirRef index, ULARGE_INTEGER newsize)
 {
   return This->baseVtbl->StreamSetSize(This, index, newsize);
+}
+
+/* Make dst point to the same stream that src points to. Other stream operations
+ * will not work properly for entries that point to the same stream, so this
+ * must be a very temporary state, and only one entry pointing to a given stream
+ * may be reachable at any given time. */
+static inline HRESULT StorageBaseImpl_StreamLink(StorageBaseImpl *This,
+  DirRef dst, DirRef src)
+{
+  return This->baseVtbl->StreamLink(This, dst, src);
 }
 
 /****************************************************************************
@@ -513,13 +524,22 @@
  * The BlockChainStream class is a utility class that is used to create an
  * abstraction of the big block chains in the storage file.
  */
+struct BlockChainRun
+{
+  /* This represents a range of blocks that happen reside in consecutive sectors. */
+  ULONG firstSector;
+  ULONG firstOffset;
+  ULONG lastOffset;
+};
+
 struct BlockChainStream
 {
   StorageImpl* parentStorage;
   ULONG*       headOfStreamPlaceHolder;
   DirRef       ownerDirEntry;
-  ULONG        lastBlockNoInSequence;
-  ULONG        lastBlockNoInSequenceIndex;
+  struct BlockChainRun* indexCache;
+  ULONG        indexCacheLen;
+  ULONG        indexCacheSize;
   ULONG        tailIndex;
   ULONG        numBlocks;
 };

Modified: trunk/reactos/dll/win32/ole32/usrmarshal.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ole32/usrmarshal.c?rev=47405&r1=47404&r2=47405&view=diff
==============================================================================
--- trunk/reactos/dll/win32/ole32/usrmarshal.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/ole32/usrmarshal.c [iso-8859-1] Sat May 29 13:34:57 2010
@@ -2761,7 +2761,8 @@
     FORMATETC *pFormatetc,
     STGMEDIUM *pStgmed)
 {
-    FIXME(":stub\n");
+    TRACE("(%p)->(%p, %p)\n", This, pFormatetc, pStgmed);
+    IAdviseSink_RemoteOnDataChange_Proxy(This, pFormatetc, pStgmed);
 }
 
 HRESULT __RPC_STUB IAdviseSink_OnDataChange_Stub(
@@ -2769,8 +2770,9 @@
     FORMATETC *pFormatetc,
     ASYNC_STGMEDIUM *pStgmed)
 {
-    FIXME(":stub\n");
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p, %p)\n", This, pFormatetc, pStgmed);
+    IAdviseSink_OnDataChange(This, pFormatetc, pStgmed);
+    return S_OK;
 }
 
 void CALLBACK IAdviseSink_OnViewChange_Proxy(
@@ -2778,7 +2780,8 @@
     DWORD dwAspect,
     LONG lindex)
 {
-    FIXME(":stub\n");
+    TRACE("(%p)->(%d, %d)\n", This, dwAspect, lindex);
+    IAdviseSink_RemoteOnViewChange_Proxy(This, dwAspect, lindex);
 }
 
 HRESULT __RPC_STUB IAdviseSink_OnViewChange_Stub(
@@ -2786,64 +2789,73 @@
     DWORD dwAspect,
     LONG lindex)
 {
-    FIXME(":stub\n");
-    return E_NOTIMPL;
+    TRACE("(%p)->(%d, %d)\n", This, dwAspect, lindex);
+    IAdviseSink_OnViewChange(This, dwAspect, lindex);
+    return S_OK;
 }
 
 void CALLBACK IAdviseSink_OnRename_Proxy(
     IAdviseSink* This,
     IMoniker *pmk)
 {
-    FIXME(":stub\n");
+    TRACE("(%p)->(%p)\n", This, pmk);
+    IAdviseSink_RemoteOnRename_Proxy(This, pmk);
 }
 
 HRESULT __RPC_STUB IAdviseSink_OnRename_Stub(
     IAdviseSink* This,
     IMoniker *pmk)
 {
-    FIXME(":stub\n");
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, pmk);
+    IAdviseSink_OnRename(This, pmk);
+    return S_OK;
 }
 
 void CALLBACK IAdviseSink_OnSave_Proxy(
     IAdviseSink* This)
 {
-    FIXME(":stub\n");
+    TRACE("(%p)\n", This);
+    IAdviseSink_RemoteOnSave_Proxy(This);
 }
 
 HRESULT __RPC_STUB IAdviseSink_OnSave_Stub(
     IAdviseSink* This)
 {
-    FIXME(":stub\n");
-    return E_NOTIMPL;
+    TRACE("(%p)\n", This);
+    IAdviseSink_OnSave(This);
+    return S_OK;
 }
 
 void CALLBACK IAdviseSink_OnClose_Proxy(
     IAdviseSink* This)
 {
-    FIXME(":stub\n");
+    TRACE("(%p)\n", This);
+    IAdviseSink_RemoteOnClose_Proxy(This);
 }
 
 HRESULT __RPC_STUB IAdviseSink_OnClose_Stub(
     IAdviseSink* This)
 {
-    FIXME(":stub\n");
-    return E_NOTIMPL;
+    TRACE("(%p)\n", This);
+    IAdviseSink_OnClose(This);
+    return S_OK;
 }
 
 void CALLBACK IAdviseSink2_OnLinkSrcChange_Proxy(
     IAdviseSink2* This,
     IMoniker *pmk)
 {
-    FIXME(":stub\n");
+    TRACE("(%p)->(%p)\n", This, pmk);
+    IAdviseSink2_RemoteOnLinkSrcChange_Proxy(This, pmk);
 }
 
 HRESULT __RPC_STUB IAdviseSink2_OnLinkSrcChange_Stub(
     IAdviseSink2* This,
     IMoniker *pmk)
 {
-    FIXME(":stub\n");
-    return E_NOTIMPL;
+    TRACE("(%p)->(%p)\n", This, pmk);
+    IAdviseSink2_OnLinkSrcChange(This, pmk);
+    return S_OK;
 }
 
 HRESULT CALLBACK IDataObject_GetData_Proxy(




More information about the Ros-diffs mailing list