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?... ============================================================================== --- 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/hglobalstr... ============================================================================== --- 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/propvarian... ============================================================================== --- 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.... ============================================================================== --- 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(); +}