Author: akhaldi
Date: Fri Oct  3 11:44:48 2014
New Revision: 64492

URL: http://svn.reactos.org/svn/reactos?rev=64492&view=rev
Log:
[OLE32_WINETEST]
* Sync with Wine 1.7.27.
CORE-8540

Modified:
    trunk/rostests/winetests/ole32/compobj.c
    trunk/rostests/winetests/ole32/hglobalstream.c
    trunk/rostests/winetests/ole32/propvariant.c
    trunk/rostests/winetests/ole32/storage32.c

Modified: trunk/rostests/winetests/ole32/compobj.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/compobj.c?rev=64492&r1=64491&r2=64492&view=diff
==============================================================================
--- trunk/rostests/winetests/ole32/compobj.c    [iso-8859-1] (original)
+++ trunk/rostests/winetests/ole32/compobj.c    [iso-8859-1] Fri Oct  3 
11:44:48 2014
@@ -50,12 +50,15 @@
 static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv);
 static HRESULT (WINAPI * pCoSwitchCallContext)(IUnknown *pObject, IUnknown 
**ppOldObject);
 static HRESULT (WINAPI * pCoGetTreatAsClass)(REFCLSID clsidOld, LPCLSID 
pClsidNew);
+static HRESULT (WINAPI * pCoTreatAsClass)(REFCLSID clsidOld, REFCLSID 
pClsidNew);
 static HRESULT (WINAPI * pCoGetContextToken)(ULONG_PTR *token);
