Wine-Devel
Threads by month
- ----- 2026 -----
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 5 participants
- 84534 discussions
[PATCH v3] gdi32: Fail in ExtTextOut if count is larger than INT_MAX.
by Gabriel Ivăncescu Feb. 3, 2021
by Gabriel Ivăncescu Feb. 3, 2021
Feb. 3, 2021
Some applications pass values like -1 and crash when BIDI_Reorder can't
allocate the memory.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/gdi32/font.c | 3 ++
dlls/gdi32/tests/dib.c | 15 ++++++++-
dlls/gdi32/tests/font.c | 2 ++
dlls/gdi32/tests/metafile.c | 61 ++++++++++++++++++++++++++++++++++++-
4 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 74ca482..de50bf0 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -5823,6 +5823,8 @@ BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
BOOL ret;
LPINT lpDxW = NULL;
+ if (count > INT_MAX) return FALSE;
+
if (flags & ETO_GLYPH_INDEX)
return ExtTextOutW( hdc, x, y, flags, lprect, (LPCWSTR)str, count, lpDx );
@@ -5932,6 +5934,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
static int quietfixme = 0;
if (!dc) return FALSE;
+ if (count > INT_MAX) return FALSE;
align = dc->textAlign;
breakRem = dc->breakRem;
diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c
index d16cb0d..bdc3d9e 100644
--- a/dlls/gdi32/tests/dib.c
+++ b/dlls/gdi32/tests/dib.c
@@ -3020,8 +3020,9 @@ static void draw_text_2( HDC hdc, const BITMAPINFO *bmi, BYTE *bits, BOOL aa )
static const char str[] = "Hello Wine";
POINT origin, g_org;
static const BYTE vals[4] = { 0x00, 0x00, 0x00, 0x00 };
+ COLORREF bk_color, text_color;
TEXTMETRICA tm;
- COLORREF text_color;
+ RECT rect;
for(i = 0; i < dib_size; i++)
bits[i] = vals[i % 4];
@@ -3116,6 +3117,18 @@ static void draw_text_2( HDC hdc, const BITMAPINFO *bmi, BYTE *bits, BOOL aa )
diy_hash = hash_dib( hdc, bmi, bits );
ok( !strcmp( eto_hash, diy_hash ), "hash mismatch - aa %d\n", aa );
+ bk_color = GetBkColor( hdc );
+ SetBkColor( hdc, RGB(128,64,32) );
+
+ SetRect( &rect, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight );
+ ret = ExtTextOutA( hdc, 10, 100, ETO_OPAQUE, &rect, str, -1, NULL );
+ ok( !ret, "ExtTextOutA succeeded\n" );
+
+ diy_hash = hash_dib( hdc, bmi, bits );
+ ok( !strcmp( eto_hash, diy_hash ), "hash mismatch - aa %d\n", aa );
+
+ SetBkColor( hdc, bk_color );
+
HeapFree( GetProcessHeap(), 0, diy_hash );
HeapFree( GetProcessHeap(), 0, eto_hash );
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 461eecf..3e1f1e9 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -6916,6 +6916,8 @@ static void test_bitmap_font_glyph_index(void)
hBmpPrev = SelectObject(hdc, hBmp[j]);
switch (j) {
case 0:
+ ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, -1, NULL);
+ ok(!ret, "ExtTextOutW succeeded\n");
ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
break;
case 1:
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index 8dae908..7773faa 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -158,6 +158,28 @@ static int CALLBACK eto_emf_enum_proc(HDC hdc, HANDLETABLE *handle_table,
return 1;
}
+static int CALLBACK eto_emf_enum_proc2(HDC hdc, HANDLETABLE *handle_table,
+ const ENHMETARECORD *emr, int n_objs, LPARAM param)
+{
+ if (!hdc) return 1;
+
+ switch (emr->iType)
+ {
+ case EMR_HEADER:
+ case EMR_LINETO:
+ emr_processed = TRUE;
+ break;
+ case EMR_EXTTEXTOUTA:
+ case EMR_EXTTEXTOUTW:
+ ok(0, "Unexpected ExtTextOut record\n");
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
static void test_ExtTextOut(void)
{
HWND hwnd;
@@ -222,7 +244,13 @@ static void test_ExtTextOut(void)
ret = ExtTextOutA(hdcMetafile, 0, 40, 0, NULL, text, lstrlenA(text), NULL);
ok( ret, "ExtTextOutA error %d\n", GetLastError());
- /* 4. test with unmatched BeginPath/EndPath calls */
+ /* 4. pass -1 to length */
+ SetLastError(0xdeadbeef);
+ ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, -1, NULL);
+ ok( !ret, "ExtTextOutA succeeded\n");
+ ok( GetLastError() == 0xdeadbeef, "ExtTextOutA error %d\n", GetLastError());
+
+ /* 5. test with unmatched BeginPath/EndPath calls */
ret = BeginPath(hdcMetafile);
ok( ret, "BeginPath error %d\n", GetLastError());
ret = BeginPath(hdcMetafile);
@@ -275,6 +303,37 @@ static void test_ExtTextOut(void)
ok(EnumEnhMetaFile(NULL, hMetafile, eto_emf_enum_proc, dx, NULL),
"A null hdc does not require a valid rc\n");
+ ret = DeleteEnhMetaFile(hMetafile);
+ ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
+
+ /* Invalid lengths don't get recorded on EMFs */
+ /* NOTE: With Windows-format Metafiles, ExtTextOutA with -1 length crashes on Windows */
+ hFont = CreateFontIndirectA(&orig_lf);
+ ok(hFont != 0, "CreateFontIndirectA error %d\n", GetLastError());
+
+ hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+ ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
+
+ hFont = SelectObject(hdcMetafile, hFont);
+ LineTo(hdcMetafile, 0, 0); /* make sure at least one valid record */
+
+ SetLastError(0xdeadbeef);
+ ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, -1, NULL);
+ ok( !ret, "ExtTextOutA succeeded\n");
+ ok( GetLastError() == 0xdeadbeef, "ExtTextOutA error %d\n", GetLastError());
+
+ hFont = SelectObject(hdcMetafile, hFont);
+ ret = DeleteObject(hFont);
+ ok( ret, "DeleteObject error %d\n", GetLastError());
+
+ hMetafile = CloseEnhMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
+
+ emr_processed = FALSE;
+ ret = EnumEnhMetaFile(hdcDisplay, hMetafile, eto_emf_enum_proc2, NULL, &rc);
+ ok( ret, "EnumEnhMetaFile error %d\n", GetLastError());
+ ok(emr_processed, "EnumEnhMetaFile couldn't find a valid record\n");
+
ret = DeleteEnhMetaFile(hMetafile);
ok( ret, "DeleteEnhMetaFile error %d\n", GetLastError());
ret = ReleaseDC(hwnd, hdcDisplay);
--
2.30.0
2
1
Feb. 3, 2021
According to the comment in large_int.c:
These builtin functions use stdcall calling convention, but compilers
reference them without stdcall declarations.
Otherwise ucrtbase initialization code crashes with +relay enabled when
compiled with clang as a PE build.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/ntdll/ntdll.spec | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 0a2c2493334..185dd6767eb 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1450,17 +1450,17 @@
@ cdecl __iscsym(long)
@ cdecl __iscsymf(long)
@ cdecl __toascii(long)
-@ cdecl -arch=i386 -ret64 _alldiv(int64 int64)
+@ cdecl -norelay -arch=i386 -ret64 _alldiv(int64 int64)
@ cdecl -arch=i386 -norelay _alldvrm(int64 int64)
-@ cdecl -arch=i386 -ret64 _allmul(int64 int64)
+@ cdecl -norelay -arch=i386 -ret64 _allmul(int64 int64)
@ cdecl -arch=i386 -norelay _alloca_probe()
-@ cdecl -arch=i386 -ret64 _allrem(int64 int64)
+@ cdecl -norelay -arch=i386 -ret64 _allrem(int64 int64)
@ stdcall -arch=i386 -ret64 _allshl(int64 long)
@ stdcall -arch=i386 -ret64 _allshr(int64 long)
@ cdecl -ret64 _atoi64(str)
-@ cdecl -arch=i386 -ret64 _aulldiv(int64 int64)
+@ cdecl -norelay -arch=i386 -ret64 _aulldiv(int64 int64)
@ cdecl -arch=i386 -norelay _aulldvrm(int64 int64)
-@ cdecl -arch=i386 -ret64 _aullrem(int64 int64)
+@ cdecl -norelay -arch=i386 -ret64 _aullrem(int64 int64)
@ stdcall -arch=i386 -ret64 _aullshr(int64 long)
@ cdecl -arch=i386 -norelay _chkstk()
@ stub _fltused
--
2.29.2
2
1
Feb. 3, 2021
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50602
Signed-off-by: Roman Pišl <rpisl(a)seznam.cz>
---
programs/conhost/window.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/programs/conhost/window.c b/programs/conhost/window.c
index 55690377a7e..5e94a1d454e 100644
--- a/programs/conhost/window.c
+++ b/programs/conhost/window.c
@@ -1885,7 +1885,7 @@ static void apply_config( struct console *console, const struct console_config *
console->active->attr = config->attr;
console->active->popup_attr = config->popup_attr;
console->active->win.left = config->win_pos.X;
- console->active->win.right = config->win_pos.Y;
+ console->active->win.top = config->win_pos.Y;
console->active->win.right = config->win_pos.X + config->win_width - 1;
console->active->win.bottom = config->win_pos.Y + config->win_height - 1;
memcpy( console->active->color_map, config->color_map, sizeof(config->color_map) );
--
2.20.1
2
6
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
A bit later It's allocated again.
dlls/evr/sample.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c
index 44b09d6d474..9c76011f153 100644
--- a/dlls/evr/sample.c
+++ b/dlls/evr/sample.c
@@ -585,7 +585,7 @@ static HRESULT sample_allocator_create_samples(struct sample_allocator *allocato
for (i = 0; i < sample_count; ++i)
{
- struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample));
+ struct queued_sample *queued_sample;
IMFMediaBuffer *buffer;
if (SUCCEEDED(hr = MFCreateVideoSampleFromSurface(NULL, &sample)))
--
2.30.0
1
0
[PATCH v4] shell32: IPersistFile::Save(NULL) should use previously stored file name.
by Huw Davies Feb. 3, 2021
by Huw Davies Feb. 3, 2021
Feb. 3, 2021
From: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/shell32/shelllink.c | 16 ++++++++++++----
dlls/shell32/tests/shelllink.c | 25 ++++++++++++++++++++++++-
2 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c
index 46d9bc994ff..69d610f2503 100644
--- a/dlls/shell32/shelllink.c
+++ b/dlls/shell32/shelllink.c
@@ -367,7 +367,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
if (!pszFileName)
- return E_FAIL;
+ {
+ if (!This->filepath) return S_OK;
+
+ pszFileName = This->filepath;
+ fRemember = FALSE;
+ }
r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
if( SUCCEEDED( r ) )
@@ -379,9 +384,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
{
StartLinkProcessor( pszFileName );
- /* update file path */
- heap_free(This->filepath);
- This->filepath = strdupW(pszFileName);
+ if (fRemember)
+ {
+ /* update file path */
+ heap_free(This->filepath);
+ This->filepath = strdupW(pszFileName);
+ }
This->bDirty = FALSE;
}
diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c
index 20c48814f1d..edd536c3a01 100644
--- a/dlls/shell32/tests/shelllink.c
+++ b/dlls/shell32/tests/shelllink.c
@@ -388,7 +388,7 @@ static void test_get_set(void)
void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
{
- HRESULT r;
+ HRESULT r, init_dirty;
IShellLinkA *sl;
IPersistFile *pf;
@@ -451,6 +451,17 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
IPersistFile_GetCurFile(pf, NULL);
}
+ init_dirty = IPersistFile_IsDirty(pf); /* empty links start off as clean */
+ r = IPersistFile_Save(pf, NULL, FALSE);
+ lok(r == S_OK || r == E_INVALIDARG /* before Windows 7 */, "save failed (0x%08x)\n", r);
+ r = IPersistFile_IsDirty(pf);
+ lok(r == init_dirty, "dirty (0x%08x)\n", r);
+
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK || r == E_INVALIDARG /* before Windows 7 */, "save failed (0x%08x)\n", r);
+ r = IPersistFile_IsDirty(pf);
+ lok(r == init_dirty, "dirty (0x%08x)\n", r);
+
/* test GetCurFile before ::Save */
str = (LPWSTR)0xdeadbeef;
r = IPersistFile_GetCurFile(pf, &str);
@@ -459,6 +470,18 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
r = IPersistFile_Save(pf, path, TRUE);
lok(r == S_OK, "save failed (0x%08x)\n", r);
+ r = IPersistFile_IsDirty(pf);
+ lok(r == S_FALSE, "dirty (0x%08x)\n", r);
+
+ /* test GetCurFile after ::Save */
+ r = IPersistFile_GetCurFile(pf, &str);
+ lok(r == S_OK, "got 0x%08x\n", r);
+ lok(str != NULL, "Didn't expect NULL\n");
+ lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK, "save failed (0x%08x)\n", r);
/* test GetCurFile after ::Save */
r = IPersistFile_GetCurFile(pf, &str);
--
2.23.0
1
0
[PATCH] shell32: IPersistFile::Save(NULL) should use previously stored file name.
by Dmitry Timoshkov Feb. 3, 2021
by Dmitry Timoshkov Feb. 3, 2021
Feb. 3, 2021
This is a resend, previous version didn't get much attention.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/shell32/shelllink.c | 14 ++++++++++----
dlls/shell32/tests/shelllink.c | 10 ++++++++++
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c
index 5b044d4be1..23c5935a7b 100644
--- a/dlls/shell32/shelllink.c
+++ b/dlls/shell32/shelllink.c
@@ -367,7 +367,10 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
if (!pszFileName)
- return E_FAIL;
+ {
+ pszFileName = This->filepath;
+ fRemember = FALSE;
+ }
r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
if( SUCCEEDED( r ) )
@@ -379,9 +382,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
{
StartLinkProcessor( pszFileName );
- /* update file path */
- heap_free(This->filepath);
- This->filepath = strdupW(pszFileName);
+ if (fRemember)
+ {
+ /* update file path */
+ heap_free(This->filepath);
+ This->filepath = strdupW(pszFileName);
+ }
This->bDirty = FALSE;
}
diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c
index 20c48814f1..21e9107fa6 100644
--- a/dlls/shell32/tests/shelllink.c
+++ b/dlls/shell32/tests/shelllink.c
@@ -467,6 +467,16 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
CoTaskMemFree(str);
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK, "save failed (0x%08x)\n", r);
+
+ /* test GetCurFile after ::Save */
+ r = IPersistFile_GetCurFile(pf, &str);
+ lok(r == S_OK, "got 0x%08x\n", r);
+ lok(str != NULL, "Didn't expect NULL\n");
+ lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
IPersistFile_Release(pf);
}
--
2.29.2
2
4
Feb. 3, 2021
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/Makefile.in | 3 +-
dlls/mfplat/buffer.c | 982 --------------------------------------
dlls/mfplat/sample.c | 1007 +++++++++++++++++++++++++++++++++++++++
3 files changed, 1009 insertions(+), 983 deletions(-)
create mode 100644 dlls/mfplat/sample.c
diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in
index cdb2b813340..bc04a440826 100644
--- a/dlls/mfplat/Makefile.in
+++ b/dlls/mfplat/Makefile.in
@@ -8,4 +8,5 @@ C_SRCS = \
buffer.c \
main.c \
mediatype.c \
- queue.c
+ queue.c \
+ sample.c
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index b47d2a9ba16..adfa2d867c1 100644
--- a/dlls/mfplat/buffer.c
+++ b/dlls/mfplat/buffer.c
@@ -63,31 +63,6 @@ struct memory_buffer
CRITICAL_SECTION cs;
};
-enum sample_prop_flags
-{
- SAMPLE_PROP_HAS_DURATION = 1 << 0,
- SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
-};
-
-struct sample
-{
- struct attributes attributes;
- IMFSample IMFSample_iface;
- IMFTrackedSample IMFTrackedSample_iface;
-
- IMFMediaBuffer **buffers;
- size_t buffer_count;
- size_t capacity;
- DWORD flags;
- DWORD prop_flags;
- LONGLONG duration;
- LONGLONG timestamp;
-
- /* Tracked sample functionality. */
- IRtwqAsyncResult *tracked_result;
- LONG tracked_refcount;
-};
-
static inline struct memory_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface)
{
return CONTAINING_RECORD(iface, struct memory_buffer, IMFMediaBuffer_iface);
@@ -103,16 +78,6 @@ static struct memory_buffer *impl_from_IMFGetService(IMFGetService *iface)
return CONTAINING_RECORD(iface, struct memory_buffer, IMFGetService_iface);
}
-static inline struct sample *impl_from_IMFSample(IMFSample *iface)
-{
- return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
-}
-
-static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
-{
- return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface);
-}
-
static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out)
{
struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface);
@@ -1080,950 +1045,3 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
return E_NOTIMPL;
}
-
-static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
-
- if (IsEqualIID(riid, &IID_IMFSample) ||
- IsEqualIID(riid, &IID_IMFAttributes) ||
- IsEqualIID(riid, &IID_IUnknown))
- {
- *out = &sample->IMFSample_iface;
- }
- else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample))
- {
- *out = &sample->IMFTrackedSample_iface;
- }
- else
- {
- WARN("Unsupported %s.\n", debugstr_guid(riid));
- *out = NULL;
- return E_NOINTERFACE;
- }
-
- IUnknown_AddRef((IUnknown *)*out);
- return S_OK;
-}
-
-static ULONG WINAPI sample_AddRef(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- ULONG refcount = InterlockedIncrement(&sample->attributes.ref);
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- return refcount;
-}
-
-static void release_sample_object(struct sample *sample)
-{
- size_t i;
-
- for (i = 0; i < sample->buffer_count; ++i)
- IMFMediaBuffer_Release(sample->buffers[i]);
- clear_attributes_object(&sample->attributes);
- heap_free(sample->buffers);
- heap_free(sample);
-}
-
-static ULONG WINAPI sample_Release(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- ULONG refcount = InterlockedDecrement(&sample->attributes.ref);
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- if (!refcount)
- release_sample_object(sample);
-
- return refcount;
-}
-
-static ULONG WINAPI sample_tracked_Release(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- ULONG refcount;
- HRESULT hr;
-
- EnterCriticalSection(&sample->attributes.cs);
- refcount = InterlockedDecrement(&sample->attributes.ref);
- if (sample->tracked_result && sample->tracked_refcount == refcount)
- {
- /* Call could fail if queue system is not initialized, it's not critical. */
- if (FAILED(hr = RtwqInvokeCallback(sample->tracked_result)))
- WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
- IRtwqAsyncResult_Release(sample->tracked_result);
- sample->tracked_result = NULL;
- sample->tracked_refcount = 0;
- }
- LeaveCriticalSection(&sample->attributes.cs);
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- if (!refcount)
- release_sample_object(sample);
-
- return refcount;
-}
-
-static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
- return attributes_GetItem(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
-
- return attributes_GetItemType(&sample->attributes, key, type);
-}
-
-static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
-
- return attributes_CompareItem(&sample->attributes, key, value, result);
-}
-
-static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
- BOOL *result)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
-
- return attributes_Compare(&sample->attributes, theirs, type, result);
-}
-
-static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
- return attributes_GetUINT32(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
- return attributes_GetUINT64(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
- return attributes_GetDouble(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
-
- return attributes_GetGUID(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
-
- return attributes_GetStringLength(&sample->attributes, key, length);
-}
-
-static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
-
- return attributes_GetString(&sample->attributes, key, value, size, length);
-}
-
-static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
-
- return attributes_GetAllocatedString(&sample->attributes, key, value, length);
-}
-
-static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
-
- return attributes_GetBlobSize(&sample->attributes, key, size);
-}
-
-static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
-
- return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
-}
-
-static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
-
- return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
-}
-
-static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
-
- return attributes_GetUnknown(&sample->attributes, key, riid, out);
-}
-
-static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
-
- return attributes_SetItem(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s.\n", iface, debugstr_attr(key));
-
- return attributes_DeleteItem(&sample->attributes, key);
-}
-
-static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p.\n", iface);
-
- return attributes_DeleteAllItems(&sample->attributes);
-}
-
-static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
-
- return attributes_SetUINT32(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
-
- return attributes_SetUINT64(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
-
- return attributes_SetDouble(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
-
- return attributes_SetGUID(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
-
- return attributes_SetString(&sample->attributes, key, value);
-}
-
-static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
-
- return attributes_SetBlob(&sample->attributes, key, buf, size);
-}
-
-static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
-
- return attributes_SetUnknown(&sample->attributes, key, unknown);
-}
-
-static HRESULT WINAPI sample_LockStore(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p.\n", iface);
-
- return attributes_LockStore(&sample->attributes);
-}
-
-static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p.\n", iface);
-
- return attributes_UnlockStore(&sample->attributes);
-}
-
-static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %p.\n", iface, count);
-
- return attributes_GetCount(&sample->attributes, count);
-}
-
-static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
-
- return attributes_GetItemByIndex(&sample->attributes, index, key, value);
-}
-
-static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %p.\n", iface, dest);
-
- return attributes_CopyAllItems(&sample->attributes, dest);
-}
-
-static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %p.\n", iface, flags);
-
- EnterCriticalSection(&sample->attributes.cs);
- *flags = sample->flags;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %#x.\n", iface, flags);
-
- EnterCriticalSection(&sample->attributes.cs);
- sample->flags = flags;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, timestamp);
-
- EnterCriticalSection(&sample->attributes.cs);
- if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
- *timestamp = sample->timestamp;
- else
- hr = MF_E_NO_SAMPLE_TIMESTAMP;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
-
- EnterCriticalSection(&sample->attributes.cs);
- sample->timestamp = timestamp;
- sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, duration);
-
- EnterCriticalSection(&sample->attributes.cs);
- if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
- *duration = sample->duration;
- else
- hr = MF_E_NO_SAMPLE_DURATION;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %s.\n", iface, debugstr_time(duration));
-
- EnterCriticalSection(&sample->attributes.cs);
- sample->duration = duration;
- sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %p.\n", iface, count);
-
- if (!count)
- return E_INVALIDARG;
-
- EnterCriticalSection(&sample->attributes.cs);
- *count = sample->buffer_count;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %u, %p.\n", iface, index, buffer);
-
- EnterCriticalSection(&sample->attributes.cs);
- if (index < sample->buffer_count)
- {
- *buffer = sample->buffers[index];
- IMFMediaBuffer_AddRef(*buffer);
- }
- else
- hr = E_INVALIDARG;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static unsigned int sample_get_total_length(struct sample *sample)
-{
- DWORD total_length = 0, length;
- size_t i;
-
- for (i = 0; i < sample->buffer_count; ++i)
- {
- length = 0;
- if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
- total_length += length;
- }
-
- return total_length;
-}
-
-static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
-{
- DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
- BYTE *src_ptr, *dst_ptr;
- BOOL locked;
- HRESULT hr;
- size_t i;
-
- total_length = sample_get_total_length(sample);
- dst_current_length = 0;
-
- dst_ptr = NULL;
- dst_length = current_length = 0;
- locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length));
- if (locked)
- {
- if (dst_length < total_length)
- hr = MF_E_BUFFERTOOSMALL;
- else if (dst_ptr)
- {
- for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
- {
- src_ptr = NULL;
- src_max_length = current_length = 0;
- if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length)))
- {
- if (src_ptr)
- {
- if (current_length > dst_length)
- hr = MF_E_BUFFERTOOSMALL;
- else if (current_length)
- {
- memcpy(dst_ptr, src_ptr, current_length);
- dst_length -= current_length;
- dst_current_length += current_length;
- dst_ptr += current_length;
- }
- }
- IMFMediaBuffer_Unlock(sample->buffers[i]);
- }
- }
- }
- }
-
- if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
- WARN("Failed to set buffer length.\n");
-
- if (locked)
- IMFMediaBuffer_Unlock(buffer);
-
- return hr;
-}
-
-static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- unsigned int total_length, i;
- IMFMediaBuffer *dest_buffer;
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, buffer);
-
- EnterCriticalSection(&sample->attributes.cs);
-
- if (sample->buffer_count == 0)
- hr = E_UNEXPECTED;
- else if (sample->buffer_count > 1)
- {
- total_length = sample_get_total_length(sample);
- if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
- {
- if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
- {
- for (i = 0; i < sample->buffer_count; ++i)
- IMFMediaBuffer_Release(sample->buffers[i]);
-
- sample->buffers[0] = dest_buffer;
- IMFMediaBuffer_AddRef(sample->buffers[0]);
-
- sample->buffer_count = 1;
- }
- IMFMediaBuffer_Release(dest_buffer);
- }
- }
-
- if (SUCCEEDED(hr) && buffer)
- {
- *buffer = sample->buffers[0];
- IMFMediaBuffer_AddRef(*buffer);
- }
-
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, buffer);
-
- EnterCriticalSection(&sample->attributes.cs);
- if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
- sizeof(*sample->buffers)))
- hr = E_OUTOFMEMORY;
- else
- {
- sample->buffers[sample->buffer_count++] = buffer;
- IMFMediaBuffer_AddRef(buffer);
- }
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %u.\n", iface, index);
-
- EnterCriticalSection(&sample->attributes.cs);
- if (index < sample->buffer_count)
- {
- IMFMediaBuffer_Release(sample->buffers[index]);
- if (index < sample->buffer_count - 1)
- {
- memmove(&sample->buffers[index], &sample->buffers[index+1],
- (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
- }
- sample->buffer_count--;
- }
- else
- hr = E_INVALIDARG;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- size_t i;
-
- TRACE("%p.\n", iface);
-
- EnterCriticalSection(&sample->attributes.cs);
- for (i = 0; i < sample->buffer_count; ++i)
- IMFMediaBuffer_Release(sample->buffers[i]);
- sample->buffer_count = 0;
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
-{
- struct sample *sample = impl_from_IMFSample(iface);
-
- TRACE("%p, %p.\n", iface, total_length);
-
- EnterCriticalSection(&sample->attributes.cs);
- *total_length = sample_get_total_length(sample);
- LeaveCriticalSection(&sample->attributes.cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
-{
- struct sample *sample = impl_from_IMFSample(iface);
- DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
- BYTE *src_ptr, *dst_ptr;
- BOOL locked;
- HRESULT hr;
- size_t i;
-
- TRACE("%p, %p.\n", iface, buffer);
-
- EnterCriticalSection(&sample->attributes.cs);
-
- total_length = sample_get_total_length(sample);
- dst_current_length = 0;
-
- dst_ptr = NULL;
- dst_length = current_length = 0;
- locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length));
- if (locked)
- {
- if (dst_length < total_length)
- hr = MF_E_BUFFERTOOSMALL;
- else if (dst_ptr)
- {
- for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
- {
- src_ptr = NULL;
- src_max_length = current_length = 0;
- if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length)))
- {
- if (src_ptr)
- {
- if (current_length > dst_length)
- hr = MF_E_BUFFERTOOSMALL;
- else if (current_length)
- {
- memcpy(dst_ptr, src_ptr, current_length);
- dst_length -= current_length;
- dst_current_length += current_length;
- dst_ptr += current_length;
- }
- }
- IMFMediaBuffer_Unlock(sample->buffers[i]);
- }
- }
- }
- }
-
- IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
-
- if (locked)
- IMFMediaBuffer_Unlock(buffer);
-
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static const IMFSampleVtbl samplevtbl =
-{
- sample_QueryInterface,
- sample_AddRef,
- sample_Release,
- sample_GetItem,
- sample_GetItemType,
- sample_CompareItem,
- sample_Compare,
- sample_GetUINT32,
- sample_GetUINT64,
- sample_GetDouble,
- sample_GetGUID,
- sample_GetStringLength,
- sample_GetString,
- sample_GetAllocatedString,
- sample_GetBlobSize,
- sample_GetBlob,
- sample_GetAllocatedBlob,
- sample_GetUnknown,
- sample_SetItem,
- sample_DeleteItem,
- sample_DeleteAllItems,
- sample_SetUINT32,
- sample_SetUINT64,
- sample_SetDouble,
- sample_SetGUID,
- sample_SetString,
- sample_SetBlob,
- sample_SetUnknown,
- sample_LockStore,
- sample_UnlockStore,
- sample_GetCount,
- sample_GetItemByIndex,
- sample_CopyAllItems,
- sample_GetSampleFlags,
- sample_SetSampleFlags,
- sample_GetSampleTime,
- sample_SetSampleTime,
- sample_GetSampleDuration,
- sample_SetSampleDuration,
- sample_GetBufferCount,
- sample_GetBufferByIndex,
- sample_ConvertToContiguousBuffer,
- sample_AddBuffer,
- sample_RemoveBufferByIndex,
- sample_RemoveAllBuffers,
- sample_GetTotalLength,
- sample_CopyToBuffer,
-};
-
-static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
-{
- struct sample *sample = impl_from_IMFTrackedSample(iface);
- return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
-}
-
-static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
-{
- struct sample *sample = impl_from_IMFTrackedSample(iface);
- return IMFSample_AddRef(&sample->IMFSample_iface);
-}
-
-static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
-{
- struct sample *sample = impl_from_IMFTrackedSample(iface);
- return IMFSample_Release(&sample->IMFSample_iface);
-}
-
-static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
- IMFAsyncCallback *sample_allocator, IUnknown *state)
-{
- struct sample *sample = impl_from_IMFTrackedSample(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
-
- EnterCriticalSection(&sample->attributes.cs);
-
- if (sample->tracked_result)
- hr = MF_E_NOTACCEPTING;
- else
- {
- if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
- state, &sample->tracked_result)))
- {
- /* Account for additional refcount brought by 'state' object. This threshold is used
- on Release() to invoke tracker callback. */
- sample->tracked_refcount = 1;
- if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
- state == (IUnknown *)&sample->IMFSample_iface)
- {
- ++sample->tracked_refcount;
- }
- }
- }
-
- LeaveCriticalSection(&sample->attributes.cs);
-
- return hr;
-}
-
-static const IMFTrackedSampleVtbl tracked_sample_vtbl =
-{
- tracked_sample_QueryInterface,
- tracked_sample_AddRef,
- tracked_sample_Release,
- tracked_sample_SetAllocator,
-};
-
-static const IMFSampleVtbl sample_tracked_vtbl =
-{
- sample_QueryInterface,
- sample_AddRef,
- sample_tracked_Release,
- sample_GetItem,
- sample_GetItemType,
- sample_CompareItem,
- sample_Compare,
- sample_GetUINT32,
- sample_GetUINT64,
- sample_GetDouble,
- sample_GetGUID,
- sample_GetStringLength,
- sample_GetString,
- sample_GetAllocatedString,
- sample_GetBlobSize,
- sample_GetBlob,
- sample_GetAllocatedBlob,
- sample_GetUnknown,
- sample_SetItem,
- sample_DeleteItem,
- sample_DeleteAllItems,
- sample_SetUINT32,
- sample_SetUINT64,
- sample_SetDouble,
- sample_SetGUID,
- sample_SetString,
- sample_SetBlob,
- sample_SetUnknown,
- sample_LockStore,
- sample_UnlockStore,
- sample_GetCount,
- sample_GetItemByIndex,
- sample_CopyAllItems,
- sample_GetSampleFlags,
- sample_SetSampleFlags,
- sample_GetSampleTime,
- sample_SetSampleTime,
- sample_GetSampleDuration,
- sample_SetSampleDuration,
- sample_GetBufferCount,
- sample_GetBufferByIndex,
- sample_ConvertToContiguousBuffer,
- sample_AddBuffer,
- sample_RemoveBufferByIndex,
- sample_RemoveAllBuffers,
- sample_GetTotalLength,
- sample_CopyToBuffer,
-};
-
-
-/***********************************************************************
- * MFCreateSample (mfplat.@)
- */
-HRESULT WINAPI MFCreateSample(IMFSample **sample)
-{
- struct sample *object;
- HRESULT hr;
-
- TRACE("%p.\n", sample);
-
- object = heap_alloc_zero(sizeof(*object));
- if (!object)
- return E_OUTOFMEMORY;
-
- if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
- {
- heap_free(object);
- return hr;
- }
-
- object->IMFSample_iface.lpVtbl = &samplevtbl;
-
- *sample = &object->IMFSample_iface;
-
- TRACE("Created sample %p.\n", *sample);
-
- return S_OK;
-}
-
-/***********************************************************************
- * MFCreateTrackedSample (mfplat.@)
- */
-HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
-{
- struct sample *object;
- HRESULT hr;
-
- TRACE("%p.\n", sample);
-
- object = heap_alloc_zero(sizeof(*object));
- if (!object)
- return E_OUTOFMEMORY;
-
- if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
- {
- heap_free(object);
- return hr;
- }
-
- object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
- object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
-
- *sample = &object->IMFTrackedSample_iface;
-
- return S_OK;
-}
diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c
new file mode 100644
index 00000000000..bd67fb731fc
--- /dev/null
+++ b/dlls/mfplat/sample.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright 2021 Nikolay Sivov for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include "mfplat_private.h"
+#include "rtworkq.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+enum sample_prop_flags
+{
+ SAMPLE_PROP_HAS_DURATION = 1 << 0,
+ SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
+};
+
+struct sample
+{
+ struct attributes attributes;
+ IMFSample IMFSample_iface;
+ IMFTrackedSample IMFTrackedSample_iface;
+
+ IMFMediaBuffer **buffers;
+ size_t buffer_count;
+ size_t capacity;
+ DWORD flags;
+ DWORD prop_flags;
+ LONGLONG duration;
+ LONGLONG timestamp;
+
+ /* Tracked sample functionality. */
+ IRtwqAsyncResult *tracked_result;
+ LONG tracked_refcount;
+};
+
+static struct sample *impl_from_IMFSample(IMFSample *iface)
+{
+ return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
+}
+
+static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
+{
+ return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface);
+}
+
+static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFSample) ||
+ IsEqualIID(riid, &IID_IMFAttributes) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &sample->IMFSample_iface;
+ }
+ else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample))
+ {
+ *out = &sample->IMFTrackedSample_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI sample_AddRef(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ ULONG refcount = InterlockedIncrement(&sample->attributes.ref);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static void release_sample_object(struct sample *sample)
+{
+ size_t i;
+
+ for (i = 0; i < sample->buffer_count; ++i)
+ IMFMediaBuffer_Release(sample->buffers[i]);
+ clear_attributes_object(&sample->attributes);
+ heap_free(sample->buffers);
+ heap_free(sample);
+}
+
+static ULONG WINAPI sample_Release(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ ULONG refcount = InterlockedDecrement(&sample->attributes.ref);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ release_sample_object(sample);
+
+ return refcount;
+}
+
+static ULONG WINAPI sample_tracked_Release(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ ULONG refcount;
+ HRESULT hr;
+
+ EnterCriticalSection(&sample->attributes.cs);
+ refcount = InterlockedDecrement(&sample->attributes.ref);
+ if (sample->tracked_result && sample->tracked_refcount == refcount)
+ {
+ /* Call could fail if queue system is not initialized, it's not critical. */
+ if (FAILED(hr = RtwqInvokeCallback(sample->tracked_result)))
+ WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
+ IRtwqAsyncResult_Release(sample->tracked_result);
+ sample->tracked_result = NULL;
+ sample->tracked_refcount = 0;
+ }
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ release_sample_object(sample);
+
+ return refcount;
+}
+
+static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+ return attributes_GetItem(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
+
+ return attributes_GetItemType(&sample->attributes, key, type);
+}
+
+static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
+
+ return attributes_CompareItem(&sample->attributes, key, value, result);
+}
+
+static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
+ BOOL *result)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
+
+ return attributes_Compare(&sample->attributes, theirs, type, result);
+}
+
+static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+ return attributes_GetUINT32(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+ return attributes_GetUINT64(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+ return attributes_GetDouble(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
+
+ return attributes_GetGUID(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
+
+ return attributes_GetStringLength(&sample->attributes, key, length);
+}
+
+static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
+
+ return attributes_GetString(&sample->attributes, key, value, size, length);
+}
+
+static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
+
+ return attributes_GetAllocatedString(&sample->attributes, key, value, length);
+}
+
+static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
+
+ return attributes_GetBlobSize(&sample->attributes, key, size);
+}
+
+static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
+
+ return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
+}
+
+static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
+
+ return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
+}
+
+static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
+
+ return attributes_GetUnknown(&sample->attributes, key, riid, out);
+}
+
+static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
+
+ return attributes_SetItem(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_attr(key));
+
+ return attributes_DeleteItem(&sample->attributes, key);
+}
+
+static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p.\n", iface);
+
+ return attributes_DeleteAllItems(&sample->attributes);
+}
+
+static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
+
+ return attributes_SetUINT32(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
+
+ return attributes_SetUINT64(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
+
+ return attributes_SetDouble(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
+
+ return attributes_SetGUID(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
+
+ return attributes_SetString(&sample->attributes, key, value);
+}
+
+static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
+
+ return attributes_SetBlob(&sample->attributes, key, buf, size);
+}
+
+static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
+
+ return attributes_SetUnknown(&sample->attributes, key, unknown);
+}
+
+static HRESULT WINAPI sample_LockStore(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p.\n", iface);
+
+ return attributes_LockStore(&sample->attributes);
+}
+
+static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p.\n", iface);
+
+ return attributes_UnlockStore(&sample->attributes);
+}
+
+static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %p.\n", iface, count);
+
+ return attributes_GetCount(&sample->attributes, count);
+}
+
+static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
+
+ return attributes_GetItemByIndex(&sample->attributes, index, key, value);
+}
+
+static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %p.\n", iface, dest);
+
+ return attributes_CopyAllItems(&sample->attributes, dest);
+}
+
+static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %p.\n", iface, flags);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ *flags = sample->flags;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %#x.\n", iface, flags);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ sample->flags = flags;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, timestamp);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
+ *timestamp = sample->timestamp;
+ else
+ hr = MF_E_NO_SAMPLE_TIMESTAMP;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
+
+ EnterCriticalSection(&sample->attributes.cs);
+ sample->timestamp = timestamp;
+ sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, duration);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
+ *duration = sample->duration;
+ else
+ hr = MF_E_NO_SAMPLE_DURATION;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %s.\n", iface, debugstr_time(duration));
+
+ EnterCriticalSection(&sample->attributes.cs);
+ sample->duration = duration;
+ sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %p.\n", iface, count);
+
+ if (!count)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&sample->attributes.cs);
+ *count = sample->buffer_count;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %u, %p.\n", iface, index, buffer);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ if (index < sample->buffer_count)
+ {
+ *buffer = sample->buffers[index];
+ IMFMediaBuffer_AddRef(*buffer);
+ }
+ else
+ hr = E_INVALIDARG;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static unsigned int sample_get_total_length(struct sample *sample)
+{
+ DWORD total_length = 0, length;
+ size_t i;
+
+ for (i = 0; i < sample->buffer_count; ++i)
+ {
+ length = 0;
+ if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
+ total_length += length;
+ }
+
+ return total_length;
+}
+
+static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
+{
+ DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
+ BYTE *src_ptr, *dst_ptr;
+ BOOL locked;
+ HRESULT hr;
+ size_t i;
+
+ total_length = sample_get_total_length(sample);
+ dst_current_length = 0;
+
+ dst_ptr = NULL;
+ dst_length = current_length = 0;
+ locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length));
+ if (locked)
+ {
+ if (dst_length < total_length)
+ hr = MF_E_BUFFERTOOSMALL;
+ else if (dst_ptr)
+ {
+ for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
+ {
+ src_ptr = NULL;
+ src_max_length = current_length = 0;
+ if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length)))
+ {
+ if (src_ptr)
+ {
+ if (current_length > dst_length)
+ hr = MF_E_BUFFERTOOSMALL;
+ else if (current_length)
+ {
+ memcpy(dst_ptr, src_ptr, current_length);
+ dst_length -= current_length;
+ dst_current_length += current_length;
+ dst_ptr += current_length;
+ }
+ }
+ IMFMediaBuffer_Unlock(sample->buffers[i]);
+ }
+ }
+ }
+ }
+
+ if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
+ WARN("Failed to set buffer length.\n");
+
+ if (locked)
+ IMFMediaBuffer_Unlock(buffer);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ unsigned int total_length, i;
+ IMFMediaBuffer *dest_buffer;
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, buffer);
+
+ EnterCriticalSection(&sample->attributes.cs);
+
+ if (sample->buffer_count == 0)
+ hr = E_UNEXPECTED;
+ else if (sample->buffer_count > 1)
+ {
+ total_length = sample_get_total_length(sample);
+ if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
+ {
+ if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
+ {
+ for (i = 0; i < sample->buffer_count; ++i)
+ IMFMediaBuffer_Release(sample->buffers[i]);
+
+ sample->buffers[0] = dest_buffer;
+ IMFMediaBuffer_AddRef(sample->buffers[0]);
+
+ sample->buffer_count = 1;
+ }
+ IMFMediaBuffer_Release(dest_buffer);
+ }
+ }
+
+ if (SUCCEEDED(hr) && buffer)
+ {
+ *buffer = sample->buffers[0];
+ IMFMediaBuffer_AddRef(*buffer);
+ }
+
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, buffer);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
+ sizeof(*sample->buffers)))
+ hr = E_OUTOFMEMORY;
+ else
+ {
+ sample->buffers[sample->buffer_count++] = buffer;
+ IMFMediaBuffer_AddRef(buffer);
+ }
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %u.\n", iface, index);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ if (index < sample->buffer_count)
+ {
+ IMFMediaBuffer_Release(sample->buffers[index]);
+ if (index < sample->buffer_count - 1)
+ {
+ memmove(&sample->buffers[index], &sample->buffers[index+1],
+ (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
+ }
+ sample->buffer_count--;
+ }
+ else
+ hr = E_INVALIDARG;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ size_t i;
+
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ for (i = 0; i < sample->buffer_count; ++i)
+ IMFMediaBuffer_Release(sample->buffers[i]);
+ sample->buffer_count = 0;
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+
+ TRACE("%p, %p.\n", iface, total_length);
+
+ EnterCriticalSection(&sample->attributes.cs);
+ *total_length = sample_get_total_length(sample);
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
+{
+ struct sample *sample = impl_from_IMFSample(iface);
+ DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
+ BYTE *src_ptr, *dst_ptr;
+ BOOL locked;
+ HRESULT hr;
+ size_t i;
+
+ TRACE("%p, %p.\n", iface, buffer);
+
+ EnterCriticalSection(&sample->attributes.cs);
+
+ total_length = sample_get_total_length(sample);
+ dst_current_length = 0;
+
+ dst_ptr = NULL;
+ dst_length = current_length = 0;
+ locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length));
+ if (locked)
+ {
+ if (dst_length < total_length)
+ hr = MF_E_BUFFERTOOSMALL;
+ else if (dst_ptr)
+ {
+ for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
+ {
+ src_ptr = NULL;
+ src_max_length = current_length = 0;
+ if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length)))
+ {
+ if (src_ptr)
+ {
+ if (current_length > dst_length)
+ hr = MF_E_BUFFERTOOSMALL;
+ else if (current_length)
+ {
+ memcpy(dst_ptr, src_ptr, current_length);
+ dst_length -= current_length;
+ dst_current_length += current_length;
+ dst_ptr += current_length;
+ }
+ }
+ IMFMediaBuffer_Unlock(sample->buffers[i]);
+ }
+ }
+ }
+ }
+
+ IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
+
+ if (locked)
+ IMFMediaBuffer_Unlock(buffer);
+
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static const IMFSampleVtbl samplevtbl =
+{
+ sample_QueryInterface,
+ sample_AddRef,
+ sample_Release,
+ sample_GetItem,
+ sample_GetItemType,
+ sample_CompareItem,
+ sample_Compare,
+ sample_GetUINT32,
+ sample_GetUINT64,
+ sample_GetDouble,
+ sample_GetGUID,
+ sample_GetStringLength,
+ sample_GetString,
+ sample_GetAllocatedString,
+ sample_GetBlobSize,
+ sample_GetBlob,
+ sample_GetAllocatedBlob,
+ sample_GetUnknown,
+ sample_SetItem,
+ sample_DeleteItem,
+ sample_DeleteAllItems,
+ sample_SetUINT32,
+ sample_SetUINT64,
+ sample_SetDouble,
+ sample_SetGUID,
+ sample_SetString,
+ sample_SetBlob,
+ sample_SetUnknown,
+ sample_LockStore,
+ sample_UnlockStore,
+ sample_GetCount,
+ sample_GetItemByIndex,
+ sample_CopyAllItems,
+ sample_GetSampleFlags,
+ sample_SetSampleFlags,
+ sample_GetSampleTime,
+ sample_SetSampleTime,
+ sample_GetSampleDuration,
+ sample_SetSampleDuration,
+ sample_GetBufferCount,
+ sample_GetBufferByIndex,
+ sample_ConvertToContiguousBuffer,
+ sample_AddBuffer,
+ sample_RemoveBufferByIndex,
+ sample_RemoveAllBuffers,
+ sample_GetTotalLength,
+ sample_CopyToBuffer,
+};
+
+static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
+{
+ struct sample *sample = impl_from_IMFTrackedSample(iface);
+ return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
+}
+
+static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
+{
+ struct sample *sample = impl_from_IMFTrackedSample(iface);
+ return IMFSample_AddRef(&sample->IMFSample_iface);
+}
+
+static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
+{
+ struct sample *sample = impl_from_IMFTrackedSample(iface);
+ return IMFSample_Release(&sample->IMFSample_iface);
+}
+
+static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
+ IMFAsyncCallback *sample_allocator, IUnknown *state)
+{
+ struct sample *sample = impl_from_IMFTrackedSample(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
+
+ EnterCriticalSection(&sample->attributes.cs);
+
+ if (sample->tracked_result)
+ hr = MF_E_NOTACCEPTING;
+ else
+ {
+ if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
+ state, &sample->tracked_result)))
+ {
+ /* Account for additional refcount brought by 'state' object. This threshold is used
+ on Release() to invoke tracker callback. */
+ sample->tracked_refcount = 1;
+ if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
+ state == (IUnknown *)&sample->IMFSample_iface)
+ {
+ ++sample->tracked_refcount;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&sample->attributes.cs);
+
+ return hr;
+}
+
+static const IMFTrackedSampleVtbl tracked_sample_vtbl =
+{
+ tracked_sample_QueryInterface,
+ tracked_sample_AddRef,
+ tracked_sample_Release,
+ tracked_sample_SetAllocator,
+};
+
+static const IMFSampleVtbl sample_tracked_vtbl =
+{
+ sample_QueryInterface,
+ sample_AddRef,
+ sample_tracked_Release,
+ sample_GetItem,
+ sample_GetItemType,
+ sample_CompareItem,
+ sample_Compare,
+ sample_GetUINT32,
+ sample_GetUINT64,
+ sample_GetDouble,
+ sample_GetGUID,
+ sample_GetStringLength,
+ sample_GetString,
+ sample_GetAllocatedString,
+ sample_GetBlobSize,
+ sample_GetBlob,
+ sample_GetAllocatedBlob,
+ sample_GetUnknown,
+ sample_SetItem,
+ sample_DeleteItem,
+ sample_DeleteAllItems,
+ sample_SetUINT32,
+ sample_SetUINT64,
+ sample_SetDouble,
+ sample_SetGUID,
+ sample_SetString,
+ sample_SetBlob,
+ sample_SetUnknown,
+ sample_LockStore,
+ sample_UnlockStore,
+ sample_GetCount,
+ sample_GetItemByIndex,
+ sample_CopyAllItems,
+ sample_GetSampleFlags,
+ sample_SetSampleFlags,
+ sample_GetSampleTime,
+ sample_SetSampleTime,
+ sample_GetSampleDuration,
+ sample_SetSampleDuration,
+ sample_GetBufferCount,
+ sample_GetBufferByIndex,
+ sample_ConvertToContiguousBuffer,
+ sample_AddBuffer,
+ sample_RemoveBufferByIndex,
+ sample_RemoveAllBuffers,
+ sample_GetTotalLength,
+ sample_CopyToBuffer,
+};
+
+/***********************************************************************
+ * MFCreateSample (mfplat.@)
+ */
+HRESULT WINAPI MFCreateSample(IMFSample **sample)
+{
+ struct sample *object;
+ HRESULT hr;
+
+ TRACE("%p.\n", sample);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
+ {
+ heap_free(object);
+ return hr;
+ }
+
+ object->IMFSample_iface.lpVtbl = &samplevtbl;
+
+ *sample = &object->IMFSample_iface;
+
+ TRACE("Created sample %p.\n", *sample);
+
+ return S_OK;
+}
+
+/***********************************************************************
+ * MFCreateTrackedSample (mfplat.@)
+ */
+HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
+{
+ struct sample *object;
+ HRESULT hr;
+
+ TRACE("%p.\n", sample);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
+ {
+ heap_free(object);
+ return hr;
+ }
+
+ object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
+ object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
+
+ *sample = &object->IMFTrackedSample_iface;
+
+ return S_OK;
+}
--
2.30.0
2
16
Feb. 3, 2021
Signed-off-by: Jan Sikorski <jsikorski(a)codeweavers.com>
---
dlls/d3d11/d3d11_private.h | 2 --
dlls/d3d11/device.c | 15 +++------------
dlls/wined3d/adapter_vk.c | 2 +-
dlls/wined3d/context_vk.c | 4 ++--
dlls/wined3d/cs.c | 15 +++++++++++----
dlls/wined3d/device.c | 25 +++++++++++++++++--------
dlls/wined3d/directx.c | 2 +-
dlls/wined3d/state.c | 8 ++++----
dlls/wined3d/wined3d_private.h | 8 ++++++--
include/wine/wined3d.h | 4 ++--
10 files changed, 47 insertions(+), 38 deletions(-)
diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h
index 7fef636b883..cdae1104efa 100644
--- a/dlls/d3d11/d3d11_private.h
+++ b/dlls/d3d11/d3d11_private.h
@@ -583,8 +583,6 @@ struct d3d_device
struct wine_rb_tree depthstencil_states;
struct wine_rb_tree rasterizer_states;
struct wine_rb_tree sampler_states;
-
- UINT stencil_ref;
};
static inline struct d3d_device *impl_from_ID3D11Device(ID3D11Device *iface)
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index d24ec0ef0ba..fcbcc64a636 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -881,27 +881,19 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_OMSetDepthStencilState(ID3
{
struct d3d_device *device = device_from_immediate_ID3D11DeviceContext1(iface);
struct d3d_depthstencil_state *state_impl;
- const D3D11_DEPTH_STENCIL_DESC *desc;
TRACE("iface %p, depth_stencil_state %p, stencil_ref %u.\n",
iface, depth_stencil_state, stencil_ref);
wined3d_mutex_lock();
- device->stencil_ref = stencil_ref;
if (!(state_impl = unsafe_impl_from_ID3D11DepthStencilState(depth_stencil_state)))
{
- wined3d_device_set_depth_stencil_state(device->wined3d_device, NULL);
+ wined3d_device_set_depth_stencil_state(device->wined3d_device, NULL, 0);
wined3d_mutex_unlock();
return;
}
- wined3d_device_set_depth_stencil_state(device->wined3d_device, state_impl->wined3d_state);
- desc = &state_impl->desc;
-
- if (desc->StencilEnable)
- {
- wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_STENCILREF, stencil_ref);
- }
+ wined3d_device_set_depth_stencil_state(device->wined3d_device, state_impl->wined3d_state, stencil_ref);
wined3d_mutex_unlock();
}
@@ -2022,7 +2014,7 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_OMGetDepthStencilState(ID3
iface, depth_stencil_state, stencil_ref);
wined3d_mutex_lock();
- if ((wined3d_state = wined3d_device_get_depth_stencil_state(device->wined3d_device)))
+ if ((wined3d_state = wined3d_device_get_depth_stencil_state(device->wined3d_device, stencil_ref)))
{
state_impl = wined3d_depth_stencil_state_get_parent(wined3d_state);
ID3D11DepthStencilState_AddRef(*depth_stencil_state = &state_impl->ID3D11DepthStencilState_iface);
@@ -2031,7 +2023,6 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_OMGetDepthStencilState(ID3
{
*depth_stencil_state = NULL;
}
- *stencil_ref = device->stencil_ref;
wined3d_mutex_unlock();
}
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index d2ac652ab62..62032fb74c5 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -43,6 +43,7 @@ static const struct wined3d_state_entry_template misc_state_template_vk[] =
{STATE_STREAMSRC, {STATE_STREAMSRC, state_nop}},
{STATE_VDECL, {STATE_VDECL, state_nop}},
{STATE_DEPTH_STENCIL, {STATE_DEPTH_STENCIL, state_nop}},
+ {STATE_STENCIL_REF, {STATE_STENCIL_REF, state_nop}},
{STATE_RASTERIZER, {STATE_RASTERIZER, state_nop}},
{STATE_SCISSORRECT, {STATE_SCISSORRECT, state_nop}},
{STATE_POINTSPRITECOORDORIGIN, {STATE_POINTSPRITECOORDORIGIN, state_nop}},
@@ -116,7 +117,6 @@ static const struct wined3d_state_entry_template misc_state_template_vk[] =
{STATE_RENDER(WINED3D_RS_ANISOTROPY), {STATE_RENDER(WINED3D_RS_ANISOTROPY), state_nop}},
{STATE_RENDER(WINED3D_RS_FLUSHBATCH), {STATE_RENDER(WINED3D_RS_FLUSHBATCH), state_nop}},
{STATE_RENDER(WINED3D_RS_TRANSLUCENTSORTINDEPENDENT), {STATE_RENDER(WINED3D_RS_TRANSLUCENTSORTINDEPENDENT), state_nop}},
- {STATE_RENDER(WINED3D_RS_STENCILREF), {STATE_RENDER(WINED3D_RS_STENCILREF), state_nop}},
{STATE_RENDER(WINED3D_RS_WRAP0), {STATE_RENDER(WINED3D_RS_WRAP0), state_nop}},
{STATE_RENDER(WINED3D_RS_WRAP1), {STATE_RENDER(WINED3D_RS_WRAP0)}},
{STATE_RENDER(WINED3D_RS_WRAP2), {STATE_RENDER(WINED3D_RS_WRAP0)}},
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index 841b3d742c6..55127e44a00 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -2076,7 +2076,7 @@ static bool wined3d_context_vk_update_graphics_pipeline_key(struct wined3d_conte
key->ds_desc.front.compareOp = vk_compare_op_from_wined3d(d->desc.front.func);
key->ds_desc.front.compareMask = d->desc.stencil_read_mask;
key->ds_desc.front.writeMask = d->desc.stencil_write_mask;
- key->ds_desc.front.reference = state->render_states[WINED3D_RS_STENCILREF]
+ key->ds_desc.front.reference = state->stencil_ref
& ((1 << state->fb.depth_stencil->format->stencil_size) - 1);
key->ds_desc.back.failOp = vk_stencil_op_from_wined3d(d->desc.back.fail_op);
@@ -2085,7 +2085,7 @@ static bool wined3d_context_vk_update_graphics_pipeline_key(struct wined3d_conte
key->ds_desc.back.compareOp = vk_compare_op_from_wined3d(d->desc.back.func);
key->ds_desc.back.compareMask = d->desc.stencil_read_mask;
key->ds_desc.back.writeMask = d->desc.stencil_write_mask;
- key->ds_desc.back.reference = state->render_states[WINED3D_RS_STENCILREF]
+ key->ds_desc.back.reference = state->stencil_ref
& ((1 << state->fb.depth_stencil->format->stencil_size) - 1);
}
else
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 56df760145a..e09b1fb9725 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -275,6 +275,7 @@ struct wined3d_cs_set_depth_stencil_state
{
enum wined3d_cs_op opcode;
struct wined3d_depth_stencil_state *state;
+ unsigned int stencil_ref;
};
struct wined3d_cs_set_rasterizer_state
@@ -1235,7 +1236,7 @@ static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const
if (prev->format->depth_bias_scale != op->view->format->depth_bias_scale)
device_invalidate_state(device, STATE_RASTERIZER);
if (prev->format->stencil_size != op->view->format->stencil_size)
- device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILREF));
+ device_invalidate_state(device, STATE_STENCIL_REF);
}
device_invalidate_state(device, STATE_FRAMEBUFFER);
@@ -1665,19 +1666,25 @@ void wined3d_cs_emit_set_blend_state(struct wined3d_cs *cs, struct wined3d_blend
static void wined3d_cs_exec_set_depth_stencil_state(struct wined3d_cs *cs, const void *data)
{
const struct wined3d_cs_set_depth_stencil_state *op = data;
+ struct wined3d_state *state = &cs->state;
- cs->state.depth_stencil_state = op->state;
- device_invalidate_state(cs->device, STATE_DEPTH_STENCIL);
+ if (state->depth_stencil_state != op->state) {
+ state->depth_stencil_state = op->state;
+ device_invalidate_state(cs->device, STATE_DEPTH_STENCIL);
+ }
+ state->stencil_ref = op->stencil_ref;
+ device_invalidate_state(cs->device, STATE_STENCIL_REF);
}
void wined3d_cs_emit_set_depth_stencil_state(struct wined3d_cs *cs,
- struct wined3d_depth_stencil_state *state)
+ struct wined3d_depth_stencil_state *state, unsigned int stencil_ref)
{
struct wined3d_cs_set_depth_stencil_state *op;
op = wined3d_cs_require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_STATE;
op->state = state;
+ op->stencil_ref = stencil_ref;
wined3d_cs_submit(cs, WINED3D_CS_QUEUE_DEFAULT);
}
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 3c16a3c691e..feaef2ef18f 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1774,28 +1774,30 @@ struct wined3d_blend_state * CDECL wined3d_device_get_blend_state(const struct w
}
void CDECL wined3d_device_set_depth_stencil_state(struct wined3d_device *device,
- struct wined3d_depth_stencil_state *state)
+ struct wined3d_depth_stencil_state *state, unsigned int stencil_ref)
{
struct wined3d_depth_stencil_state *prev;
- TRACE("device %p, state %p.\n", device, state);
+ TRACE("device %p, state %p, stencil_ref %u.\n", device, state, stencil_ref);
prev = device->state.depth_stencil_state;
- if (prev == state)
+ if (prev == state && device->state.stencil_ref == stencil_ref)
return;
if (state)
wined3d_depth_stencil_state_incref(state);
device->state.depth_stencil_state = state;
- wined3d_cs_emit_set_depth_stencil_state(device->cs, state);
+ device->state.stencil_ref = stencil_ref;
+ wined3d_cs_emit_set_depth_stencil_state(device->cs, state, stencil_ref);
if (prev)
wined3d_depth_stencil_state_decref(prev);
}
-struct wined3d_depth_stencil_state * CDECL wined3d_device_get_depth_stencil_state(const struct wined3d_device *device)
+struct wined3d_depth_stencil_state * CDECL wined3d_device_get_depth_stencil_state(const struct wined3d_device *device, unsigned int *stencil_ref)
{
- TRACE("device %p.\n", device);
+ TRACE("device %p, stencil_ref %p.\n", device, stencil_ref);
+ *stencil_ref = device->state.stencil_ref;
return device->state.depth_stencil_state;
}
@@ -3704,6 +3706,7 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
case WINED3D_RS_STENCILENABLE:
case WINED3D_RS_STENCILFAIL:
case WINED3D_RS_STENCILFUNC:
+ case WINED3D_RS_STENCILREF:
case WINED3D_RS_STENCILMASK:
case WINED3D_RS_STENCILPASS:
case WINED3D_RS_STENCILWRITEMASK:
@@ -3848,6 +3851,7 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
struct wined3d_depth_stencil_state *depth_stencil_state;
struct wined3d_depth_stencil_state_desc desc;
struct wine_rb_entry *entry;
+ unsigned int stencil_ref;
memset(&desc, 0, sizeof(desc));
switch (state->rs[WINED3D_RS_ZENABLE])
@@ -3887,15 +3891,20 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
desc.back = desc.front;
}
+ if (wined3d_bitmap_is_set(changed->renderState, WINED3D_RS_STENCILREF))
+ stencil_ref = state->rs[WINED3D_RS_STENCILREF];
+ else
+ wined3d_device_get_depth_stencil_state(device, &stencil_ref);
+
if ((entry = wine_rb_get(&device->depth_stencil_states, &desc)))
{
depth_stencil_state = WINE_RB_ENTRY_VALUE(entry, struct wined3d_depth_stencil_state, entry);
- wined3d_device_set_depth_stencil_state(device, depth_stencil_state);
+ wined3d_device_set_depth_stencil_state(device, depth_stencil_state, stencil_ref);
}
else if (SUCCEEDED(wined3d_depth_stencil_state_create(device, &desc, NULL,
&wined3d_null_parent_ops, &depth_stencil_state)))
{
- wined3d_device_set_depth_stencil_state(device, depth_stencil_state);
+ wined3d_device_set_depth_stencil_state(device, depth_stencil_state, stencil_ref);
if (wine_rb_put(&device->depth_stencil_states, &desc, &depth_stencil_state->entry) == -1)
{
ERR("Failed to insert depth/stencil state.\n");
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 040a9f81083..f72fd3e3ae3 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -2469,6 +2469,7 @@ static const struct wined3d_state_entry_template misc_state_template_no3d[] =
{STATE_BLEND_FACTOR, {STATE_VDECL}},
{STATE_SAMPLE_MASK, {STATE_VDECL}},
{STATE_DEPTH_STENCIL, {STATE_VDECL}},
+ {STATE_STENCIL_REF, {STATE_VDECL}},
{STATE_STREAMSRC, {STATE_VDECL}},
{STATE_VDECL, {STATE_VDECL, state_nop}},
{STATE_RASTERIZER, {STATE_VDECL}},
@@ -2545,7 +2546,6 @@ static const struct wined3d_state_entry_template misc_state_template_no3d[] =
{STATE_RENDER(WINED3D_RS_ANISOTROPY), {STATE_VDECL}},
{STATE_RENDER(WINED3D_RS_FLUSHBATCH), {STATE_VDECL}},
{STATE_RENDER(WINED3D_RS_TRANSLUCENTSORTINDEPENDENT), {STATE_VDECL}},
- {STATE_RENDER(WINED3D_RS_STENCILREF), {STATE_VDECL}},
{STATE_RENDER(WINED3D_RS_WRAP0), {STATE_VDECL}},
{STATE_RENDER(WINED3D_RS_WRAP1), {STATE_VDECL}},
{STATE_RENDER(WINED3D_RS_WRAP2), {STATE_VDECL}},
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index e40c23daf03..f454a7a3801 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -1070,7 +1070,7 @@ static void state_stencil(struct wined3d_context *context, const struct wined3d_
if (!(func_back = wined3d_gl_compare_func(d->desc.back.func)))
func_back = GL_ALWAYS;
mask = d->desc.stencil_read_mask;
- ref = state->render_states[WINED3D_RS_STENCILREF] & ((1 << state->fb.depth_stencil->format->stencil_size) - 1);
+ ref = state->stencil_ref & ((1 << state->fb.depth_stencil->format->stencil_size) - 1);
stencilFail = gl_stencil_op(d->desc.front.fail_op);
depthFail = gl_stencil_op(d->desc.front.depth_fail_op);
stencilPass = gl_stencil_op(d->desc.front.pass_op);
@@ -4691,6 +4691,7 @@ const struct wined3d_state_entry_template misc_state_template_gl[] =
{ STATE_SAMPLE_MASK, { STATE_SAMPLE_MASK, state_sample_mask_w }, WINED3D_GL_EXT_NONE },
{ STATE_DEPTH_STENCIL, { STATE_DEPTH_STENCIL, depth_stencil_2s }, EXT_STENCIL_TWO_SIDE },
{ STATE_DEPTH_STENCIL, { STATE_DEPTH_STENCIL, depth_stencil }, WINED3D_GL_EXT_NONE },
+ { STATE_STENCIL_REF, { STATE_DEPTH_STENCIL, NULL }, WINED3D_GL_EXT_NONE },
{ STATE_STREAMSRC, { STATE_STREAMSRC, streamsrc }, WINED3D_GL_EXT_NONE },
{ STATE_VDECL, { STATE_VDECL, vdecl_miscpart }, WINED3D_GL_EXT_NONE },
{ STATE_RASTERIZER, { STATE_RASTERIZER, rasterizer_cc }, ARB_CLIP_CONTROL },
@@ -4775,7 +4776,6 @@ const struct wined3d_state_entry_template misc_state_template_gl[] =
{ STATE_RENDER(WINED3D_RS_ANISOTROPY), { STATE_RENDER(WINED3D_RS_ANISOTROPY), state_anisotropy }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_FLUSHBATCH), { STATE_RENDER(WINED3D_RS_FLUSHBATCH), state_flushbatch }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_TRANSLUCENTSORTINDEPENDENT),{ STATE_RENDER(WINED3D_RS_TRANSLUCENTSORTINDEPENDENT),state_translucentsi }, WINED3D_GL_EXT_NONE },
- { STATE_RENDER(WINED3D_RS_STENCILREF), { STATE_DEPTH_STENCIL, NULL }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_WRAP0), { STATE_RENDER(WINED3D_RS_WRAP0), state_wrap }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_WRAP1), { STATE_RENDER(WINED3D_RS_WRAP0), NULL }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_WRAP2), { STATE_RENDER(WINED3D_RS_WRAP0), NULL }, WINED3D_GL_EXT_NONE },
@@ -5574,8 +5574,7 @@ static void validate_state_table(struct wined3d_state_entry *state_table)
{ 40, 40},
{ 42, 45},
{ 47, 47},
- { 52, 56},
- { 58, 59},
+ { 52, 59},
{ 61, 127},
{149, 150},
{162, 162},
@@ -5621,6 +5620,7 @@ static void validate_state_table(struct wined3d_state_entry *state_table)
STATE_BLEND,
STATE_BLEND_FACTOR,
STATE_DEPTH_STENCIL,
+ STATE_STENCIL_REF,
};
unsigned int i, current;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 101c0287936..f959cd51d68 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1827,7 +1827,10 @@ enum wined3d_pipeline
#define STATE_DEPTH_STENCIL (STATE_SAMPLE_MASK + 1)
#define STATE_IS_DEPTH_STENCIL(a) ((a) == STATE_DEPTH_STENCIL)
-#define STATE_COMPUTE_OFFSET (STATE_DEPTH_STENCIL + 1)
+#define STATE_STENCIL_REF (STATE_DEPTH_STENCIL + 1)
+#define STATE_IS_SAMPLE_REF(a) ((a) == STATE_STENCIL_REF)
+
+#define STATE_COMPUTE_OFFSET (STATE_STENCIL_REF + 1)
#define STATE_COMPUTE_SHADER (STATE_COMPUTE_OFFSET)
#define STATE_IS_COMPUTE_SHADER(a) ((a) == STATE_COMPUTE_SHADER)
@@ -3701,6 +3704,7 @@ struct wined3d_state
struct wined3d_color blend_factor;
unsigned int sample_mask;
struct wined3d_depth_stencil_state *depth_stencil_state;
+ unsigned int stencil_ref;
struct wined3d_rasterizer_state *rasterizer_state;
};
@@ -4740,7 +4744,7 @@ void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture
void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
UINT cb_idx, struct wined3d_buffer *buffer) DECLSPEC_HIDDEN;
void wined3d_cs_emit_set_depth_stencil_state(struct wined3d_cs *cs,
- struct wined3d_depth_stencil_state *state) DECLSPEC_HIDDEN;
+ struct wined3d_depth_stencil_state *state, unsigned int stencil_ref) DECLSPEC_HIDDEN;
void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs,
struct wined3d_rendertarget_view *view) DECLSPEC_HIDDEN;
void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 310911992ae..96cb6fc1d86 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2392,7 +2392,7 @@ struct wined3d_sampler * __cdecl wined3d_device_get_cs_sampler(const struct wine
struct wined3d_unordered_access_view * __cdecl wined3d_device_get_cs_uav(const struct wined3d_device *device,
unsigned int idx);
struct wined3d_depth_stencil_state * __cdecl wined3d_device_get_depth_stencil_state(
- const struct wined3d_device *device);
+ const struct wined3d_device *device, unsigned int *stencil_ref);
struct wined3d_rendertarget_view * __cdecl wined3d_device_get_depth_stencil_view(const struct wined3d_device *device);
HRESULT __cdecl wined3d_device_get_device_caps(const struct wined3d_device *device, struct wined3d_caps *caps);
HRESULT __cdecl wined3d_device_get_display_mode(const struct wined3d_device *device, UINT swapchain_idx,
@@ -2480,7 +2480,7 @@ void __cdecl wined3d_device_set_cursor_position(struct wined3d_device *device,
HRESULT __cdecl wined3d_device_set_cursor_properties(struct wined3d_device *device,
UINT x_hotspot, UINT y_hotspot, struct wined3d_texture *texture, unsigned int sub_resource_idx);
void __cdecl wined3d_device_set_depth_stencil_state(struct wined3d_device *device,
- struct wined3d_depth_stencil_state *state);
+ struct wined3d_depth_stencil_state *state, unsigned int stencil_ref);
HRESULT __cdecl wined3d_device_set_depth_stencil_view(struct wined3d_device *device,
struct wined3d_rendertarget_view *view);
HRESULT __cdecl wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs);
--
2.30.0
2
6
[PATCH v3] shell32: IPersistFile::Save(NULL) should use previously stored file name.
by Dmitry Timoshkov Feb. 3, 2021
by Dmitry Timoshkov Feb. 3, 2021
Feb. 3, 2021
v3: Fixed test failures under Windows Vista.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/shell32/shelllink.c | 16 ++++++++++++----
dlls/shell32/tests/shelllink.c | 16 ++++++++++++++++
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c
index 46d9bc994ff..69d610f2503 100644
--- a/dlls/shell32/shelllink.c
+++ b/dlls/shell32/shelllink.c
@@ -367,7 +367,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
if (!pszFileName)
- return E_FAIL;
+ {
+ if (!This->filepath) return S_OK;
+
+ pszFileName = This->filepath;
+ fRemember = FALSE;
+ }
r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
if( SUCCEEDED( r ) )
@@ -379,9 +384,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
{
StartLinkProcessor( pszFileName );
- /* update file path */
- heap_free(This->filepath);
- This->filepath = strdupW(pszFileName);
+ if (fRemember)
+ {
+ /* update file path */
+ heap_free(This->filepath);
+ This->filepath = strdupW(pszFileName);
+ }
This->bDirty = FALSE;
}
diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c
index 20c48814f1d..7245f5533f6 100644
--- a/dlls/shell32/tests/shelllink.c
+++ b/dlls/shell32/tests/shelllink.c
@@ -451,6 +451,12 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
IPersistFile_GetCurFile(pf, NULL);
}
+ r = IPersistFile_Save(pf, NULL, FALSE);
+ lok(r == S_OK || r == E_INVALIDARG /* before Windows 7 */, "save failed (0x%08x)\n", r);
+
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK || r == E_INVALIDARG /* before Windows 7 */, "save failed (0x%08x)\n", r);
+
/* test GetCurFile before ::Save */
str = (LPWSTR)0xdeadbeef;
r = IPersistFile_GetCurFile(pf, &str);
@@ -467,6 +473,16 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
CoTaskMemFree(str);
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK, "save failed (0x%08x)\n", r);
+
+ /* test GetCurFile after ::Save */
+ r = IPersistFile_GetCurFile(pf, &str);
+ lok(r == S_OK, "got 0x%08x\n", r);
+ lok(str != NULL, "Didn't expect NULL\n");
+ lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
IPersistFile_Release(pf);
}
--
2.29.2
1
0
[PATCH v2] shell32: IPersistFile::Save(NULL) should use previously stored file name.
by Dmitry Timoshkov Feb. 3, 2021
by Dmitry Timoshkov Feb. 3, 2021
Feb. 3, 2021
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/shell32/shelllink.c | 16 ++++++++++++----
dlls/shell32/tests/shelllink.c | 16 ++++++++++++++++
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c
index 46d9bc994ff..69d610f2503 100644
--- a/dlls/shell32/shelllink.c
+++ b/dlls/shell32/shelllink.c
@@ -367,7 +367,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
if (!pszFileName)
- return E_FAIL;
+ {
+ if (!This->filepath) return S_OK;
+
+ pszFileName = This->filepath;
+ fRemember = FALSE;
+ }
r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
if( SUCCEEDED( r ) )
@@ -379,9 +384,12 @@ static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFile
{
StartLinkProcessor( pszFileName );
- /* update file path */
- heap_free(This->filepath);
- This->filepath = strdupW(pszFileName);
+ if (fRemember)
+ {
+ /* update file path */
+ heap_free(This->filepath);
+ This->filepath = strdupW(pszFileName);
+ }
This->bDirty = FALSE;
}
diff --git a/dlls/shell32/tests/shelllink.c b/dlls/shell32/tests/shelllink.c
index 20c48814f1d..60271ace2ce 100644
--- a/dlls/shell32/tests/shelllink.c
+++ b/dlls/shell32/tests/shelllink.c
@@ -451,6 +451,12 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
IPersistFile_GetCurFile(pf, NULL);
}
+ r = IPersistFile_Save(pf, NULL, FALSE);
+ lok(r == S_OK, "save failed (0x%08x)\n", r);
+
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK, "save failed (0x%08x)\n", r);
+
/* test GetCurFile before ::Save */
str = (LPWSTR)0xdeadbeef;
r = IPersistFile_GetCurFile(pf, &str);
@@ -467,6 +473,16 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
CoTaskMemFree(str);
+ r = IPersistFile_Save(pf, NULL, TRUE);
+ lok(r == S_OK, "save failed (0x%08x)\n", r);
+
+ /* test GetCurFile after ::Save */
+ r = IPersistFile_GetCurFile(pf, &str);
+ lok(r == S_OK, "got 0x%08x\n", r);
+ lok(str != NULL, "Didn't expect NULL\n");
+ lok(!wcscmp(path, str), "Expected %s, got %s\n", wine_dbgstr_w(path), wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
IPersistFile_Release(pf);
}
--
2.29.2
2
1