From: Jactry Zeng Subject: [PATCH v6 1/3] mfplat: Implement MFCreateFile(). Message-Id: <73f67689-1bf7-a8f0-9f49-846434afde57@codeweavers.com> Date: Tue, 12 Feb 2019 16:23:49 +0800 Superseded patch 157963 to 157965. ChangeLog: v6: - Add broken() for test results on Windows XP and Vista.(Thanks Sven!) - Cache length in bytestream by itself and improve IMFByteStream::GetLength() to follow behavior on Windows 7. v5: - Fix crash when calling MFCreateMFByteStreamOnStream() on Windows. v4: - Fix test failure on Windows XP and Vista. Signed-off-by: Jactry Zeng --- dlls/mfplat/Makefile.in | 2 +- dlls/mfplat/main.c | 69 +++++++++++++++----------- dlls/mfplat/tests/mfplat.c | 99 +++++++++++++++++++++++++++++++++----- 3 files changed, 127 insertions(+), 43 deletions(-) diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in index 76843f5f25..5d9c8eb4c6 100644 --- a/dlls/mfplat/Makefile.in +++ b/dlls/mfplat/Makefile.in @@ -1,6 +1,6 @@ MODULE = mfplat.dll IMPORTLIB = mfplat -IMPORTS = advapi32 ole32 +IMPORTS = advapi32 ole32 shlwapi C_SRCS = \ main.c diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index c7c346512f..ff559e6667 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -31,6 +31,7 @@ #include "mfapi.h" #include "mfidl.h" #include "mferror.h" +#include "shlwapi.h" #include "wine/heap.h" #include "wine/debug.h" @@ -849,6 +850,7 @@ typedef struct _mfbytestream { mfattributes attributes; IMFByteStream IMFByteStream_iface; + IStream *stream; } mfbytestream; static inline mfbytestream *impl_from_IMFByteStream(IMFByteStream *iface) @@ -901,6 +903,7 @@ static ULONG WINAPI mfbytestream_Release(IMFByteStream *iface) if (!ref) { + IStream_Release(This->stream); HeapFree(GetProcessHeap(), 0, This); } @@ -1144,6 +1147,8 @@ HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **byt init_attribute_object(&object->attributes, 0); object->IMFByteStream_iface.lpVtbl = &mfbytestream_vtbl; object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl; + object->stream = stream; + IStream_AddRef(object->stream); *bytestream = &object->IMFByteStream_iface; @@ -1154,60 +1159,65 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open LPCWSTR url, IMFByteStream **bytestream) { mfbytestream *object; - DWORD fileaccessmode = 0; - DWORD filesharemode = FILE_SHARE_READ; - DWORD filecreation_disposition = 0; - DWORD fileattributes = 0; - HANDLE file; + DWORD mode = STGM_SHARE_DENY_WRITE; + DWORD attributes = FILE_ATTRIBUTE_NORMAL; + BOOL create = FALSE, reset = FALSE; + IStream *stream = NULL; + HRESULT hres; - FIXME("(%d, %d, %d, %s, %p): stub\n", accessmode, openmode, flags, debugstr_w(url), bytestream); + TRACE("(%d, %d, %d, %s, %p)\n", accessmode, openmode, flags, debugstr_w(url), bytestream); switch (accessmode) { case MF_ACCESSMODE_READ: - fileaccessmode = GENERIC_READ; + mode |= STGM_READ; break; case MF_ACCESSMODE_WRITE: - fileaccessmode = GENERIC_WRITE; + mode |= STGM_WRITE; break; case MF_ACCESSMODE_READWRITE: - fileaccessmode = GENERIC_READ | GENERIC_WRITE; + mode |= STGM_READWRITE; break; } switch (openmode) { - case MF_OPENMODE_FAIL_IF_NOT_EXIST: - filecreation_disposition = OPEN_EXISTING; - break; - case MF_OPENMODE_FAIL_IF_EXIST: - filecreation_disposition = CREATE_NEW; - break; case MF_OPENMODE_RESET_IF_EXIST: - filecreation_disposition = TRUNCATE_EXISTING; + if (accessmode == MF_ACCESSMODE_READ) + return E_INVALIDARG; + reset = TRUE; + mode |= STGM_FAILIFTHERE; break; case MF_OPENMODE_APPEND_IF_EXIST: - filecreation_disposition = OPEN_ALWAYS; - fileaccessmode |= FILE_APPEND_DATA; + if (GetFileAttributesW(url) == INVALID_FILE_ATTRIBUTES) + create = TRUE; + case MF_OPENMODE_FAIL_IF_NOT_EXIST: + mode |= STGM_FAILIFTHERE; + break; + case MF_OPENMODE_FAIL_IF_EXIST: + mode |= STGM_FAILIFTHERE; + create = TRUE; break; case MF_OPENMODE_DELETE_IF_EXIST: - filecreation_disposition = CREATE_ALWAYS; + mode |= STGM_CREATE; break; } if (flags & MF_FILEFLAGS_NOBUFFERING) - fileattributes |= FILE_FLAG_NO_BUFFERING; - - /* Open HANDLE to file */ - file = CreateFileW(url, fileaccessmode, filesharemode, NULL, - filecreation_disposition, fileattributes, 0); - - if(file == INVALID_HANDLE_VALUE) - return HRESULT_FROM_WIN32(GetLastError()); + attributes |= FILE_FLAG_NO_BUFFERING; + if ((flags & MF_FILEFLAGS_ALLOW_WRITE_SHARING) && (accessmode == MF_ACCESSMODE_READ)) + mode &= ~STGM_SHARE_DENY_WRITE; - /* Close the file again, since we don't do anything with it yet */ - CloseHandle(file); + hres = SHCreateStreamOnFileEx(url, mode, attributes, create, NULL, &stream); + if (FAILED(hres)) + return hres; + if (reset) + { + ULARGE_INTEGER zero; + zero.QuadPart = 0; + IStream_SetSize(stream, zero); + } object = heap_alloc( sizeof(*object) ); if(!object) return E_OUTOFMEMORY; @@ -1215,6 +1225,7 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open init_attribute_object(&object->attributes, 0); object->IMFByteStream_iface.lpVtbl = &mfbytestream_vtbl; object->attributes.IMFAttributes_iface.lpVtbl = &mfbytestream_attributes_vtbl; + object->stream = stream; *bytestream = &object->IMFByteStream_iface; diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 3fa59f4816..3c39be6ea9 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -54,6 +54,48 @@ DEFINE_GUID(DUMMY_GUID2, 0x12345678,0x1234,0x1234,0x22,0x22,0x22,0x22,0x22,0x22, static const WCHAR mp4file[] = {'t','e','s','t','.','m','p','4',0}; +#define CHECK_REF(obj,ref) _check_ref((IUnknown*)obj, ref, __LINE__) +static void _check_ref(IUnknown* obj, ULONG ref, int line) +{ + ULONG rc; + IUnknown_AddRef(obj); + rc = IUnknown_Release(obj); + ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc); +} + +#define CHECK_BS_POS(obj,pos) _check_bs_pos(obj, pos, __LINE__) +static void _check_bs_pos(IMFByteStream* obj, QWORD pos, int line) +{ + QWORD position = 0xdeadbeef; + HRESULT hr; + hr = IMFByteStream_GetCurrentPosition(obj, &position); + ok_(__FILE__,line)(hr == S_OK, "IMFByteStream_GetCurrentPosition failed: 0x%08x.\n", hr); + ok_(__FILE__,line)(position == pos, "got wrong position: %s.\n", + wine_dbgstr_longlong(position)); +} + +#define CHECK_BS_LEN(obj,len) _check_bs_len(obj, len, __LINE__) +static void _check_bs_len(IMFByteStream* obj, QWORD len, int line) +{ + QWORD length = 0xdeadbeef; + HRESULT hr; + hr = IMFByteStream_GetLength(obj, &length); + ok_(__FILE__,line)(hr == S_OK, "IMFByteStream_GetLength failed: 0x%08x.\n", hr); + ok_(__FILE__,line)(length == len, "got wrong length: %s.\n", + wine_dbgstr_longlong(length)); +} + +#define CHECK_FILE_SIZE(filename,exp_size) _check_file_size(filename, exp_size, __LINE__) +static void _check_file_size(const WCHAR *filename, LONG exp_size, int line) +{ + HANDLE handle; + DWORD file_size = 0xdeadbeef; + handle = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + file_size = GetFileSize(handle, NULL); + ok_(__FILE__,line)(file_size == exp_size, "got wrong file size: %d.\n", file_size); + CloseHandle(handle); +} + static WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; @@ -450,8 +492,10 @@ static void test_MFCreateMFByteStreamOnStream(void) hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); ok(hr == S_OK, "got 0x%08x\n", hr); + CHECK_REF(stream, 1); hr = pMFCreateMFByteStreamOnStream(stream, &bytestream); ok(hr == S_OK, "got 0x%08x\n", hr); + CHECK_REF(stream, 2); hr = IMFByteStream_QueryInterface(bytestream, &IID_IUnknown, (void **)&unknown); @@ -509,7 +553,8 @@ static void test_MFCreateFile(void) IMFAttributes *attributes = NULL; HRESULT hr; WCHAR *filename; - + LONG file_size; + HANDLE handle; static const WCHAR newfilename[] = {'n','e','w','.','m','p','4',0}; filename = load_resource(mp4file); @@ -534,13 +579,11 @@ static void test_MFCreateFile(void) hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &bytestream2); - todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); - if (hr == S_OK) IMFByteStream_Release(bytestream2); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); hr = MFCreateFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &bytestream2); - todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); - if (hr == S_OK) IMFByteStream_Release(bytestream2); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); IMFByteStream_Release(bytestream); @@ -558,18 +601,15 @@ static void test_MFCreateFile(void) hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, newfilename, &bytestream2); - todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); - if (hr == S_OK) IMFByteStream_Release(bytestream2); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, newfilename, &bytestream2); - todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); - if (hr == S_OK) IMFByteStream_Release(bytestream2); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_ALLOW_WRITE_SHARING, newfilename, &bytestream2); - todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); - if (hr == S_OK) IMFByteStream_Release(bytestream2); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); IMFByteStream_Release(bytestream); @@ -580,10 +620,43 @@ static void test_MFCreateFile(void) /* Opening the file again fails even though MF_FILEFLAGS_ALLOW_WRITE_SHARING is set. */ hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_ALLOW_WRITE_SHARING, newfilename, &bytestream2); - todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); - if (hr == S_OK) IMFByteStream_Release(bytestream2); + ok(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), "got 0x%08x\n", hr); + hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, + MF_FILEFLAGS_ALLOW_WRITE_SHARING, newfilename, &bytestream2); + ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION)) /* xp and vista */, + "MFCreateFile failed: 0x%08x.\n", hr); + if(hr == S_OK) + IMFByteStream_Release(bytestream2); + IMFByteStream_Release(bytestream); + + /* test MF_OPENMODE_APPEND_IF_EXIST */ + handle = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(handle != INVALID_HANDLE_VALUE, "File creation failed: 0x%08x.\n", GetLastError()); + file_size = GetFileSize(handle, NULL); + CloseHandle(handle); + hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_APPEND_IF_EXIST, + MF_FILEFLAGS_ALLOW_WRITE_SHARING, filename, &bytestream); + ok(hr == S_OK, "MFCreateFile failed: 0x%08x.\n", hr); + todo_wine CHECK_BS_LEN(bytestream, file_size); + todo_wine CHECK_BS_POS(bytestream, 0); + IMFByteStream_Release(bytestream); + CHECK_FILE_SIZE(filename, file_size); + + /* test MF_OPENMODE_RESET_IF_EXIST with read-only mode */ + hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_RESET_IF_EXIST, + MF_FILEFLAGS_ALLOW_WRITE_SHARING, filename, &bytestream); + ok(hr == E_INVALIDARG, "MFCreateFile should fail: 0x%08x.\n", hr); + CHECK_FILE_SIZE(filename, file_size); + + /* test MF_OPENMODE_RESET_IF_EXIST */ + hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_RESET_IF_EXIST, + MF_FILEFLAGS_NONE, filename, &bytestream); + ok(hr == S_OK, "MFCreateFile failed: 0x%08x.\n", hr); + todo_wine CHECK_BS_LEN(bytestream, 0); + todo_wine CHECK_BS_POS(bytestream, 0); IMFByteStream_Release(bytestream); + CHECK_FILE_SIZE(filename, 0); MFShutdown(); -- 2.20.1