+static LONG (WINAPI * pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
 static LONG (WINAPI * pRegOverridePredefKey)(HKEY key, HKEY override);
 
 static BOOL   (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
 static BOOL   (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
+static BOOL   (WINAPI *pIsWow64Process)(HANDLE, LPBOOL);
 static void   (WINAPI *pReleaseActCtx)(HANDLE);
 
 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 
0x%08x\n", hr)
@@ -1057,6 +1060,8 @@
     CLSID clsid;
     HKEY hkey;
     LONG res;
+    const BOOL is_win64 = (sizeof(void*) != sizeof(int));
+    BOOL is_wow64 = FALSE;
 
     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
     ok(hr == CO_E_NOTINITIALIZED,
@@ -1138,6 +1143,43 @@
 
         pDeactivateActCtx(0, cookie);
         pReleaseActCtx(handle);
+    }
+
+    if (pRegDeleteKeyExA &&
+        (is_win64 ||
+         (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &is_wow64) 
&& is_wow64)))
+    {
+        static GUID IID_DeadBeef = 
{0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
+        static const char clsidDeadBeef[] = 
"{deadbeef-dead-beef-dead-beefdeadbeef}";
+        static const char clsidA[] = "{66666666-8888-7777-6666-555555555555}";
+        HKEY hkey_iface, hkey_psclsid;
+        REGSAM opposite = is_win64 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
+
+        hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
+        ok(hr == REGDB_E_IIDNOTREG, "got 0x%08x\n", hr);
+
+        res = RegCreateKeyExA(HKEY_CLASSES_ROOT, "Interface",
+                              0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, 
&hkey_iface, NULL);
+        ok(!res, "RegCreateKeyEx returned %d\n", res);
+        res = RegCreateKeyExA(hkey_iface, clsidDeadBeef,
+                              0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, 
&hkey, NULL);
+        ok(!res, "RegCreateKeyEx returned %d\n", res);
+        res = RegCreateKeyExA(hkey, "ProxyStubClsid32",
+                              0, NULL, 0, KEY_ALL_ACCESS | opposite, NULL, 
&hkey_psclsid, NULL);
+        res = RegSetValueExA(hkey_psclsid, NULL, 0, REG_SZ, (const BYTE 
*)clsidA, strlen(clsidA)+1);
+        ok(!res, "RegSetValueEx returned %d\n", res);
+        RegCloseKey(hkey_psclsid);
+
+        hr = CoGetPSClsid(&IID_DeadBeef, &clsid);
+        ok_ole_success(hr, "CoGetPSClsid");
+        ok(IsEqualGUID(&clsid, &IID_TestPS), "got clsid %s\n", 
wine_dbgstr_guid(&clsid));
+
+        res = pRegDeleteKeyExA(hkey, "ProxyStubClsid32", opposite, 0);
+        ok(!res, "RegDeleteKeyEx returned %d\n", res);
+        RegCloseKey(hkey);
+        res = pRegDeleteKeyExA(hkey_iface, clsidDeadBeef, opposite, 0);
+        ok(!res, "RegDeleteKeyEx returned %d\n", res);
+        RegCloseKey(hkey_iface);
     }
 
     CoUninitialize();
@@ -1905,11 +1947,15 @@
     CoUninitialize();
 }
 
-static void test_CoGetTreatAsClass(void)
+static void test_TreatAsClass(void)
 {
     HRESULT hr;
     CLSID out;
     static GUID deadbeef = 
{0xdeadbeef,0xdead,0xbeef,{0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef}};
+    static const char deadbeefA[] = "{DEADBEEF-DEAD-BEEF-DEAD-BEEFDEADBEEF}";
+    IInternetProtocol *pIP = NULL;
+    HKEY clsidkey, deadbeefkey;
+    LONG lr;
 
     if (!pCoGetTreatAsClass)
     {
@@ -1919,6 +1965,63 @@
     hr = pCoGetTreatAsClass(&deadbeef,&out);
     ok (hr == S_FALSE, "expected S_FALSE got %x\n",hr);
     ok (IsEqualGUID(&out,&deadbeef), "expected to get same clsid back\n");
+
+    lr = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &clsidkey);
+    ok(lr == ERROR_SUCCESS, "Couldn't open CLSID key\n");
+
+    lr = RegCreateKeyExA(clsidkey, deadbeefA, 0, NULL, 0, KEY_WRITE, NULL, 
&deadbeefkey, NULL);
+    ok(lr == ERROR_SUCCESS, "Couldn't create class key\n");
+
+    hr = pCoTreatAsClass(&deadbeef, &deadbeef);
+    ok(hr == REGDB_E_WRITEREGDB, "CoTreatAsClass gave wrong error: %08x\n", 
hr);
+
+    hr = pCoTreatAsClass(&deadbeef, &CLSID_FileProtocol);
+    if(hr == REGDB_E_WRITEREGDB){
+        win_skip("Insufficient privileges to use CoTreatAsClass\n");
+        goto exit;
+    }
+    ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
+
+    hr = pCoGetTreatAsClass(&deadbeef, &out);
+    ok(hr == S_OK, "CoGetTreatAsClass failed: %08x\n",hr);
+    ok(IsEqualGUID(&out, &CLSID_FileProtocol), "expected to get substituted 
clsid\n");
+
+    OleInitialize(NULL);
+
+    hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, 
&IID_IInternetProtocol, (void **)&pIP);
+    if(hr == REGDB_E_CLASSNOTREG)
+    {
+        win_skip("IE not installed so can't test CoCreateInstance\n");
+        goto exit;
+    }
+
+    ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
+    if(pIP){
+        IInternetProtocol_Release(pIP);
+        pIP = NULL;
+    }
+
+    hr = pCoTreatAsClass(&deadbeef, &CLSID_NULL);
+    ok(hr == S_OK, "CoTreatAsClass failed: %08x\n", hr);
+
+    hr = pCoGetTreatAsClass(&deadbeef, &out);
+    ok(hr == S_FALSE, "expected S_FALSE got %08x\n", hr);
+    ok(IsEqualGUID(&out, &deadbeef), "expected to get same clsid back\n");
+
+    /* bizarrely, native's CoTreatAsClass takes some time to take effect in 
CoCreateInstance */
+    Sleep(200);
+
+    hr = CoCreateInstance(&deadbeef, NULL, CLSCTX_INPROC_SERVER, 
&IID_IInternetProtocol, (void **)&pIP);
+    ok(hr == REGDB_E_CLASSNOTREG, "CoCreateInstance gave wrong error: %08x\n", 
hr);
+
+    if(pIP)
+        IInternetProtocol_Release(pIP);
+
+exit:
+    OleUninitialize();
+    RegCloseKey(deadbeefkey);
+    RegDeleteKeyA(clsidkey, deadbeefA);
+    RegCloseKey(clsidkey);
 }
 
 static void test_CoInitializeEx(void)
@@ -1986,6 +2089,14 @@
     }
 }
 
