diff --git a/dlls/ole32/filemoniker.c b/dlls/ole32/filemoniker.c index e9fd4cacfe9..9decfaf124d 100644 --- a/dlls/ole32/filemoniker.c +++ b/dlls/ole32/filemoniker.c @@ -198,9 +198,9 @@ FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) TRACE("(%p,%p)\n",iface,pStm); - /* first WORD must be 0 */ + /* first WORD */ res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); - if (bread!=sizeof(WORD) || wbuffer!=0) + if (bread!=sizeof(WORD)) { WARN("Couldn't read 0 word\n"); goto fail; @@ -229,18 +229,26 @@ FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) goto fail; } - /* read the first constant */ - IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF) + /* read the unknown value */ + IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread != sizeof(WORD)) { - WARN("Couldn't read 0xDEADFFFF constant\n"); + WARN("Couldn't read unknown value\n"); + goto fail; + } + + /* read the DEAD constant */ + IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread != sizeof(WORD)) + { + WARN("Couldn't read DEAD constant\n"); goto fail; } for(i=0;i<5;i++) { res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread!=sizeof(DWORD) || dwbuffer!=0) + if (bread!=sizeof(DWORD)) { WARN("Couldn't read 0 padding\n"); goto fail; @@ -320,18 +328,20 @@ FileMonikerImpl_Load(IMoniker* iface, IStream* pStm) * of Windows have minor variations. * * Data which must be written on stream is: - * 1) WORD constant:zero + * 1) WORD constant: zero (not validated by Windows) * 2) length of the path string ("\0" included) * 3) path string type A - * 4) DWORD constant : 0xDEADFFFF - * 5) five DWORD constant: zero - * 6) If we're only writing the multibyte version, + * 4) Unknown WORD value: Frequently 0xFFFF, but not always. If set very large, + * Windows returns E_OUTOFMEMORY + * 5) WORD Constant: 0xDEAD (not validated by Windows) + * 6) five DWORD constant: zero (not validated by Windows) + * 7) If we're only writing the multibyte version, * write a zero DWORD and finish. * - * 7) DWORD: double-length of the path string type W ("\0" not + * 8) DWORD: double-length of the path string type W ("\0" not * included) - * 8) WORD constant: 0x3 - * 9) filePath unicode string. + * 9) WORD constant: 0x3 + * 10) filePath unicode string. * */ static HRESULT WINAPI @@ -344,7 +354,8 @@ FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) CHAR* filePathA; DWORD bytesA, bytesW, len; - static const DWORD DEADFFFF = 0xDEADFFFF; /* Constants */ + static const WORD FFFF = 0xFFFF; /* Constants */ + static const WORD DEAD = 0xDEAD; static const DWORD ZERO = 0; static const WORD THREE = 0x3; @@ -374,8 +385,12 @@ FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) HeapFree(GetProcessHeap(),0,filePathA); if (FAILED(res)) return res; - /* write a DWORD 0xDEADFFFF */ - res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL); + /* write a WORD 0xFFFF */ + res=IStream_Write(pStm,&FFFF,sizeof(WORD),NULL); + if (FAILED(res)) return res; + + /* write a WORD 0xDEAD */ + res=IStream_Write(pStm,&DEAD,sizeof(WORD),NULL); if (FAILED(res)) return res; /* write 5 zero DWORDs */ diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c index b17237771e8..d27f766baba 100644 --- a/dlls/ole32/tests/moniker.c +++ b/dlls/ole32/tests/moniker.c @@ -1867,6 +1867,75 @@ static void test_bind_context(void) ok(!refs, "bound object should have been destroyed, instead of having %d refs\n", refs); } +static void test_save_load_filemoniker(void) +{ + IMoniker* pMk; + IStream* pStm; + HRESULT hr; + ULARGE_INTEGER size; + LARGE_INTEGER zero_pos, dead_pos, nulls_pos; + DWORD some_val = 0xFEDCBA98; + int i; + + /* see FileMonikerImpl_Save docs */ + zero_pos.u.LowPart = 0; + dead_pos.u.LowPart = sizeof(WORD) + sizeof(DWORD) + (lstrlenW(wszFileName1) + 1) + sizeof(WORD); + nulls_pos.u.LowPart = dead_pos.u.LowPart + sizeof(WORD); + + /* create the stream we're going to write to */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm); + ok_ole_success(hr, "CreateStreamOnHGlobal"); + + size.u.LowPart = 128; + hr = IStream_SetSize(pStm, size); + ok_ole_success(hr, "IStream_SetSize"); + + /* create and save a moniker */ + hr = CreateFileMoniker(wszFileName1, &pMk); + ok_ole_success(hr, "CreateFileMoniker"); + + hr = IMoniker_Save(pMk, pStm, TRUE); + ok_ole_success(hr, "IMoniker_Save"); + + hr = IMoniker_Release(pMk); + ok_ole_success(hr, "IMoniker_Release"); + + /* overwrite the constants with various values */ + hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, "IStream_Seek"); + hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL); + ok_ole_success(hr, "IStream_Write"); + + hr = IStream_Seek(pStm, dead_pos, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, "IStream_Seek"); + hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL); + ok_ole_success(hr, "IStream_Write"); + + hr = IStream_Seek(pStm, nulls_pos, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, "IStream_Seek"); + for(i = 0; i < 5; ++i){ + hr = IStream_Write(pStm, &some_val, sizeof(DWORD), NULL); + ok_ole_success(hr, "IStream_Write"); + } + + /* go back to the start of the stream */ + hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL); + ok_ole_success(hr, "IStream_Seek"); + + /* create a new moniker and load into it */ + hr = CreateFileMoniker(wszFileName1, &pMk); + ok_ole_success(hr, "CreateFileMoniker"); + + hr = IMoniker_Load(pMk, pStm); + ok_ole_success(hr, "IMoniker_Load"); + + hr = IMoniker_Release(pMk); + ok_ole_success(hr, "IMoniker_Release"); + + hr = IStream_Release(pStm); + ok_ole_success(hr, "IStream_Release"); +} + START_TEST(moniker) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); @@ -1880,6 +1949,7 @@ START_TEST(moniker) test_anti_moniker(); test_generic_composite_moniker(); test_pointer_moniker(); + test_save_load_filemoniker(); /* FIXME: test moniker creation funcs and parsing other moniker formats */