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
February 2021
- 81 participants
- 640 discussions
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
---
dlls/concrt140/concrt140.spec | 259 ++++++++++++++++++++++++++++++----
1 file changed, 233 insertions(+), 26 deletions(-)
1
1
Feb. 3, 2021
Signed-off-by: Piotr Caban <piotr(a)codeweavers.com>
---
dlls/msvcr120/msvcr120.spec | 24 ++++++++++++------------
dlls/msvcr120_app/msvcr120_app.spec | 24 ++++++++++++------------
2 files changed, 24 insertions(+), 24 deletions(-)
1
0
[PATCH v4] gdi32: ExtTextOut should fail if count is larger than INT_MAX.
by Huw Davies Feb. 3, 2021
by Huw Davies Feb. 3, 2021
Feb. 3, 2021
From: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/gdi32/font.c | 3 +++
dlls/gdi32/tests/dib.c | 15 +++++++++++++-
dlls/gdi32/tests/metafile.c | 41 +++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 74ca4825de4..de50bf0de42 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 d16cb0df5c0..bdc3d9ed55b 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/metafile.c b/dlls/gdi32/tests/metafile.c
index 8dae908126d..e81cff1ae57 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -2394,6 +2394,26 @@ static void test_mf_ExtTextOut_on_path(void)
ok(ret, "DeleteMetaFile(%p) error %d\n", hMetafile, GetLastError());
}
+static const unsigned char EMF_EMPTY_BITS[] =
+{
+ 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff,
+ 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x90, 0x06, 0x00, 0x00, 0xba, 0x03, 0x00, 0x00,
+ 0x4e, 0x02, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x09, 0x00,
+ 0x10, 0x09, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00
+};
+
static void test_emf_ExtTextOut_on_path(void)
{
HWND hwnd;
@@ -2403,6 +2423,7 @@ static void test_emf_ExtTextOut_on_path(void)
LOGFONTA lf;
HFONT hFont;
static const INT dx[4] = { 3, 5, 8, 12 };
+ RECT rect = { 10, 20, 30, 40 };
/* Win9x doesn't play EMFs on invisible windows */
hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE,
@@ -2515,6 +2536,26 @@ static void test_emf_ExtTextOut_on_path(void)
ret = DeleteEnhMetaFile(hMetafile);
ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
+ /* test ExtTextOut with count == -1 doesn't get written */
+ hdcMetafile = CreateEnhMetaFileA(hdcDisplay, NULL, NULL, NULL);
+ ok(hdcMetafile != 0, "CreateEnhMetaFileA error %d\n", GetLastError());
+
+ ret = ExtTextOutA(hdcMetafile, 11, 22, ETO_OPAQUE, &rect, "Test", -1, dx);
+ ok(!ret, "ExtTextOut error %d\n", GetLastError());
+
+ hMetafile = CloseEnhMetaFile(hdcMetafile);
+ ok(hMetafile != 0, "CloseEnhMetaFile error %d\n", GetLastError());
+
+ if (compare_emf_bits(hMetafile, EMF_EMPTY_BITS, sizeof(EMF_EMPTY_BITS),
+ "emf_TextOut_negative_count", FALSE) != 0)
+ {
+ dump_emf_bits(hMetafile, "emf_TextOut_negative_count");
+ dump_emf_records(hMetafile, "emf_TextOut_negative_count");
+ }
+
+ ret = DeleteEnhMetaFile(hMetafile);
+ ok(ret, "DeleteEnhMetaFile error %d\n", GetLastError());
+
ret = ReleaseDC(hwnd, hdcDisplay);
ok(ret, "ReleaseDC error %d\n", GetLastError());
DestroyWindow(hwnd);
--
2.23.0
1
0
[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