+static void test_CoCreateGuid(void)
+{
+    HRESULT hr;
+
+    hr = CoCreateGuid(NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+}
+
 static void init_funcs(void)
 {
     HMODULE hOle32 = GetModuleHandleA("ole32");
@@ -1995,13 +2106,16 @@
     pCoGetObjectContext = (void*)GetProcAddress(hOle32, "CoGetObjectContext");
     pCoSwitchCallContext = (void*)GetProcAddress(hOle32, 
"CoSwitchCallContext");
     pCoGetTreatAsClass = (void*)GetProcAddress(hOle32,"CoGetTreatAsClass");
+    pCoTreatAsClass = (void*)GetProcAddress(hOle32,"CoTreatAsClass");
     pCoGetContextToken = (void*)GetProcAddress(hOle32, "CoGetContextToken");
+    pRegDeleteKeyExA = (void*)GetProcAddress(hAdvapi32, "RegDeleteKeyExA");
     pRegOverridePredefKey = (void*)GetProcAddress(hAdvapi32, 
"RegOverridePredefKey");
     pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
 
     pActivateActCtx = (void*)GetProcAddress(hkernel32, "ActivateActCtx");
     pCreateActCtxW = (void*)GetProcAddress(hkernel32, "CreateActCtxW");
     pDeactivateActCtx = (void*)GetProcAddress(hkernel32, "DeactivateActCtx");
+    pIsWow64Process = (void*)GetProcAddress(hkernel32, "IsWow64Process");
     pReleaseActCtx = (void*)GetProcAddress(hkernel32, "ReleaseActCtx");
 }
 
@@ -2039,7 +2153,8 @@
     test_CoGetObjectContext();
     test_CoGetCallContext();
     test_CoGetContextToken();
-    test_CoGetTreatAsClass();
+    test_TreatAsClass();
     test_CoInitializeEx();
     test_OleRegGetMiscStatus();
-}
+    test_CoCreateGuid();
+}

Modified: trunk/rostests/winetests/ole32/hglobalstream.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/hglobalstream.c?rev=64492&r1=64491&r2=64492&view=diff
==============================================================================
--- trunk/rostests/winetests/ole32/hglobalstream.c      [iso-8859-1] (original)
+++ trunk/rostests/winetests/ole32/hglobalstream.c      [iso-8859-1] Fri Oct  3 
11:44:48 2014
@@ -266,14 +266,17 @@
     ok(ull.u.LowPart == 0x80000008, "should have set LowPart to 0x80000008 
instead of %08x\n", ull.u.LowPart);
     ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", 
ull.u.HighPart);
 
-    /* IStream_Seek -- seek wraps position/size on integer overflow */
+    /* IStream_Seek -- seek wraps position/size on integer overflow, but not 
on win8 */
     ull.u.HighPart = 0xCAFECAFE;
     ull.u.LowPart = 0xCAFECAFE;
     ll.u.HighPart = 0;
     ll.u.LowPart = 0x7FFFFFFF;
     hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
