#define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
+static CHAR filenameA[MAX_PATH];
+static WCHAR filename[MAX_PATH];
+
+static const char file1_nameA[] = {'c','o','p','y','t','e','s','t','A',0};
+static const WCHAR file1_name[] = {'c','o','p','y','t','e','s','t','A',0};
+static const char file2_nameA[] = {'c','o','p','y','t','e','s','t','B',0};
+static const WCHAR file2_name[] = {'c','o','p','y','t','e','s','t','B',0};
+static const WCHAR stgA_name[] = {'S','t','o','r','a','g','e','A',0};
+static const WCHAR stgB_name[] = {'S','t','o','r','a','g','e','B',0};
+static const WCHAR strmA_name[] = {'S','t','r','e','a','m','A',0};
+static const WCHAR strmB_name[] = {'S','t','r','e','a','m','B',0};
+static const WCHAR strmC_name[] = {'S','t','r','e','a','m','C',0};
+
+/* Win9x and WinMe don't have lstrcmpW */
+static int strcmp_ww(LPCWSTR strw1, LPCWSTR strw2)
+{
+ CHAR stra1[512], stra2[512];
+ WideCharToMultiByte(CP_ACP, 0, strw1, -1, stra1, sizeof(stra1), NULL, NULL);
+ WideCharToMultiByte(CP_ACP, 0, strw2, -1, stra2, sizeof(stra2), NULL, NULL);
+ return lstrcmpA(stra1, stra2);
+}
+
static void test_hglobal_storage_stat(void)
{
ILockBytes *ilb = NULL;
static void test_create_storage_modes(void)
{
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- static const WCHAR szDot[] = { '.',0 };
- WCHAR filename[MAX_PATH];
IStorage *stg = NULL;
HRESULT r;
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* test with some invalid parameters */
r = StgCreateDocfile( NULL, 0, 0, &stg);
ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile wrong error\n");
r = StgCreateDocfile( filename, STGM_TRANSACTED | STGM_SHARE_DENY_WRITE | STGM_READ, 0, &stg);
ok(r==STG_E_INVALIDFLAG, "StgCreateDocfile wrong error\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
r = StgCreateDocfile( filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
ok(r==S_OK, "StgCreateDocfile failed\n");
ok(r==S_OK, "StgCreateDocfile failed\n");
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
r = StgCreateDocfile( filename, STGM_CREATE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
ok(r==S_OK, "StgCreateDocfile failed\n");
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
/* test the way excel uses StgCreateDocFile */
r = StgCreateDocfile( filename, STGM_TRANSACTED|STGM_CREATE|STGM_SHARE_DENY_WRITE|STGM_READWRITE, 0, &stg);
{
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
}
/* and the way windows media uses it ... */
{
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
}
/* looks like we need STGM_TRANSACTED or STGM_CREATE */
{
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
}
r = StgCreateDocfile( filename, STGM_TRANSACTED|STGM_CREATE|STGM_SHARE_DENY_WRITE|STGM_WRITE, 0, &stg);
{
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
}
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
{
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
}
/* test the way msi uses StgCreateDocfile */
ok(r==S_OK, "StgCreateDocFile failed\n");
r = IStorage_Release(stg);
ok(r == 0, "storage not released\n");
- ok(DeleteFileW(filename), "failed to delete file\n");
+ ok(DeleteFileA(filenameA), "failed to delete file\n");
}
static void test_storage_stream(void)
{
static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- static const WCHAR szDot[] = { '.',0 };
static const WCHAR longname[] = {
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',0
};
- WCHAR filename[MAX_PATH];
IStorage *stg = NULL;
HRESULT r;
IStream *stm = NULL;
ULARGE_INTEGER p;
unsigned char buffer[0x100];
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
ok(r==S_OK, "StgCreateDocfile failed\n");
r = IStorage_Release(stg);
ok(r == 0, "wrong ref count\n");
- r = DeleteFileW(filename);
+
+ /* try create some invalid streams */
+ stg = NULL;
+ stm = NULL;
+ r = StgOpenStorage(filename, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
+ ok(r == S_OK, "should succeed\n");
+ if (stg)
+ {
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
+ ok(r == STG_E_INVALIDFLAG, "IStorage->OpenStream should return STG_E_INVALIDFLAG instead of 0x%08x\n", r);
+ IStorage_Release(stg);
+ }
+
+ r = DeleteFileA(filenameA);
ok(r, "file should exist\n");
}
-static BOOL touch_file(LPCWSTR filename)
+static BOOL touch_file(LPCSTR filename)
{
HANDLE file;
- file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+ file = CreateFileA(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file==INVALID_HANDLE_VALUE)
return FALSE;
return TRUE;
}
-static BOOL is_zero_length(LPCWSTR filename)
+static BOOL is_zero_length(LPCSTR filename)
{
HANDLE file;
DWORD len;
- file = CreateFileW(filename, GENERIC_READ, 0, NULL,
+ file = CreateFileA(filename, GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (file==INVALID_HANDLE_VALUE)
return FALSE;
return len == 0;
}
-static BOOL is_existing_file(LPCWSTR filename)
+static BOOL is_existing_file(LPCSTR filename)
{
HANDLE file;
- file = CreateFileW(filename, GENERIC_READ, 0, NULL,
+ file = CreateFileA(filename, GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (file==INVALID_HANDLE_VALUE)
return FALSE;
static void test_open_storage(void)
{
- static const WCHAR szPrefix[] = { 's','t','g',0 };
static const WCHAR szNonExist[] = { 'n','o','n','e','x','i','s','t',0 };
- static const WCHAR szDot[] = { '.',0 };
- WCHAR filename[MAX_PATH];
IStorage *stg = NULL, *stg2 = NULL;
HRESULT r;
DWORD stgm;
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
/* try opening a zero length file - it should stay zero length */
- DeleteFileW(filename);
- touch_file(filename);
+ DeleteFileA(filenameA);
+ touch_file(filenameA);
stgm = STGM_NOSCRATCH | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE | STGM_READWRITE;
r = StgOpenStorage( filename, NULL, stgm, NULL, 0, &stg);
ok(r==STG_E_FILEALREADYEXISTS, "StgOpenStorage didn't fail\n");
stgm = STGM_SHARE_EXCLUSIVE | STGM_READWRITE;
r = StgOpenStorage( filename, NULL, stgm, NULL, 0, &stg);
ok(r==STG_E_FILEALREADYEXISTS, "StgOpenStorage didn't fail\n");
- ok(is_zero_length(filename), "file length changed\n");
+ ok(is_zero_length(filenameA), "file length changed\n");
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* try opening a nonexistent file - it should not create it */
stgm = STGM_DIRECT | STGM_SHARE_EXCLUSIVE | STGM_READWRITE;
r = StgOpenStorage( filename, NULL, stgm, NULL, 0, &stg);
ok(r!=S_OK, "StgOpenStorage failed: 0x%08x\n", r);
if (r==S_OK) IStorage_Release(stg);
- ok(!is_existing_file(filename), "StgOpenStorage should not create a file\n");
- DeleteFileW(filename);
+ ok(!is_existing_file(filenameA), "StgOpenStorage should not create a file\n");
+ DeleteFileA(filenameA);
/* create the file */
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
r = StgOpenStorage( filename, NULL, STGM_NOSNAPSHOT | STGM_PRIORITY, NULL, 0, &stg);
ok(r == STG_E_INVALIDFLAG, "should fail\n");
- r = DeleteFileW(filename);
+ r = DeleteFileA(filenameA);
ok(r, "file didn't exist\n");
}
static void test_storage_suminfo(void)
{
- static const WCHAR szDot[] = { '.',0 };
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- WCHAR filename[MAX_PATH];
IStorage *stg = NULL;
IPropertySetStorage *propset = NULL;
IPropertyStorage *ps = NULL;
HRESULT r;
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* create the file */
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
r = IStorage_Release(stg);
ok(r == 0, "ref count wrong\n");
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
}
static void test_storage_refcount(void)
{
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- static const WCHAR szDot[] = { '.',0 };
- WCHAR filename[MAX_PATH];
IStorage *stg = NULL;
IStorage *stgprio = NULL;
HRESULT r;
STATSTG stat;
char buffer[10];
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* create the file */
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
r = IStorage_Stat( stg2, &statstg, STATFLAG_DEFAULT );
ok(r == S_OK, "Stat should have succeded instead of returning 0x%08x\n", r);
- ok(!lstrcmpW(statstg.pwcsName, stgname),
+ ok(!memcmp(statstg.pwcsName, stgname, sizeof(stgname)),
"Statstg pwcsName should have been the name the storage was created with\n");
ok(statstg.type == STGTY_STORAGE, "Statstg type should have been STGTY_STORAGE instead of %d\n", statstg.type);
ok(U(statstg.cbSize).LowPart == 0, "Statstg cbSize.LowPart should have been 0 instead of %d\n", U(statstg.cbSize).LowPart);
}
IStorage_Release(stgprio);
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
}
static void test_writeclassstg(void)
{
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- static const WCHAR szDot[] = { '.',0 };
- WCHAR filename[MAX_PATH];
IStorage *stg = NULL;
HRESULT r;
CLSID temp_cls;
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* create the file */
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
r = IStorage_Release( stg );
ok (r == 0, "storage not released\n");
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
}
static void test_streamenum(void)
{
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- static const WCHAR szDot[] = { '.',0 };
- WCHAR filename[MAX_PATH];
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[] = { 'A','B','C','D','E','F','G','H','I',0 };
+ static const WCHAR stmname3[] = { 'A','B','C','D','E','F','G','H','I','J',0 };
STATSTG stat;
IEnumSTATSTG *ee = NULL;
ULONG count;
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* create the file */
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
ok(count == 1, "count wrong\n");
+ if (r == S_OK)
+ CoTaskMemFree(stat.pwcsName);
+
r = IEnumSTATSTG_Release(ee);
/* second enum... destroy the stream before reading */
ok(r==S_OK, "IStorage->EnumElements failed\n");
r = IStorage_DestroyElement(stg, stmname);
- ok(r==S_OK, "IStorage->EnumElements failed\n");
+ ok(r==S_OK, "IStorage->DestroyElement failed\n");
- todo_wine {
count = 0xf00;
r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n");
ok(count == 0, "count wrong\n");
- }
/* reset and try again */
r = IEnumSTATSTG_Reset(ee);
ok(r==S_FALSE, "IEnumSTATSTG->Next failed\n");
ok(count == 0, "count wrong\n");
- r = IEnumSTATSTG_Release(ee);
- ok (r == 0, "enum not released\n");
+ /* add a stream before reading */
+ r = IEnumSTATSTG_Reset(ee);
+ ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
+
+ r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ r = IStream_Release(stm);
+
+ count = 0xf00;
+ r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
+ ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
+ ok(count == 1, "count wrong\n");
+
+ if (r == S_OK)
+ {
+ ok(lstrcmpiW(stat.pwcsName, stmname) == 0, "expected CONTENTS, got %s\n", wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+ }
+
+ r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ r = IStream_Release(stm);
+
+ count = 0xf00;
+ r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
+ ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
+ ok(count == 1, "count wrong\n");
+
+ if (r == S_OK)
+ {
+ ok(lstrcmpiW(stat.pwcsName, stmname2) == 0, "expected ABCDEFGHI, got %s\n", wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+ }
+
+ /* delete previous and next stream after reading */
+ r = IStorage_CreateStream(stg, stmname3, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ r = IStream_Release(stm);
+
+ r = IEnumSTATSTG_Reset(ee);
+ ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
+
+ count = 0xf00;
+ r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
+ ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
+ ok(count == 1, "count wrong\n");
+
+ if (r == S_OK)
+ {
+ ok(lstrcmpiW(stat.pwcsName, stmname) == 0, "expected CONTENTS, got %s\n", wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+ }
+
+ r = IStorage_DestroyElement(stg, stmname);
+ ok(r==S_OK, "IStorage->DestroyElement failed\n");
+
+ r = IStorage_DestroyElement(stg, stmname2);
+ ok(r==S_OK, "IStorage->DestroyElement failed\n");
+
+ count = 0xf00;
+ r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
+ ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
+ ok(count == 1, "count wrong\n");
+
+ if (r == S_OK)
+ {
+ ok(lstrcmpiW(stat.pwcsName, stmname3) == 0, "expected ABCDEFGHIJ, got %s\n", wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+ }
r = IStorage_Release( stg );
- ok (r == 0, "storage not released\n");
+ todo_wine ok (r == 0, "storage not released\n");
+
+ /* enumerator is still valid and working after the storage is released */
+ r = IEnumSTATSTG_Reset(ee);
+ ok(r==S_OK, "IEnumSTATSTG->Reset failed\n");
+
+ count = 0xf00;
+ r = IEnumSTATSTG_Next(ee, 1, &stat, &count);
+ ok(r==S_OK, "IEnumSTATSTG->Next failed\n");
+ ok(count == 1, "count wrong\n");
+
+ if (r == S_OK)
+ {
+ ok(lstrcmpiW(stat.pwcsName, stmname3) == 0, "expected ABCDEFGHIJ, got %s\n", wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+ }
+
+ /* the storage is left open until the enumerator is freed */
+ r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE |STGM_TRANSACTED, NULL, 0, &stg);
+ ok(r==STG_E_SHAREVIOLATION ||
+ r==STG_E_LOCKVIOLATION, /* XP-SP2/W2K3-SP1 and below */
+ "StgCreateDocfile failed, res=%x\n", r);
+
+ r = IEnumSTATSTG_Release(ee);
+ ok (r == 0, "enum not released\n");
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
}
static void test_transact(void)
{
- static const WCHAR szPrefix[] = { 's','t','g',0 };
- static const WCHAR szDot[] = { '.',0 };
- WCHAR filename[MAX_PATH];
- IStorage *stg = NULL, *stg2 = NULL;
+ IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
HRESULT r;
IStream *stm = NULL;
static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
static const WCHAR stmname2[] = { 'F','O','O',0 };
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+ static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 };
- if(!GetTempFileNameW(szDot, szPrefix, 0, filename))
- return;
-
- DeleteFileW(filename);
+ DeleteFileA(filenameA);
/* create the file */
r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
ok(r==S_OK, "StgCreateDocfile failed\n");
- /* now create a stream, but don't commit it */
+ /* commit a new stream and storage */
r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
ok(r==S_OK, "IStorage->CreateStream failed\n");
r = IStream_Write(stm, "this is stream 1\n", 16, NULL);
ok(r==S_OK, "IStream->Write failed\n");
- r = IStream_Release(stm);
+ IStream_Release(stm);
+
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ {
+ /* Create two substorages but only commit one */
+ r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
- r = IStorage_Commit(stg, 0);
- ok(r==S_OK, "IStorage->Commit failed\n");
+ if (r == S_OK)
+ IStorage_Release(stg3);
- /* now create a stream, but don't commit it */
+ r = IStorage_Commit(stg, 0);
+ ok(r==S_OK, "IStorage->Commit failed\n");
+
+ r = IStorage_CreateStorage(stg2, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ IStorage_Release(stg3);
+
+ IStorage_Release(stg2);
+ }
+
+ /* now create a stream and storage, but don't commit them */
stm = NULL;
r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
ok(r==S_OK, "IStorage->CreateStream failed\n");
r = IStream_Write(stm, "this is stream 2\n", 16, NULL);
ok(r==S_OK, "IStream->Write failed\n");
+ /* IStream::Commit does nothing for OLE storage streams */
r = IStream_Commit(stm, STGC_ONLYIFCURRENT | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
ok(r==S_OK, "IStream->Commit failed\n");
- r = IStream_Release(stm);
+ r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ IStorage_Release(stg2);
+
+ IStream_Release(stm);
IStorage_Release(stg);
r = IStorage_OpenStorage(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
- todo_wine {
r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
- }
- if (stm)
- r = IStream_Release(stm);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
+ if (r == S_OK)
+ IStorage_Release(stg2);
r = IStorage_OpenStorage(stg, stmname2, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
- ok(r==S_OK, "IStorage->OpenStream should fail %08x\n", r);
- if (stm)
- r = IStream_Release(stm);
+ ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
+ ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
+ if (r == S_OK)
+ {
+ r = IStorage_OpenStorage(stg2, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
+ ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
+ if (r == S_OK)
+ IStorage_Release(stg3);
+
+ r = IStorage_OpenStorage(stg2, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
+ if (r == S_OK)
+ IStorage_Release(stg3);
+
+ IStorage_Release(stg2);
+ }
IStorage_Release(stg);
- r = DeleteFileW(filename);
+ r = DeleteFileA(filenameA);
ok( r == TRUE, "deleted file\n");
}
-static void test_ReadClassStm(void)
+static void test_substorage_share(void)
{
- CLSID clsid;
- HRESULT hr;
- IStream *pStream;
- static const LARGE_INTEGER llZero;
+ IStorage *stg, *stg2, *stg3;
+ IStream *stm, *stm2;
+ HRESULT r;
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+ static const WCHAR othername[] = { 'N','E','W','N','A','M','E',0 };
- hr = ReadClassStm(NULL, &clsid);
- ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
+ DeleteFileA(filenameA);
- hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
- ok_ole_success(hr, "CreateStreamOnHGlobal");
- hr = WriteClassStm(pStream, &test_stg_cls);
- ok_ole_success(hr, "WriteClassStm");
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
- hr = ReadClassStm(pStream, NULL);
- ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
+ /* create a read/write storage and try to open it again */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
- /* test not rewound stream */
- hr = ReadClassStm(pStream, &clsid);
- ok(hr == STG_E_READFAULT, "ReadClassStm should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
- ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid should have been zeroed\n");
+ if (r == S_OK)
+ {
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r);
- hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
- ok_ole_success(hr, "IStream_Seek");
- hr = ReadClassStm(pStream, &clsid);
- ok_ole_success(hr, "ReadClassStm");
- ok(IsEqualCLSID(&clsid, &test_stg_cls), "clsid should have been set to CLSID_WineTest\n");
-}
+ if (r == S_OK)
+ IStorage_Release(stg3);
-struct access_res
-{
- BOOL gothandle;
- DWORD lasterr;
- BOOL ignore;
-};
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage should fail %08x\n", r);
-static const struct access_res create[16] =
-{
- { TRUE, ERROR_SUCCESS, TRUE },
- { TRUE, ERROR_SUCCESS, TRUE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { TRUE, ERROR_SUCCESS, TRUE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { TRUE, ERROR_SUCCESS, TRUE }
-};
+ if (r == S_OK)
+ IStorage_Release(stg3);
-static const struct access_res create_commit[16] =
-{
- { TRUE, ERROR_SUCCESS, TRUE },
- { TRUE, ERROR_SUCCESS, TRUE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { TRUE, ERROR_SUCCESS, TRUE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { FALSE, ERROR_SHARING_VIOLATION, FALSE },
- { TRUE, ERROR_SUCCESS, TRUE }
-};
+ /* cannot rename the storage while it's open */
+ r = IStorage_RenameElement(stg, stgname, othername);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r);
+ if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stgname);
-static const struct access_res create_close[16] =
-{
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS, FALSE },
- { TRUE, ERROR_SUCCESS }
-};
+ /* destroying an object while it's open invalidates it */
+ r = IStorage_DestroyElement(stg, stgname);
+ ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r);
-static void _test_file_access(LPCSTR file, const struct access_res *ares, DWORD line)
-{
- DWORD access = 0, share = 0;
- DWORD lasterr;
- HANDLE hfile;
- int i, j, idx = 0;
+ r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ ok(r==STG_E_REVERTED, "IStorage->CreateStream failed, hr=%08x\n", r);
- for (i = 0; i < 4; i++)
- {
- if (i == 0) access = 0;
- if (i == 1) access = GENERIC_READ;
- if (i == 2) access = GENERIC_WRITE;
- if (i == 3) access = GENERIC_READ | GENERIC_WRITE;
+ if (r == S_OK)
+ IStorage_Release(stm);
- for (j = 0; j < 4; j++)
- {
- if (ares[idx].ignore)
- continue;
+ IStorage_Release(stg2);
+ }
- if (j == 0) share = 0;
- if (j == 1) share = FILE_SHARE_READ;
- if (j == 2) share = FILE_SHARE_WRITE;
- if (j == 3) share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ /* create a read/write stream and try to open it again */
+ r = IStorage_CreateStream(stg, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
- SetLastError(0xdeadbeef);
- hfile = CreateFileA(file, access, share, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, 0);
- lasterr = GetLastError();
+ if (r == S_OK)
+ {
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm2);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r);
- ok((hfile != INVALID_HANDLE_VALUE) == ares[idx].gothandle,
- "(%d, handle, %d): Expected %d, got %d\n",
- line, idx, ares[idx].gothandle,
- (hfile != INVALID_HANDLE_VALUE));
+ if (r == S_OK)
+ IStorage_Release(stm2);
+
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm2);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStream should fail %08x\n", r);
+
+ if (r == S_OK)
+ IStorage_Release(stm2);
+
+ /* cannot rename the stream while it's open */
+ r = IStorage_RenameElement(stg, stmname, othername);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->RenameElement should fail %08x\n", r);
+ if (SUCCEEDED(r)) IStorage_RenameElement(stg, othername, stmname);
+
+ /* destroying an object while it's open invalidates it */
+ r = IStorage_DestroyElement(stg, stmname);
+ ok(r==S_OK, "IStorage->DestroyElement failed, hr=%08x\n", r);
+
+ r = IStream_Write(stm, "this shouldn't work\n", 20, NULL);
+ ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
+
+ IStorage_Release(stm);
+ }
+
+ IStorage_Release(stg);
+
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
+
+static void test_revert(void)
+{
+ IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
+ HRESULT r;
+ IStream *stm = NULL, *stm2 = NULL;
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+ static const WCHAR stmname2[] = { 'F','O','O',0 };
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+ static const WCHAR stgname2[] = { 'T','E','M','P','S','T','G',0 };
+ STATSTG statstg;
+
+ DeleteFileA(filenameA);
+
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* commit a new stream and storage */
+ r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ r = IStream_Write(stm, "this is stream 1\n", 16, NULL);
+ ok(r==S_OK, "IStream->Write failed\n");
+
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ {
+ /* Create two substorages but only commit one */
+ r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ IStorage_Release(stg3);
+
+ r = IStorage_Commit(stg, 0);
+ ok(r==S_OK, "IStorage->Commit failed\n");
+
+ r = IStorage_CreateStorage(stg2, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ IStorage_Release(stg3);
+ }
+
+ /* now create a stream and storage, then revert */
+ r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm2 );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ r = IStream_Write(stm2, "this is stream 2\n", 16, NULL);
+ ok(r==S_OK, "IStream->Write failed\n");
+
+ r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ r = IStorage_Revert(stg);
+
+ /* all open objects become invalid */
+ r = IStream_Write(stm, "this shouldn't work\n", 20, NULL);
+ ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
+
+ r = IStream_Write(stm2, "this shouldn't work\n", 20, NULL);
+ ok(r==STG_E_REVERTED, "IStream_Write should fail %08x\n", r);
+
+ r = IStorage_Stat(stg2, &statstg, STATFLAG_NONAME);
+ ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
+
+ r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME);
+ ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
+
+ IStream_Release(stm);
+ IStream_Release(stm2);
+ IStorage_Release(stg2);
+ IStorage_Release(stg3);
+
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_DENY_NONE|STGM_READ, 0, &stm );
+ ok(r==STG_E_INVALIDFLAG, "IStorage->OpenStream failed %08x\n", r);
+
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_DELETEONRELEASE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
+
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==STG_E_INVALIDFUNCTION, "IStorage->OpenStream failed %08x\n", r);
+
+ r = IStorage_OpenStorage(stg, stmname, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
+
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
+ if (r == S_OK)
+ IStorage_Release(stg2);
+
+ r = IStorage_OpenStorage(stg, stmname2, NULL, STGM_TRANSACTED|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream failed %08x\n", r);
+
+ r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg2 );
+ ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
+ if (r == S_OK)
+ {
+ r = IStorage_OpenStorage(stg2, stgname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
+ ok(r==S_OK, "IStorage->OpenStorage should succeed %08x\n", r);
+ if (r == S_OK)
+ IStorage_Release(stg3);
+
+ r = IStorage_OpenStorage(stg2, stgname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg3 );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStorage should fail %08x\n", r);
+ if (r == S_OK)
+ IStorage_Release(stg3);
+
+ IStorage_Release(stg2);
+ }
+
+ IStorage_Release(stg);
+
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+
+ /* Revert only invalidates objects in transacted mode */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ r = IStorage_Revert(stg);
+ ok(r==S_OK, "IStorage->Revert failed %08x\n", r);
+
+ r = IStream_Write(stm, "this works\n", 11, NULL);
+ ok(r==S_OK, "IStream_Write should succeed %08x\n", r);
+
+ IStream_Release(stm);
+ IStream_Release(stg);
+
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
+
+static void test_parent_free(void)
+{
+ IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
+ HRESULT r;
+ IStream *stm = NULL;
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+ ULONG ref;
+ STATSTG statstg;
+
+ DeleteFileA(filenameA);
+
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* create a new storage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ {
+ /* now create a stream inside the new storage */
+ r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+
+ if (r == S_OK)
+ {
+ /* create a storage inside the new storage */
+ r = IStorage_CreateStorage(stg2, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg3 );
+ ok(r==S_OK, "IStorage->CreateStorage failed\n");
+ }
+
+ /* free the parent */
+ ref = IStorage_Release(stg2);
+ ok(ref == 0, "IStorage still has %u references\n", ref);
+
+ /* child objects are invalid */
+ if (r == S_OK)
+ {
+ r = IStream_Write(stm, "this should fail\n", 17, NULL);
+ ok(r==STG_E_REVERTED, "IStream->Write sould fail, hr=%x\n", r);
+
+ IStream_Release(stm);
+
+ r = IStorage_Stat(stg3, &statstg, STATFLAG_NONAME);
+ ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
+
+ r = IStorage_SetStateBits(stg3, 1, 1);
+ ok(r==STG_E_REVERTED, "IStorage_Stat should fail %08x\n", r);
+
+ IStorage_Release(stg3);
+ }
+ }
+
+ IStorage_Release(stg);
+
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
+
+static void test_nonroot_transacted(void)
+{
+ IStorage *stg = NULL, *stg2 = NULL, *stg3 = NULL;
+ HRESULT r;
+ IStream *stm = NULL;
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+ static const WCHAR stmname2[] = { 'F','O','O',0 };
+
+ DeleteFileA(filenameA);
+
+ /* create a transacted file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* create a transacted substorage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ {
+ /* create and commit stmname */
+ r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ IStorage_Commit(stg2, 0);
+
+ /* create and revert stmname2 */
+ r = IStorage_CreateStream(stg2, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ IStorage_Revert(stg2);
+
+ /* check that Commit and Revert really worked */
+ r = IStorage_OpenStream(stg2, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ IStorage_Release(stg2);
+ }
+
+ /* create a read-only transacted substorage */
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, NULL, 0, &stg2);
+ ok(r==S_OK, "IStorage->OpenStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ {
+ /* The storage can be modified. */
+ r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stg3);
+
+ /* But changes cannot be committed. */
+ r = IStorage_Commit(stg2, 0);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->Commit should fail, hr=%08x\n", r);
+
+ IStorage_Release(stg2);
+ }
+
+ IStorage_Release(stg);
+
+ /* create a non-transacted file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* create a transacted substorage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ if (r == S_OK)
+ {
+ /* create and commit stmname */
+ r = IStorage_CreateStream(stg2, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ IStorage_Commit(stg2, 0);
+
+ /* create and revert stmname2 */
+ r = IStorage_CreateStream(stg2, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm );
+ ok(r==S_OK, "IStorage->CreateStream failed\n");
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ IStorage_Revert(stg2);
+
+ /* check that Commit and Revert really worked */
+ r = IStorage_OpenStream(stg2, stmname, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==S_OK, "IStorage->OpenStream should succeed %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+ ok(r==STG_E_FILENOTFOUND, "IStorage->OpenStream should fail %08x\n", r);
+ if (r == S_OK)
+ IStream_Release(stm);
+
+ IStorage_Release(stg2);
+ }
+
+ IStream_Release(stg);
+
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
+
+static void test_ReadClassStm(void)
+{
+ CLSID clsid;
+ HRESULT hr;
+ IStream *pStream;
+ static const LARGE_INTEGER llZero;
+
+ hr = ReadClassStm(NULL, &clsid);
+ ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
+ ok_ole_success(hr, "CreateStreamOnHGlobal");
+ hr = WriteClassStm(pStream, &test_stg_cls);
+ ok_ole_success(hr, "WriteClassStm");
+
+ hr = ReadClassStm(pStream, NULL);
+ ok(hr == E_INVALIDARG, "ReadClassStm should have returned E_INVALIDARG instead of 0x%08x\n", hr);
+
+ /* test not rewound stream */
+ hr = ReadClassStm(pStream, &clsid);
+ ok(hr == STG_E_READFAULT, "ReadClassStm should have returned STG_E_READFAULT instead of 0x%08x\n", hr);
+ ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid should have been zeroed\n");
+
+ hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
+ ok_ole_success(hr, "IStream_Seek");
+ hr = ReadClassStm(pStream, &clsid);
+ ok_ole_success(hr, "ReadClassStm");
+ ok(IsEqualCLSID(&clsid, &test_stg_cls), "clsid should have been set to CLSID_WineTest\n");
+
+ IStream_Release(pStream);
+}
+
+struct access_res
+{
+ BOOL gothandle;
+ DWORD lasterr;
+ BOOL ignore;
+};
+
+static const struct access_res create[16] =
+{
+ { TRUE, ERROR_SUCCESS, TRUE },
+ { TRUE, ERROR_SUCCESS, TRUE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { TRUE, ERROR_SUCCESS, TRUE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { TRUE, ERROR_SUCCESS, TRUE }
+};
+
+static const struct access_res create_commit[16] =
+{
+ { TRUE, ERROR_SUCCESS, TRUE },
+ { TRUE, ERROR_SUCCESS, TRUE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { TRUE, ERROR_SUCCESS, TRUE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { FALSE, ERROR_SHARING_VIOLATION, FALSE },
+ { TRUE, ERROR_SUCCESS, TRUE }
+};
+
+static const struct access_res create_close[16] =
+{
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS, FALSE },
+ { TRUE, ERROR_SUCCESS }
+};
+
+static void _test_file_access(LPCSTR file, const struct access_res *ares, DWORD line)
+{
+ DWORD access = 0, share = 0;
+ DWORD lasterr;
+ HANDLE hfile;
+ int i, j, idx = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (i == 0) access = 0;
+ if (i == 1) access = GENERIC_READ;
+ if (i == 2) access = GENERIC_WRITE;
+ if (i == 3) access = GENERIC_READ | GENERIC_WRITE;
+
+ for (j = 0; j < 4; j++)
+ {
+ if (ares[idx].ignore)
+ continue;
+
+ if (j == 0) share = 0;
+ if (j == 1) share = FILE_SHARE_READ;
+ if (j == 2) share = FILE_SHARE_WRITE;
+ if (j == 3) share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ SetLastError(0xdeadbeef);
+ hfile = CreateFileA(file, access, share, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ lasterr = GetLastError();
+
+ ok((hfile != INVALID_HANDLE_VALUE) == ares[idx].gothandle,
+ "(%d, handle, %d): Expected %d, got %d\n",
+ line, idx, ares[idx].gothandle,
+ (hfile != INVALID_HANDLE_VALUE));
ok(lasterr == ares[idx].lasterr ||
broken(lasterr == 0xdeadbeef) /* win9x */,
"(%d, lasterr, %d): Expected %d, got %d\n",
line, idx, ares[idx].lasterr, lasterr);
- CloseHandle(hfile);
- idx++;
+ CloseHandle(hfile);
+ idx++;
+ }
+ }
+}
+
+#define test_file_access(file, ares) _test_file_access(file, ares, __LINE__)
+
+static void test_access(void)
+{
+ IStorage *stg;
+ HRESULT hr;
+
+ static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
+
+ /* STGM_TRANSACTED */
+
+ hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, &stg);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create);
+
+ hr = IStorage_Commit(stg, STGC_DEFAULT);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create_commit);
+
+ IStorage_Release(stg);
+
+ test_file_access("winetest", create_close);
+
+ DeleteFileA("winetest");
+
+ /* STGM_DIRECT */
+
+ hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &stg);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create);
+
+ hr = IStorage_Commit(stg, STGC_DEFAULT);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create_commit);
+
+ IStorage_Release(stg);
+
+ test_file_access("winetest", create_close);
+
+ DeleteFileA("winetest");
+
+ /* STGM_SHARE_DENY_NONE */
+
+ hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
+ STGM_SHARE_DENY_NONE | STGM_TRANSACTED, 0, &stg);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create);
+
+ hr = IStorage_Commit(stg, STGC_DEFAULT);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create_commit);
+
+ IStorage_Release(stg);
+
+ test_file_access("winetest", create_close);
+
+ DeleteFileA("winetest");
+
+ /* STGM_SHARE_DENY_READ */
+
+ hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
+ STGM_SHARE_DENY_READ | STGM_TRANSACTED, 0, &stg);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create);
+
+ hr = IStorage_Commit(stg, STGC_DEFAULT);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create_commit);
+
+ IStorage_Release(stg);
+
+ test_file_access("winetest", create_close);
+
+ DeleteFileA("winetest");
+
+ /* STGM_SHARE_DENY_WRITE */
+
+ hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
+ STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create);
+
+ hr = IStorage_Commit(stg, STGC_DEFAULT);
+ ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+
+ test_file_access("winetest", create_commit);
+
+ IStorage_Release(stg);
+
+ test_file_access("winetest", create_close);
+
+ DeleteFileA("winetest");
+}
+
+static void test_readonly(void)
+{
+ IStorage *stg, *stg2, *stg3;
+ IStream *stream;
+ HRESULT hr;
+ static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
+ static const WCHAR storageW[] = {'s','t','o','r','a','g','e',0};
+ static const WCHAR streamW[] = {'s','t','r','e','a','m',0};
+
+ hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ hr = IStorage_CreateStorage( stg, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg2 );
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ hr = IStorage_CreateStream( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stream );
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ IStream_Release(stream);
+ IStorage_Release(stg2);
+ }
+ IStorage_Release(stg);
+ }
+
+ /* re-open read only */
+ hr = StgOpenStorage( fileW, NULL, STGM_TRANSACTED | STGM_SHARE_DENY_NONE | STGM_READ, NULL, 0, &stg);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ hr = IStorage_OpenStorage( stg, storageW, NULL, STGM_SHARE_EXCLUSIVE | STGM_READ, NULL, 0, &stg2 );
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ /* CreateStream on read-only storage, name exists */
+ hr = IStorage_CreateStream( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stream );
+ ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ IStream_Release(stream);
+
+ /* CreateStream on read-only storage, name does not exist */
+ hr = IStorage_CreateStream( stg2, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stream );
+ ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ IStream_Release(stream);
+
+ /* CreateStorage on read-only storage, name exists */
+ hr = IStorage_CreateStorage( stg2, streamW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stg3 );
+ ok(hr == STG_E_FILEALREADYEXISTS, "should fail, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ IStream_Release(stg3);
+
+ /* CreateStorage on read-only storage, name does not exist */
+ hr = IStorage_CreateStorage( stg2, storageW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READ, 0, 0, &stg3 );
+ ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ IStream_Release(stg3);
+
+ /* DestroyElement on read-only storage, name exists */
+ hr = IStorage_DestroyElement( stg2, streamW );
+ ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
+
+ /* DestroyElement on read-only storage, name does not exist */
+ hr = IStorage_DestroyElement( stg2, storageW );
+ ok(hr == STG_E_ACCESSDENIED, "should fail, res=%x\n", hr);
+
+ IStorage_Release(stg2);
+ }
+
+ IStorage_Release(stg);
+ }
+
+ DeleteFileA("winetest");
+}
+
+static void test_simple(void)
+{
+ /* Tests for STGM_SIMPLE mode */
+
+ IStorage *stg, *stg2;
+ HRESULT r;
+ IStream *stm;
+ static const WCHAR stgname[] = { 'S','t','g',0 };
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+ static const WCHAR stmname2[] = { 'S','m','a','l','l',0 };
+ LARGE_INTEGER pos;
+ ULARGE_INTEGER upos;
+ DWORD count;
+ STATSTG stat;
+
+ DeleteFileA(filenameA);
+
+ r = StgCreateDocfile( filename, STGM_SIMPLE | STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
+ ok(r == S_OK, "got %08x\n", r);
+
+ r = IStorage_CreateStorage(stg, stgname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stg2);
+ ok(r == STG_E_INVALIDFUNCTION, "got %08x\n", r);
+ if (SUCCEEDED(r)) IStorage_Release(stg2);
+
+ r = IStorage_CreateStream(stg, stmname, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
+ ok(r == STG_E_INVALIDFLAG, "got %08x\n", r);
+ r = IStorage_CreateStream(stg, stmname, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
+ ok(r == S_OK, "got %08x\n", r);
+
+ upos.QuadPart = 6000;
+ r = IStream_SetSize(stm, upos);
+ ok(r == S_OK, "got %08x\n", r);
+
+ r = IStream_Write(stm, "foo", 3, &count);
+ ok(r == S_OK, "got %08x\n", r);
+ ok(count == 3, "got %d\n", count);
+
+ pos.QuadPart = 0;
+ r = IStream_Seek(stm, pos, STREAM_SEEK_CUR, &upos);
+ ok(r == S_OK, "got %08x\n", r);
+ ok(upos.QuadPart == 3, "got %d\n", upos.u.LowPart);
+
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
+ ok(r == S_OK ||
+ broken(r == STG_E_INVALIDFUNCTION), /* NT4 and below */
+ "got %08x\n", r);
+ if (r == S_OK)
+ ok(stat.cbSize.QuadPart == 3, "got %d\n", stat.cbSize.u.LowPart);
+
+ pos.QuadPart = 1;
+ r = IStream_Seek(stm, pos, STREAM_SEEK_SET, &upos);
+ ok(r == S_OK, "got %08x\n", r);
+ ok(upos.QuadPart == 1, "got %d\n", upos.u.LowPart);
+
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
+ ok(r == S_OK ||
+ broken(r == STG_E_INVALIDFUNCTION), /* NT4 and below */
+ "got %08x\n", r);
+ if (r == S_OK)
+ ok(stat.cbSize.QuadPart == 1, "got %d\n", stat.cbSize.u.LowPart);
+
+ IStream_Release(stm);
+
+ r = IStorage_CreateStream(stg, stmname2, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, 0, &stm);
+ ok(r == S_OK, "got %08x\n", r);
+
+ upos.QuadPart = 100;
+ r = IStream_SetSize(stm, upos);
+ ok(r == S_OK, "got %08x\n", r);
+
+ r = IStream_Write(stm, "foo", 3, &count);
+ ok(r == S_OK, "got %08x\n", r);
+ ok(count == 3, "got %d\n", count);
+
+ IStream_Release(stm);
+
+ IStorage_Commit(stg, STGC_DEFAULT);
+ IStorage_Release(stg);
+
+ r = StgOpenStorage( filename, NULL, STGM_SIMPLE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg);
+ if (r == STG_E_INVALIDFLAG)
+ {
+ win_skip("Flag combination is not supported on NT4 and below\n");
+ DeleteFileA(filenameA);
+ return;
+ }
+ ok(r == S_OK, "got %08x\n", r);
+
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg2);
+ ok(r == STG_E_INVALIDFUNCTION, "got %08x\n", r);
+ if (SUCCEEDED(r)) IStorage_Release(stg2);
+
+ r = IStorage_OpenStream(stg, stmname, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
+ ok(r == S_OK, "got %08x\n", r);
+
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
+ ok(r == S_OK, "got %08x\n", r);
+ ok(stat.cbSize.QuadPart == 6000, "got %d\n", stat.cbSize.u.LowPart);
+
+ IStream_Release(stm);
+
+ r = IStorage_OpenStream(stg, stmname2, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stm);
+ ok(r == S_OK, "got %08x\n", r);
+
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
+ ok(r == S_OK, "got %08x\n", r);
+ ok(stat.cbSize.QuadPart == 4096, "got %d\n", stat.cbSize.u.LowPart);
+
+ IStream_Release(stm);
+
+
+ IStorage_Release(stg);
+
+ DeleteFileA(filenameA);
+}
+
+static void test_fmtusertypestg(void)
+{
+ IStorage *stg;
+ IEnumSTATSTG *stat;
+ HRESULT hr;
+ static const char fileA[] = {'f','m','t','t','e','s','t',0};
+ static const WCHAR fileW[] = {'f','m','t','t','e','s','t',0};
+ static WCHAR userTypeW[] = {'S','t','g','U','s','r','T','y','p','e',0};
+ static WCHAR strmNameW[] = {1,'C','o','m','p','O','b','j',0};
+
+ hr = StgCreateDocfile( fileW, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &stg);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+
+ if (SUCCEEDED(hr))
+ {
+ /* try to write the stream */
+ hr = WriteFmtUserTypeStg(stg, 0, userTypeW);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+
+ /* check that the stream was created */
+ hr = IStorage_EnumElements(stg, 0, NULL, 0, &stat);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ BOOL found = FALSE;
+ STATSTG statstg;
+ DWORD got;
+ while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1)
+ {
+ if (strcmp_ww(statstg.pwcsName, strmNameW) == 0)
+ found = TRUE;
+ else
+ ok(0, "found unexpected stream or storage\n");
+ CoTaskMemFree(statstg.pwcsName);
+ }
+ ok(found == TRUE, "expected storage to contain stream \\0001CompObj\n");
+ IEnumSTATSTG_Release(stat);
+ }
+
+ /* re-write the stream */
+ hr = WriteFmtUserTypeStg(stg, 0, userTypeW);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+
+ /* check that the stream is still there */
+ hr = IStorage_EnumElements(stg, 0, NULL, 0, &stat);
+ ok(hr == S_OK, "should succeed, res=%x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ BOOL found = FALSE;
+ STATSTG statstg;
+ DWORD got;
+ while ((hr = IEnumSTATSTG_Next(stat, 1, &statstg, &got)) == S_OK && got == 1)
+ {
+ if (strcmp_ww(statstg.pwcsName, strmNameW) == 0)
+ found = TRUE;
+ else
+ ok(0, "found unexpected stream or storage\n");
+ CoTaskMemFree(statstg.pwcsName);
+ }
+ ok(found == TRUE, "expected storage to contain stream \\0001CompObj\n");
+ IEnumSTATSTG_Release(stat);
}
+
+ IStorage_Release(stg);
+ DeleteFileA( fileA );
}
}
-#define test_file_access(file, ares) _test_file_access(file, ares, __LINE__)
+static void test_references(void)
+{
+ IStorage *stg,*stg2;
+ HRESULT hr;
+ unsigned c1,c2;
+ static const WCHAR StorName[] = { 'D','a','t','a','S','p','a','c','e','I','n','f','o',0 };
-static void test_access(void)
+ DeleteFileA(filenameA);
+
+ hr = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+ ok(hr==S_OK, "StgCreateDocfile failed\n");
+
+ if (SUCCEEDED(hr))
+ {
+ IStorage_Release(stg);
+
+ hr = StgOpenStorage( filename, NULL, STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &stg);
+ ok(hr==S_OK, "StgOpenStorage failed (result=%x)\n",hr);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IStorage_CreateStorage(stg,StorName,STGM_READWRITE | STGM_SHARE_EXCLUSIVE,0,0,&stg2);
+ ok(hr == S_OK, "IStorage_CreateStorage failed (result=%x)\n",hr);
+
+ if (SUCCEEDED(hr))
+ {
+ c1 = IStorage_AddRef(stg);
+ ok(c1 == 2, "creating internal storage added references to ancestor\n");
+ c1 = IStorage_AddRef(stg);
+ IStorage_Release(stg2);
+ c2 = IStorage_AddRef(stg) - 1;
+ ok(c1 == c2, "releasing internal storage removed references to ancestor\n");
+ }
+ c1 = IStorage_Release(stg);
+ while ( c1 ) c1 = IStorage_Release(stg);
+ }
+ }
+
+ DeleteFileA(filenameA);
+}
+
+/* dest
+ * |-StorageA
+ * | `StreamA: "StreamA"
+ * |-StorageB
+ * | `StreamB: "StreamB"
+ * `StreamC: "StreamC"
+ */
+static HRESULT create_test_file(IStorage *dest)
{
- IStorage *stg;
+ IStorage *stgA = NULL, *stgB = NULL;
+ IStream *strmA = NULL, *strmB = NULL, *strmC = NULL;
+ const ULONG strmA_name_size = lstrlenW(strmA_name) * sizeof(WCHAR);
+ const ULONG strmB_name_size = lstrlenW(strmB_name) * sizeof(WCHAR);
+ const ULONG strmC_name_size = lstrlenW(strmC_name) * sizeof(WCHAR);
+ ULONG bytes;
HRESULT hr;
- static const WCHAR fileW[] = {'w','i','n','e','t','e','s','t',0};
+ hr = IStorage_CreateStorage(dest, stgA_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stgA);
+ ok(hr == S_OK, "IStorage_CreateStorage failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = IStorage_CreateStream(stgA, strmA_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmA);
+ ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = IStream_Write(strmA, strmA_name, strmA_name_size, &bytes);
+ ok(hr == S_OK && bytes == strmA_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmA_name_size);
+
+ hr = IStorage_CreateStorage(dest, stgB_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stgB);
+ ok(hr == S_OK, "IStorage_CreateStorage failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = IStorage_CreateStream(stgB, strmB_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmB);
+ ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = IStream_Write(strmB, strmB_name, strmB_name_size, &bytes);
+ ok(hr == S_OK && bytes == strmB_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmB_name_size);
+
+ hr = IStorage_CreateStream(dest, strmC_name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &strmC);
+ ok(hr == S_OK, "IStorage_CreateStream failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = IStream_Write(strmC, strmC_name, strmC_name_size, &bytes);
+ ok(hr == S_OK && bytes == strmC_name_size, "IStream_Write failed: 0x%08x, %d of %d bytes written\n", hr, bytes, strmC_name_size);
+
+cleanup:
+ if(strmC)
+ IStream_Release(strmC);
+ if(strmB)
+ IStream_Release(strmB);
+ if(stgB)
+ IStorage_Release(stgB);
+ if(strmA)
+ IStream_Release(strmA);
+ if(stgA)
+ IStorage_Release(stgA);
+
+ return hr;
+}
- /* STGM_TRANSACTED */
+static void test_copyto(void)
+{
+ IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
+ IStream *strm_tmp;
+ WCHAR buf[64];
+ HRESULT hr;
- hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
- STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, &stg);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ /* create & populate file1 */
+ hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = create_test_file(file1);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* create file2 */
+ hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* copy file1 into file2 */
+ hr = IStorage_CopyTo(file1, 0, NULL, NULL, NULL);
+ ok(hr == STG_E_INVALIDPOINTER, "CopyTo should give STG_E_INVALIDPONITER, gave: 0x%08x\n", hr);
+
+ hr = IStorage_CopyTo(file1, 0, NULL, NULL, file2);
+ ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* verify that all of file1 was copied */
+ hr = IStorage_OpenStorage(file2, stgA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ hr = IStorage_OpenStream(stg_tmp, strmA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ memset(buf, 0, sizeof(buf));
+ hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
+ ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ ok(strcmp_ww(buf, strmA_name) == 0,
+ "Expected %s to be read, got %s\n", wine_dbgstr_w(strmA_name), wine_dbgstr_w(buf));
+
+ IStream_Release(strm_tmp);
+ }
- test_file_access("winetest", create);
+ IStorage_Release(stg_tmp);
+ }
- hr = IStorage_Commit(stg, STGC_DEFAULT);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ hr = IStorage_OpenStorage(file2, stgB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
- test_file_access("winetest", create_commit);
+ if(SUCCEEDED(hr)){
+ hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
- IStorage_Release(stg);
+ if(SUCCEEDED(hr)){
+ memset(buf, 0, sizeof(buf));
+ hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
+ ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ ok(strcmp_ww(buf, strmB_name) == 0,
+ "Expected %s to be read, got %s\n", wine_dbgstr_w(strmB_name), wine_dbgstr_w(buf));
- test_file_access("winetest", create_close);
+ IStream_Release(strm_tmp);
+ }
- DeleteFileA("winetest");
+ IStorage_Release(stg_tmp);
+ }
- /* STGM_DIRECT */
+ hr = IStorage_OpenStream(file2, strmC_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
- hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
- STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &stg);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ if(SUCCEEDED(hr)){
+ memset(buf, 0, sizeof(buf));
+ hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
+ ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ ok(strcmp_ww(buf, strmC_name) == 0,
+ "Expected %s to be read, got %s\n", wine_dbgstr_w(strmC_name), wine_dbgstr_w(buf));
- test_file_access("winetest", create);
+ IStream_Release(strm_tmp);
+ }
- hr = IStorage_Commit(stg, STGC_DEFAULT);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+cleanup:
+ if(file1)
+ IStorage_Release(file1);
+ if(file2)
+ IStorage_Release(file2);
- test_file_access("winetest", create_commit);
+ DeleteFileA(file1_nameA);
+ DeleteFileA(file2_nameA);
+}
- IStorage_Release(stg);
+static void test_copyto_snbexclusions(void)
+{
+ static const WCHAR *snb_exclude[] = {stgA_name, strmB_name, strmC_name, 0};
- test_file_access("winetest", create_close);
+ IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
+ IStream *strm_tmp;
+ WCHAR buf[64];
+ HRESULT hr;
- DeleteFileA("winetest");
+ /* create & populate file1 */
+ hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = create_test_file(file1);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* create file2 */
+ hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* copy file1 to file2 with name exclusions */
+ hr = IStorage_CopyTo(file1, 0, NULL, (SNB)snb_exclude, file2);
+ ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* verify that file1 copied over, respecting exclusions */
+ hr = IStorage_OpenStorage(file2, stgA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStorage_Release(stg_tmp);
+
+ hr = IStorage_OpenStream(file2, strmA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
+
+ hr = IStorage_OpenStorage(file2, stgB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ memset(buf, 0, sizeof(buf));
+ hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
+ ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ ok(strcmp_ww(buf, strmB_name) == 0,
+ "Expected %s to be read, got %s\n", wine_dbgstr_w(strmB_name), wine_dbgstr_w(buf));
+
+ IStream_Release(strm_tmp);
+ }
- /* STGM_SHARE_DENY_NONE */
+ IStorage_Release(stg_tmp);
+ }
- hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
- STGM_SHARE_DENY_NONE | STGM_TRANSACTED, 0, &stg);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ hr = IStorage_OpenStream(file2, strmC_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
- test_file_access("winetest", create);
+cleanup:
+ if(file1)
+ IStorage_Release(file1);
+ if(file2)
+ IStorage_Release(file2);
- hr = IStorage_Commit(stg, STGC_DEFAULT);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ DeleteFileA(file1_nameA);
+ DeleteFileA(file2_nameA);
+}
- test_file_access("winetest", create_commit);
+static void test_copyto_iidexclusions_storage(void)
+{
+ IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
+ IStream *strm_tmp;
+ WCHAR buf[64];
+ HRESULT hr;
+
+ /* create & populate file1 */
+ hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = create_test_file(file1);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* create file2 */
+ hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* copy file1 to file2 with iid exclusions */
+ hr = IStorage_CopyTo(file1, 1, &IID_IStorage, NULL, file2);
+ ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* verify that file1 copied over, respecting exclusions */
+ hr = IStorage_OpenStorage(file2, stgA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStorage_Release(stg_tmp);
+
+ hr = IStorage_OpenStream(file2, strmA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
+
+ hr = IStorage_OpenStorage(file2, stgB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStorage should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStorage_Release(stg_tmp);
+
+ hr = IStorage_OpenStream(file2, strmB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
+
+ hr = IStorage_OpenStream(file2, strmC_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == S_OK, "OpenStream failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ memset(buf, 0, sizeof(buf));
+ hr = IStream_Read(strm_tmp, buf, sizeof(buf), NULL);
+ ok(hr == S_OK, "Read failed: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ ok(strcmp_ww(buf, strmC_name) == 0,
+ "Expected %s to be read, got %s\n", wine_dbgstr_w(strmC_name), wine_dbgstr_w(buf));
+
+ IStream_Release(strm_tmp);
+ }
+
+cleanup:
+ if(file1)
+ IStorage_Release(file1);
+ if(file2)
+ IStorage_Release(file2);
+
+ DeleteFileA(file1_nameA);
+ DeleteFileA(file2_nameA);
+}
+
+static void test_copyto_iidexclusions_stream(void)
+{
+ IStorage *file1 = NULL, *file2 = NULL, *stg_tmp;
+ IStream *strm_tmp;
+ HRESULT hr;
+
+ /* create & populate file1 */
+ hr = StgCreateDocfile(file1_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file1);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ hr = create_test_file(file1);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* create file2 */
+ hr = StgCreateDocfile(file2_name, STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE, 0, &file2);
+ ok(hr == S_OK, "StgCreateDocfile failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* copy file1 to file2 with iid exclusions */
+ hr = IStorage_CopyTo(file1, 1, &IID_IStream, NULL, file2);
+ ok(hr == S_OK, "CopyTo failed: 0x%08x\n", hr);
+ if(FAILED(hr))
+ goto cleanup;
+
+ /* verify that file1 copied over, respecting exclusions */
+ hr = IStorage_OpenStorage(file2, stgA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ hr = IStorage_OpenStream(stg_tmp, strmA_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
+
+ IStorage_Release(stg_tmp);
+ }
+
+ hr = IStorage_OpenStorage(file2, stgB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg_tmp);
+ ok(hr == S_OK, "OpenStorage failed: 0x%08x\n", hr);
+
+ if(SUCCEEDED(hr)){
+ hr = IStorage_OpenStream(stg_tmp, strmB_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
+
+ IStorage_Release(stg_tmp);
+ }
+
+ hr = IStorage_OpenStream(file2, strmC_name, NULL,
+ STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &strm_tmp);
+ ok(hr == STG_E_FILENOTFOUND, "OpenStream should give STG_E_FILENOTFOUND, gave: 0x%08x\n", hr);
+ if(SUCCEEDED(hr))
+ IStream_Release(strm_tmp);
+
+cleanup:
+ if(file1)
+ IStorage_Release(file1);
+ if(file2)
+ IStorage_Release(file2);
+
+ DeleteFileA(file1_nameA);
+ DeleteFileA(file2_nameA);
+}
+
+static void test_rename(void)
+{
+ IStorage *stg, *stg2;
+ IStream *stm;
+ HRESULT r;
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+ static const WCHAR stgname2[] = { 'S','T','G',0 };
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
+ static const WCHAR stmname2[] = { 'E','N','T','S',0 };
+
+ DeleteFileA(filenameA);
+
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* create a substorage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ /* create a stream in the substorage */
+ r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
+ IStream_Release(stm);
+
+ /* rename the stream */
+ r = IStorage_RenameElement(stg2, stmname, stmname2);
+ ok(r==S_OK, "IStorage->RenameElement failed, hr=%08x\n", r);
+
+ /* cannot open stream with old name */
+ r = IStorage_OpenStream(stg2, stmname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
+ ok(r==STG_E_FILENOTFOUND, "IStorage_OpenStream should fail, hr=%08x\n", r);
+ if (SUCCEEDED(r)) IStream_Release(stm);
+
+ /* can open stream with new name */
+ r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
+ ok(r==S_OK, "IStorage_OpenStream failed, hr=%08x\n", r);
+ if (SUCCEEDED(r)) IStream_Release(stm);
+
+ IStorage_Release(stg2);
+
+ /* rename the storage */
+ IStorage_RenameElement(stg, stgname, stgname2);
+
+ /* cannot open storage with old name */
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg2);
+ ok(r==STG_E_FILENOTFOUND, "IStorage_OpenStream should fail, hr=%08x\n", r);
+ if (SUCCEEDED(r)) IStorage_Release(stg2);
+
+ /* can open storage with new name */
+ r = IStorage_OpenStorage(stg, stgname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &stg2);
+ ok(r==S_OK, "IStorage_OpenStream should fail, hr=%08x\n", r);
+ if (SUCCEEDED(r))
+ {
+ /* opened storage still has the stream */
+ r = IStorage_OpenStream(stg2, stmname2, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
+ ok(r==S_OK, "IStorage_OpenStream failed, hr=%08x\n", r);
+ if (SUCCEEDED(r)) IStream_Release(stm);
+
+ IStorage_Release(stg2);
+ }
IStorage_Release(stg);
- test_file_access("winetest", create_close);
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
- DeleteFileA("winetest");
+static void test_toplevel_stat(void)
+{
+ IStorage *stg = NULL;
+ HRESULT r;
+ STATSTG stat;
+ char prev_dir[MAX_PATH];
+ char temp[MAX_PATH];
+ char full_path[MAX_PATH];
+ LPSTR rel_pathA;
+ WCHAR rel_path[MAX_PATH];
- /* STGM_SHARE_DENY_READ */
+ DeleteFileA(filenameA);
- hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
- STGM_SHARE_DENY_READ | STGM_TRANSACTED, 0, &stg);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
- test_file_access("winetest", create);
+ r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
+ ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
+ wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
- hr = IStorage_Commit(stg, STGC_DEFAULT);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ IStorage_Release( stg );
- test_file_access("winetest", create_commit);
+ r = StgOpenStorage( filename, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
+ ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
+
+ r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
+ ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
+ wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+
+ IStorage_Release( stg );
+
+ DeleteFileA(filenameA);
+
+ /* Stat always returns the full path, even for files opened with a relative path. */
+ GetCurrentDirectoryA(MAX_PATH, prev_dir);
+
+ GetTempPathA(MAX_PATH, temp);
+
+ SetCurrentDirectoryA(temp);
+
+ GetFullPathNameA(filenameA, MAX_PATH, full_path, &rel_pathA);
+ MultiByteToWideChar(CP_ACP, 0, rel_pathA, -1, rel_path, MAX_PATH);
+
+ r = StgCreateDocfile( rel_path, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE |STGM_TRANSACTED, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
+ ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
+ wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+
+ IStorage_Release( stg );
+
+ r = StgOpenStorage( rel_path, NULL, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, NULL, 0, &stg);
+ ok(r==S_OK, "StgOpenStorage failed with error 0x%08x\n", r);
+
+ r = IStorage_Stat( stg, &stat, STATFLAG_DEFAULT );
+ ok(!strcmp_ww(stat.pwcsName, filename), "expected %s, got %s\n",
+ wine_dbgstr_w(filename), wine_dbgstr_w(stat.pwcsName));
+ CoTaskMemFree(stat.pwcsName);
+
+ IStorage_Release( stg );
+
+ SetCurrentDirectoryA(prev_dir);
+
+ DeleteFileA(filenameA);
+}
+
+static void test_substorage_enum(void)
+{
+ IStorage *stg, *stg2;
+ IEnumSTATSTG *ee;
+ HRESULT r;
+ ULONG ref;
+ static const WCHAR stgname[] = { 'P','E','R','M','S','T','G',0 };
+
+ DeleteFileA(filenameA);
+
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* create a substorage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ /* create an enumelements */
+ r = IStorage_EnumElements(stg2, 0, NULL, 0, &ee);
+ ok(r==S_OK, "IStorage->EnumElements failed, hr=%08x\n", r);
+
+ /* release the substorage */
+ ref = IStorage_Release(stg2);
+ todo_wine ok(ref==0, "storage not released\n");
+
+ /* reopening fails, because the substorage is really still open */
+ r = IStorage_OpenStorage(stg, stgname, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->OpenStorage failed, hr=%08x\n", r);
+
+ /* destroying the storage invalidates the enumerator */
+ r = IStorage_DestroyElement(stg, stgname);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ r = IEnumSTATSTG_Reset(ee);
+ ok(r==STG_E_REVERTED, "IEnumSTATSTG->Reset failed, hr=%08x\n", r);
+
+ IEnumSTATSTG_Release(ee);
IStorage_Release(stg);
- test_file_access("winetest", create_close);
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
- DeleteFileA("winetest");
+static void test_copyto_locking(void)
+{
+ IStorage *stg, *stg2, *stg3, *stg4;
+ IStream *stm;
+ HRESULT r;
+ static const WCHAR stgname[] = { 'S','T','G','1',0 };
+ static const WCHAR stgname2[] = { 'S','T','G','2',0 };
+ static const WCHAR stmname[] = { 'C','O','N','T','E','N','T','S',0 };
- /* STGM_SHARE_DENY_WRITE */
+ DeleteFileA(filenameA);
- hr = StgCreateDocfile(fileW, STGM_CREATE | STGM_READWRITE |
- STGM_SHARE_DENY_WRITE | STGM_TRANSACTED, 0, &stg);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
- test_file_access("winetest", create);
+ /* create a substorage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
- hr = IStorage_Commit(stg, STGC_DEFAULT);
- ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
+ /* create another substorage */
+ r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
- test_file_access("winetest", create_commit);
+ /* add a stream, and leave it open */
+ r = IStorage_CreateStream(stg2, stmname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ ok(r==S_OK, "IStorage->CreateStream failed, hr=%08x\n", r);
+ /* Try to copy the storage while the stream is open */
+ r = IStorage_CopyTo(stg2, 0, NULL, NULL, stg3);
+ todo_wine ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
+
+ IStream_Release(stm);
+
+ /* create a substorage */
+ r = IStorage_CreateStorage(stg2, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg4);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ /* Try to copy the storage while the substorage is open */
+ r = IStorage_CopyTo(stg2, 0, NULL, NULL, stg3);
+ todo_wine ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
+
+ IStorage_Release(stg4);
+ IStorage_Release(stg3);
+ IStorage_Release(stg2);
IStorage_Release(stg);
- test_file_access("winetest", create_close);
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
+}
- DeleteFileA("winetest");
+static void test_copyto_recursive(void)
+{
+ IStorage *stg, *stg2, *stg3, *stg4;
+ HRESULT r;
+ static const WCHAR stgname[] = { 'S','T','G','1',0 };
+ static const WCHAR stgname2[] = { 'S','T','G','2',0 };
+
+ DeleteFileA(filenameA);
+
+ /* create the file */
+ r = StgCreateDocfile( filename, STGM_CREATE | STGM_SHARE_EXCLUSIVE |
+ STGM_READWRITE, 0, &stg);
+ ok(r==S_OK, "StgCreateDocfile failed\n");
+
+ /* create a substorage */
+ r = IStorage_CreateStorage(stg, stgname, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stg2);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ /* copy the parent to the child */
+ r = IStorage_CopyTo(stg, 0, NULL, NULL, stg2);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
+
+ /* create a transacted substorage */
+ r = IStorage_CreateStorage(stg, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg3);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ /* copy the parent to the transacted child */
+ r = IStorage_CopyTo(stg, 0, NULL, NULL, stg2);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
+
+ /* create a transacted subsubstorage */
+ r = IStorage_CreateStorage(stg3, stgname2, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_TRANSACTED, 0, 0, &stg4);
+ ok(r==S_OK, "IStorage->CreateStorage failed, hr=%08x\n", r);
+
+ /* copy the parent to the transacted child of the transacted child */
+ r = IStorage_CopyTo(stg, 0, NULL, NULL, stg4);
+ ok(r==STG_E_ACCESSDENIED, "IStorage->CopyTo failed, hr=%08x\n", r);
+
+ /* copy the parent but exclude storage objects */
+ r = IStorage_CopyTo(stg, 1, &IID_IStorage, NULL, stg4);
+ ok(r==S_OK, "IStorage->CopyTo failed, hr=%08x\n", r);
+
+ IStorage_Release(stg4);
+ IStorage_Release(stg3);
+ IStorage_Release(stg2);
+ IStorage_Release(stg);
+
+ r = DeleteFileA(filenameA);
+ ok( r == TRUE, "deleted file\n");
}
START_TEST(storage32)
{
+ CHAR temp[MAX_PATH];
+
+ GetTempPathA(MAX_PATH, temp);
+ if(!GetTempFileNameA(temp, "stg", 0, filenameA))
+ {
+ win_skip("Could not create temp file, %u\n", GetLastError());
+ return;
+ }
+ MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filename, MAX_PATH);
+ DeleteFileA(filenameA);
+
test_hglobal_storage_stat();
test_create_storage_modes();
test_storage_stream();
test_storage_refcount();
test_streamenum();
test_transact();
+ test_substorage_share();
+ test_revert();
+ test_parent_free();
+ test_nonroot_transacted();
test_ReadClassStm();
test_access();
test_writeclassstg();
+ test_readonly();
+ test_simple();
+ test_fmtusertypestg();
+ test_references();
+ test_copyto();
+ test_copyto_snbexclusions();
+ test_copyto_iidexclusions_storage();
+ test_copyto_iidexclusions_stream();
+ test_rename();
+ test_toplevel_stat();
+ test_substorage_enum();
+ test_copyto_locking();
+ test_copyto_recursive();
}