-    ok_ole_success(hr, "IStream_Seek");
-    ok(ull.u.LowPart == 0x00000007, "should have set LowPart to 0x00000007 
instead of %08x\n", ull.u.LowPart);
+    ok(hr == S_OK || hr == STG_E_SEEKERROR /* win8 */, "IStream_Seek\n");
+    if (SUCCEEDED(hr))
+        ok(ull.u.LowPart == 0x00000007, "should have set LowPart to 0x00000007 
instead of %08x\n", ull.u.LowPart);
+    else
+        ok(ull.u.LowPart == 0x80000008, "should have set LowPart to 0x80000008 
instead of %08x\n", ull.u.LowPart);
     ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", 
ull.u.HighPart);
 
     hr = IStream_Commit(pStream, STGC_DEFAULT);

Modified: trunk/rostests/winetests/ole32/propvariant.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/propvariant.c?rev=64492&r1=64491&r2=64492&view=diff
==============================================================================
--- trunk/rostests/winetests/ole32/propvariant.c        [iso-8859-1] (original)
+++ trunk/rostests/winetests/ole32/propvariant.c        [iso-8859-1] Fri Oct  3 
11:44:48 2014
@@ -61,11 +61,11 @@
     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* 
VT_CY */
     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* 
VT_DATE */
     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* 
VT_BSTR */
-    { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | 
PROP_TODO  }, /* VT_DISPATCH */
+    { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* 
VT_DISPATCH */
     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* 
VT_ERROR */
     { PROP_V0 , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | PROP_TODO  }, /* 
VT_BOOL */
     { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_V0 , PROP_V1 | 
PROP_TODO  }, /* VT_VARIANT */
-    { PROP_V1 | PROP_TODO , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | 
PROP_TODO  }, /* VT_UNKNOWN */
+    { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* 
VT_UNKNOWN */
     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_INV, PROP_V1 | PROP_TODO  }, /* 
VT_DECIMAL */
     { PROP_INV, PROP_INV, PROP_INV, PROP_INV }, /* 15 */
     { PROP_V1 , PROP_V1 | PROP_TODO , PROP_V1 , PROP_V1 | PROP_TODO  }, /* 
VT_I1 */

Modified: trunk/rostests/winetests/ole32/storage32.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/ole32/storage32.c?rev=64492&r1=64491&r2=64492&view=diff
==============================================================================
--- trunk/rostests/winetests/ole32/storage32.c  [iso-8859-1] (original)
+++ trunk/rostests/winetests/ole32/storage32.c  [iso-8859-1] Fri Oct  3 
11:44:48 2014
@@ -25,6 +25,8 @@
 //#include <stdio.h>
 
 #define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
 
 //#include <windows.h>
 #include <wine/test.h>
@@ -870,11 +872,9 @@
     r = StgOpenStorage( filename, NULL, STGM_PRIORITY, NULL, 0, &stgprio);
     ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
 
-    todo_wine {
     /* non-transacted mode read/write fails */
     r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 
NULL, 0, &stg);
     ok(r==STG_E_LOCKVIOLATION, "StgOpenStorage should return 
STG_E_LOCKVIOLATION instead of 0x%08x\n", r);
-    }
 
     /* non-transacted mode read-only succeeds */
     r = StgOpenStorage( filename, NULL, STGM_SHARE_DENY_WRITE|STGM_READ, NULL, 
0, &stg);
@@ -3144,6 +3144,506 @@
     }
 
     DeleteFileW(fileW);
+}
+
+struct lock_test
+{
+    DWORD stg_mode;
+    BOOL create;
+    DWORD access;
+    DWORD sharing;
+    const int *locked_bytes;
+    const int *fail_ranges;
+    BOOL todo;
+};
+
+static const int priority_locked_bytes[] = { 0x58, 0x81, 0x93, -1 };
+static const int rwex_locked_bytes[] = { 0x93, 0xa7, 0xbb, 0xcf, -1 };
+static const int rw_locked_bytes[] = { 0x93, 0xa7, -1 };
+static const int nosn_locked_bytes[] = { 0x6c, 0x93, 0xa7, 0xcf, -1 };
+static const int rwdw_locked_bytes[] = { 0x93, 0xa7, 0xcf, -1 };
+static const int wodw_locked_bytes[] = { 0xa7, 0xcf, -1 };
+static const int tr_locked_bytes[] = { 0x93, -1 };
+static const int no_locked_bytes[] = { -1 };
+static const int roex_locked_bytes[] = { 0x93, 0xbb, 0xcf, -1 };
+
+static const int rwex_fail_ranges[] = { 0x93,0xe3, -1 };
+static const int rw_fail_ranges[] = { 0xbb,0xe3, -1 };
+static const int rwdw_fail_ranges[] = { 0xa7,0xe3, -1 };
+static const int dw_fail_ranges[] = { 0xa7,0xcf, -1 };
+static const int tr_fail_ranges[] = { 0xbb,0xcf, -1 };
+static const int pr_fail_ranges[] = { 0x80,0x81, 0xbb,0xcf, -1 };
+static const int roex_fail_ranges[] = { 0x0,-1 };
+
+static const struct lock_test lock_tests[] = {
+    { STGM_PRIORITY, FALSE, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 
priority_locked_bytes, pr_fail_ranges, FALSE },
+    { STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, TRUE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 0, FALSE },
+    { STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE|STGM_TRANSACTED, TRUE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 0, FALSE },
+    { STGM_CREATE|STGM_READWRITE|STGM_TRANSACTED, TRUE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, rw_locked_bytes, 
0, FALSE },
+    { STGM_CREATE|STGM_READWRITE|STGM_SHARE_DENY_WRITE|STGM_TRANSACTED, TRUE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwdw_locked_bytes, 0, FALSE },
+    { STGM_CREATE|STGM_WRITE|STGM_SHARE_DENY_WRITE|STGM_TRANSACTED, TRUE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, wodw_locked_bytes, 0, FALSE },
+    { STGM_SHARE_EXCLUSIVE|STGM_READWRITE, FALSE, GENERIC_READ|GENERIC_WRITE, 
FILE_SHARE_READ, rwex_locked_bytes, rwex_fail_ranges, FALSE },
+    { STGM_SHARE_EXCLUSIVE|STGM_READWRITE|STGM_TRANSACTED, FALSE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwex_locked_bytes, 
rwex_fail_ranges, FALSE },
+    { STGM_READWRITE|STGM_TRANSACTED, FALSE, GENERIC_READ|GENERIC_WRITE, 
FILE_SHARE_READ|FILE_SHARE_WRITE, rw_locked_bytes, rw_fail_ranges, FALSE },
+    { STGM_READWRITE|STGM_TRANSACTED|STGM_NOSNAPSHOT, FALSE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 
nosn_locked_bytes, rwdw_fail_ranges, FALSE },
+    { STGM_READWRITE|STGM_TRANSACTED|STGM_SHARE_DENY_WRITE, FALSE, 
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, rwdw_locked_bytes, 
rwdw_fail_ranges, FALSE },
+    { STGM_READ|STGM_SHARE_DENY_WRITE, FALSE, GENERIC_READ, FILE_SHARE_READ, 
no_locked_bytes, dw_fail_ranges, TRUE },
+    { STGM_READ|STGM_TRANSACTED, FALSE, GENERIC_READ, 
FILE_SHARE_READ|FILE_SHARE_WRITE, tr_locked_bytes, tr_fail_ranges, FALSE },
+    { STGM_READ|STGM_SHARE_EXCLUSIVE, FALSE, GENERIC_READ, FILE_SHARE_READ, 
roex_locked_bytes, roex_fail_ranges, TRUE },
+    { STGM_READ|STGM_SHARE_EXCLUSIVE|STGM_TRANSACTED, FALSE, GENERIC_READ, 
FILE_SHARE_READ, roex_locked_bytes, roex_fail_ranges, TRUE },
+};
+
+static BOOL can_open(LPCWSTR filename, DWORD access, DWORD sharing)
+{
+    HANDLE hfile;
+
+    hfile = CreateFileW(filename, access, sharing, NULL, OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL, NULL);
+
+    if (hfile == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    CloseHandle(hfile);
+    return TRUE;
+}
+
+static void check_sharing(LPCWSTR filename, const struct lock_test *current,
+    DWORD access, DWORD sharing, const char *desc, DWORD *open_mode, BOOL 
*any_failure)
+{
+    if (can_open(filename, access, 
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE))
+    {
+        *open_mode = access;
+        if (!current->todo || (current->sharing & sharing))
+            ok(current->sharing & sharing ||
+                broken(!(current->sharing & sharing) && access == 
GENERIC_WRITE && (current->stg_mode & 0xf) != STGM_READ) /* win2k */,
+                "file with mode %x should not be openable with %s 
permission\n", current->stg_mode, desc);
+        else
+        {
+            todo_wine ok(current->sharing & sharing ||
+                broken(!(current->sharing & sharing) && access == 
GENERIC_WRITE && (current->stg_mode & 0xf) != STGM_READ) /* win2k */,
+                "file with mode %x should not be openable with %s 
permission\n", current->stg_mode, desc);
+            *any_failure = TRUE;
+        }
+    }
+    else
+    {
+        if (!current->todo || !(current->sharing & sharing))
+            ok(!(current->sharing & sharing), "file with mode %x should be 
openable with %s permission\n", current->stg_mode, desc);
+        else
+        {
+            todo_wine ok(!(current->sharing & sharing), "file with mode %x 
should be openable with %s permission\n", current->stg_mode, desc);
+            *any_failure = TRUE;
+        }
+    }
+}
+
+static void check_access(LPCWSTR filename, const struct lock_test *current,
+    DWORD access, DWORD sharing, const char *desc, DWORD open_mode, BOOL 
*any_failure)
+{
+    if (can_open(filename, open_mode, 
(FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE) & ~sharing))
+    {
+        if (!current->todo || !(current->access & access))
+            ok(!(current->access & access), "file with mode %x should not be 
openable without %s sharing\n", current->stg_mode, desc);
+        else
+        {
+            todo_wine ok(!(current->access & access), "file with mode %x 
should not be openable without %s sharing\n", current->stg_mode, desc);
+            *any_failure = TRUE;
+        }
+    }
+    else
+    {
+        if (!current->todo || (current->access & access))
+            ok(current->access & access, "file with mode %x should be openable 
without %s sharing\n", current->stg_mode, desc);
+        else
+        {
+            todo_wine ok(current->access & access, "file with mode %x should 
be openable without %s sharing\n", current->stg_mode, desc);
+            *any_failure = TRUE;
+        }
+    }
+}
+
+static void test_locking(void)
+{
+    static const WCHAR filename[] = {'w','i','n','e','t','e','s','t',0};
+    int i;
+    IStorage *stg;
+    HRESULT hr;
+
+    for (i=0; i<sizeof(lock_tests)/sizeof(lock_tests[0]); i++)
+    {
+        const struct lock_test *current = &lock_tests[i];
+        BOOL any_failure = FALSE;
+        DWORD open_mode = 0;
+
+        if (current->create)
+        {
+            hr = StgCreateDocfile(filename, current->stg_mode, 0, &stg);
+            ok(SUCCEEDED(hr), "StgCreateDocfile with mode %x failed with hr 
%x\n", current->stg_mode, hr);
+            if (FAILED(hr)) continue;
+        }
+        else
+        {
+            hr = StgCreateDocfile(filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE 
| STGM_READWRITE, 0, &stg);
+            ok(SUCCEEDED(hr), "StgCreateDocfile failed with hr %x\n", hr);
+            if (FAILED(hr)) continue;
+            IStorage_Release(stg);
+
+            hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 0, 
&stg);
+            ok(SUCCEEDED(hr), "StgOpenStorage with mode %x failed with hr 
%x\n", current->stg_mode, hr);
+            if (FAILED(hr))
+            {
+                DeleteFileW(filename);
+                continue;
+            }
+        }
+
+        check_sharing(filename, current, GENERIC_READ, FILE_SHARE_READ, 
"READ", &open_mode, &any_failure);
+        check_sharing(filename, current, GENERIC_WRITE, FILE_SHARE_WRITE, 
"WRITE", &open_mode, &any_failure);
+        check_sharing(filename, current, DELETE, FILE_SHARE_DELETE, "DELETE", 
&open_mode, &any_failure);
+
+        if (open_mode != 0)
+        {
+            HANDLE hfile;
+            BOOL locked, expect_locked;
+            OVERLAPPED ol;
+            const int* next_lock = current->locked_bytes;
+
+            check_access(filename, current, GENERIC_READ, FILE_SHARE_READ, 
"READ", open_mode, &any_failure);
+            check_access(filename, current, GENERIC_WRITE, FILE_SHARE_WRITE, 
"WRITE", open_mode, &any_failure);
+            check_access(filename, current, DELETE, FILE_SHARE_DELETE, 
"DELETE", open_mode, &any_failure);
+
+            hfile = CreateFileW(filename, open_mode, 
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL, NULL);
+            ok(hfile != INVALID_HANDLE_VALUE, "couldn't open file with mode 
%x\n", current->stg_mode);
+
+            ol.u.s.OffsetHigh = 0;
+            ol.hEvent = NULL;
+
+            for (ol.u.s.Offset = 0x7fffff00; ol.u.s.Offset != 0x80000000; 
ol.u.s.Offset++)
+            {
+                if (LockFileEx(hfile, 
LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ol))
+                    locked = FALSE;
+                else
+                {
+                    ok(!LockFileEx(hfile, LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, 
&ol), "shared locks should not be used\n");
+                    locked = TRUE;
+                }
+
+                UnlockFileEx(hfile, 0, 1, 0, &ol);
+
+                if ((ol.u.s.Offset&0xff) == *next_lock)
+                {
+                    expect_locked = TRUE;
+                    next_lock++;
+                }
+                else
+                    expect_locked = FALSE;
+
+                if (!current->todo || locked == expect_locked)
+                    ok(locked == expect_locked, "byte %x of file with mode %x 
is %slocked but should %sbe\n",
+                       ol.u.s.Offset, current->stg_mode, locked?"":"not ", 
expect_locked?"":"not ");
+                else
+                {
+                    any_failure = TRUE;
+                    todo_wine ok(locked == expect_locked, "byte %x of file 
with mode %x is %slocked but should %sbe\n",
+                              ol.u.s.Offset, current->stg_mode, locked?"":"not 
", expect_locked?"":"not ");
+                }
+            }
+
+            CloseHandle(hfile);
+        }
+
+        IStorage_Release( stg );
+
+        if (!current->create)
+        {
+            HANDLE hfile;
+            BOOL failed, expect_failed=FALSE;
+            OVERLAPPED ol;
+            const int* next_range = current->fail_ranges;
+
+            hfile = CreateFileW(filename, open_mode, 
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL, NULL);
+            ok(hfile != INVALID_HANDLE_VALUE, "couldn't open file with mode 
%x\n", current->stg_mode);
+
+            ol.u.s.OffsetHigh = 0;
+            ol.hEvent = NULL;
+
+            for (ol.u.s.Offset = 0x7fffff00; ol.u.s.Offset != 0x80000000; 
ol.u.s.Offset++)
+            {
+                if (ol.u.s.Offset == 0x7fffff92 ||
+                    (ol.u.s.Offset == 0x7fffff80 && current->stg_mode == 
(STGM_TRANSACTED|STGM_READWRITE)) ||
+                    (ol.u.s.Offset == 0x7fffff80 && current->stg_mode == 
(STGM_TRANSACTED|STGM_READ)))
+                    continue; /* This makes opens hang */
+
+                LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ol);
+
+                hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 
0, &stg);
+                ok(hr == S_OK || hr == STG_E_LOCKVIOLATION || hr == 
STG_E_SHAREVIOLATION, "failed with unexpected hr %x\n", hr);
+                if (SUCCEEDED(hr)) IStorage_Release(stg);
+
+                UnlockFileEx(hfile, 0, 1, 0, &ol);
+
+                failed = FAILED(hr);
+
+                if (!expect_failed && (ol.u.s.Offset&0xff) == next_range[0])
+                {
+                    expect_failed = TRUE;
+                }
+                else if (expect_failed && (ol.u.s.Offset&0xff) == 
next_range[1])
+                {
+                    expect_failed = FALSE;
+                    next_range += 2;
+                }
+
+                if (!current->todo || failed == expect_failed)
+                    ok(failed == expect_failed, "open with byte %x locked, 
mode %x %s but should %s\n",
+                       ol.u.s.Offset, current->stg_mode, 
failed?"failed":"succeeded", expect_failed?"fail":"succeed");
+                else
+                {
+                    any_failure = TRUE;
+                    todo_wine ok(failed == expect_failed, "open with byte %x 
locked, mode %x %s but should %s\n",
+                                 ol.u.s.Offset, current->stg_mode, 
failed?"failed":"succeeded", expect_failed?"fail":"succeed");
+                }
+            }
+
+            CloseHandle(hfile);
+        }
+
+        DeleteFileW(filename);
+
+        if (current->todo && !any_failure)
+            todo_wine ok(1, "tests succeeded for mode %x\n", 
current->stg_mode);
+    }
+}
+
+static void test_transacted_shared(void)
+{
+    IStorage *stg = NULL;
+    IStorage *stgrw = NULL;
+    HRESULT r;
+    IStream *stm = NULL;
+    static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+    LARGE_INTEGER pos;
+    ULARGE_INTEGER upos;
+    char buffer[10];
+    ULONG bytesread;
+
+    DeleteFileA(filenameA);
+
+    /* create a new transacted storage with a stream */
+    r = StgCreateDocfile(filename, STGM_CREATE |
+                            STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+    ok(r==S_OK, "StgCreateDocfile failed %x\n", r);
+
+    r = WriteClassStg(stg, &test_stg_cls);
+    ok(r == S_OK, "WriteClassStg failed %x\n", r);
+
+    r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | 
STGM_READWRITE, 0, 0, &stm);
+    ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
+
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, 0, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Write(stm, "aaa", 3, NULL);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+
+    r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    /* open a second transacted read/write storage */
+    r = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_TRANSACTED | 
STGM_SHARE_DENY_NONE, NULL, 0, &stgrw);
+    ok(r==S_OK, "StgOpenStorage failed %x\n", r);
+
+    /* update stream on the first storage and commit */
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, 0, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Write(stm, "ccc", 3, NULL);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+
+    r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    /* update again without committing */
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, 0, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Write(stm, "ddd", 3, NULL);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+
+    IStream_Release(stm);
+
+    /* we can still read the old content from the second storage */
+    r = IStorage_OpenStream(stgrw, stmname, NULL, STGM_READWRITE | 
STGM_SHARE_EXCLUSIVE, 0, &stm);
+    ok(r==S_OK, "IStorage->OpenStream failed %x\n", r);
+
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, 0, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
+    ok(r==S_OK, "IStream->Read failed %x\n", r);
+    ok(bytesread == 3, "read wrong number of bytes %i\n", bytesread);
+    ok(memcmp(buffer, "aaa", 3) == 0, "wrong data\n");
+
+    /* and overwrite the data */
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, 0, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Write(stm, "bbb", 3, NULL);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+
+    IStream_Release(stm);
+
+    /* commit fails because we're out of date */
+    r = IStorage_Commit(stgrw, STGC_ONLYIFCURRENT);
+    ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
+
+    /* unless we force it */
+    r = IStorage_Commit(stgrw, STGC_DEFAULT);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    /* reverting gets us back to the last commit from the same storage */
+    r = IStorage_Revert(stg);
+    ok(r==S_OK, "IStorage->Revert failed %x\n", r);
+
+    r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | 
STGM_SHARE_EXCLUSIVE, 0, &stm);
+    ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
+
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, 0, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
+    ok(r==S_OK, "IStream->Read failed %x\n", r);
+    ok(bytesread == 3, "read wrong number of bytes %i\n", bytesread);
+    ok(memcmp(buffer, "ccc", 3) == 0, "wrong data\n");
+
+    /* and committing fails forever */
+    r = IStorage_Commit(stg, STGC_ONLYIFCURRENT);
+    ok(r==STG_E_NOTCURRENT, "IStorage->Commit failed %x\n", r);
+
+    IStream_Release(stm);
+
+    IStorage_Release(stg);
+    IStorage_Release(stgrw);
+
+    DeleteFileA(filenameA);
+}
+
+static void test_overwrite(void)
+{
+    IStorage *stg = NULL;
+    HRESULT r;
+    IStream *stm = NULL;
+    static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+    static const WCHAR stmname2[] = { 'C','O','N','T','E','N','T','2',0 };
+    LARGE_INTEGER pos;
+    ULARGE_INTEGER upos;
+    char buffer[4096];
+    DWORD orig_size, new_size;
+    ULONG bytesread;
+    HANDLE hfile;
+    int i;
+
+    DeleteFileA(filenameA);
+
+    r = StgCreateDocfile(filename, STGM_CREATE | STGM_READWRITE | 
STGM_TRANSACTED, 0, &stg);
+    ok(r==S_OK, "StgCreateDocfile failed %x\n", r);
+
+    r = WriteClassStg(stg, &test_stg_cls);
+    ok(r == S_OK, "WriteClassStg failed %x\n", r);
+
+    r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | 
STGM_READWRITE, 0, 0, &stm);
+    ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
+
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    memset(buffer, 'a', sizeof(buffer));
+    for (i=0; i<4; i++)
+    {
+        /* Write enough bytes to pass the minimum storage file size */
+        r = IStream_Write(stm, buffer, sizeof(buffer), NULL);
+        ok(r==S_OK, "IStream->Write failed %x\n", r);
+    }
+
+    r = IStorage_Commit(stg, STGC_DEFAULT);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    hfile = CreateFileA(filenameA, GENERIC_READ, 
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+        NULL, OPEN_EXISTING, 0, NULL);
+    ok(hfile != NULL, "couldn't open file %d\n", GetLastError());
+
+    orig_size = GetFileSize(hfile, NULL);
+
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Write(stm, "b", 1, NULL);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+
+    r = IStorage_Commit(stg, STGC_OVERWRITE);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    new_size = GetFileSize(hfile, NULL);
+
+    todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", 
orig_size, new_size);
+
+    IStream_Release(stm);
+
+    IStorage_RenameElement(stg, stmname, stmname2);
+
+    r = IStorage_Commit(stg, STGC_OVERWRITE);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    new_size = GetFileSize(hfile, NULL);
+
+    todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", 
orig_size, new_size);
+
+    IStorage_Release(stg);
+
+    r = StgOpenStorage(filename, NULL, STGM_READWRITE | STGM_TRANSACTED | 
STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
+    ok(r==S_OK, "StgOpenStorage failed %x\n", r);
+
+    r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE | 
STGM_READWRITE, 0, &stm);
+    ok(r==S_OK, "IStorage->CreateStream failed %x\n", r);
+
+    r = IStream_Read(stm, buffer, sizeof(buffer), &bytesread);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+    ok(bytesread == sizeof(buffer), "only read %d bytes\n", bytesread);
+    ok(buffer[0] == 'b', "unexpected data at byte 0\n");
+
+    for (i=1; i<sizeof(buffer); i++)
+        if (buffer[i] != 'a')
+            break;
+    ok(i == sizeof(buffer), "unexpected data at byte %i\n", i);
+
+    pos.QuadPart = 0;
+    r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
+    ok(r==S_OK, "IStream->Seek failed %x\n", r);
+
+    r = IStream_Write(stm, "c", 1, NULL);
+    ok(r==S_OK, "IStream->Write failed %x\n", r);
+
+    r = IStorage_Commit(stg, STGC_OVERWRITE);
+    ok(r==S_OK, "IStorage->Commit failed %x\n", r);
+
+    new_size = GetFileSize(hfile, NULL);
+
+    todo_wine ok(new_size == orig_size, "file grew from %d bytes to %d\n", 
orig_size, new_size);
+
+    IStream_Release(stm);
+
+    IStorage_Release(stg);
+
+    CloseHandle(hfile);
+
+    DeleteFileA(filenameA);
 }
 
 START_TEST(storage32)
@@ -3191,4 +3691,7 @@
     test_hglobal_storage_creation();
     test_convert();
     test_direct_swmr();
-}
+    test_locking();
+    test_transacted_shared();
+    test_overwrite();
+}


Reply via email to