Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- 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
November 2021
- 83 participants
- 2620 messages
Re: [PATCH] dmime: Fixup the Wave track parser
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=101316
Your paranoid android.
=== debiant2 (build log) ===
error: patch failed: dlls/dmime/dmime_private.h:86
error: patch failed: dlls/dmime/wavetrack.c:19
Task: Patch failed to apply
=== debiant2 (build log) ===
error: patch failed: dlls/dmime/dmime_private.h:86
error: patch failed: dlls/dmime/wavetrack.c:19
Task: Patch failed to apply
Nov. 4, 2021
[PATCH] dmime: Fixup the Wave track parser
by Michael Stefaniuc
An incomplete patch was prematurely added with 854895f70afeeb3c098ff32318353ec4fe7b9bc1
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmime/dmime_private.h | 6 -
dlls/dmime/wavetrack.c | 254 +++++++++++++++++++++----------------
2 files changed, 142 insertions(+), 118 deletions(-)
diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h
index 6ab47292b39..c2221a15fd2 100644
--- a/dlls/dmime/dmime_private.h
+++ b/dlls/dmime/dmime_private.h
@@ -86,12 +86,6 @@ typedef struct _DMUS_PRIVATE_TEMPO_ITEM {
DMUS_IO_TEMPO_ITEM item;
} DMUS_PRIVATE_TEMPO_ITEM, *LPDMUS_PRIVATE_TEMPO_ITEM;
-struct wave_item {
- struct list entry;
- DMUS_IO_WAVE_TRACK_HEADER header;
- IDirectMusicObject *object;
-};
-
typedef struct _DMUS_PRIVATE_GRAPH_TOOL {
struct list entry; /* for listing elements */
DWORD dwIndex;
diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c
index da7ef37d2c8..454695ebfb6 100644
--- a/dlls/dmime/wavetrack.c
+++ b/dlls/dmime/wavetrack.c
@@ -19,7 +19,6 @@
#include "dmime_private.h"
#include "dmobject.h"
-
#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(dmime);
@@ -27,15 +26,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime);
/*****************************************************************************
* IDirectMusicWaveTrack implementation
*/
-/*****************************************************************************
- * IDirectMusicChordMapTrack implementation
- */
+struct wave_item {
+ struct list entry;
+ DMUS_IO_WAVE_ITEM_HEADER header;
+ IDirectMusicObject *object;
+};
+
+struct wave_part {
+ struct list entry;
+ DMUS_IO_WAVE_PART_HEADER header;
+ struct list items;
+};
+
typedef struct IDirectMusicWaveTrack {
IDirectMusicTrack8 IDirectMusicTrack8_iface;
struct dmobject dmobj; /* IPersistStream only */
LONG ref;
-
- struct list items;
+ DMUS_IO_WAVE_TRACK_HEADER header;
+ struct list parts;
} IDirectMusicWaveTrack;
/* IDirectMusicWaveTrack IDirectMusicTrack8 part: */
@@ -90,20 +98,21 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface)
TRACE("(%p) ref=%d\n", This, ref);
if (!ref) {
- struct list *cursor, *cursor2;
- struct wave_item *item;
-
- LIST_FOR_EACH_SAFE(cursor, cursor2, &This->items) {
- item = LIST_ENTRY(cursor, struct wave_item, entry);
- list_remove(cursor);
-
- if (item->object)
- IDirectMusicObject_Release(item->object);
-
- heap_free(item);
+ struct wave_item *item, *item2;
+ struct wave_part *part, *part2;
+
+ LIST_FOR_EACH_ENTRY_SAFE(part, part2, &This->parts, struct wave_part, entry) {
+ list_remove(&part->entry);
+ LIST_FOR_EACH_ENTRY_SAFE(item, item2, &part->items, struct wave_item, entry) {
+ list_remove(&item->entry);
+ if (item->object)
+ IDirectMusicObject_Release(item->object);
+ heap_free(item);
+ }
+ heap_free(part);
}
- HeapFree(GetProcessHeap(), 0, This);
+ heap_free(This);
DMIME_UnlockModule();
}
@@ -302,131 +311,152 @@ static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
wave_track_Join
};
-static HRESULT parse_wave_item(IDirectMusicWaveTrack *This, IStream *stream,
- struct chunk_entry *wave, struct wave_item *item)
+static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct chunk_entry *wavi)
{
+ struct chunk_entry wave = {.parent = wavi};
+ struct chunk_entry chunk = {.parent = &wave};
+ struct wave_item *item;
HRESULT hr;
- struct chunk_entry chunk = {.parent = wave};
- if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ /* Nested list with two chunks */
+ if (FAILED(hr = stream_next_chunk(stream, &wave)))
return hr;
+ if (wave.id != FOURCC_LIST || wave.type != DMUS_FOURCC_WAVE_LIST)
+ return DMUS_E_UNSUPPORTED_STREAM;
- if(chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVE_LIST)
- {
- struct chunk_entry child = {.parent = &chunk};
- DMUS_IO_WAVE_ITEM_HEADER header;
-
- if (FAILED(hr = stream_next_chunk(stream, &child)))
- return hr;
-
- if(child.id != DMUS_FOURCC_WAVEITEM_CHUNK)
- return DMUS_E_UNSUPPORTED_STREAM;
+ if (!(item = heap_alloc_zero(sizeof(*item))))
+ return E_OUTOFMEMORY;
- if (FAILED(hr = stream_chunk_get_data(stream, &child, &header, sizeof(header)))) {
- WARN("Failed to read data of %s\n", debugstr_chunk(&child));
- return hr;
- }
+ /* Wave item header chunk */
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ goto error;
+ if (chunk.id != DMUS_FOURCC_WAVEITEM_CHUNK) {
+ hr = DMUS_E_UNSUPPORTED_STREAM;
+ goto error;
+ }
- TRACE("Found DMUS_IO_WAVE_ITEM_HEADER\n");
- TRACE(" - lVolume %d\n", header.lVolume);
- TRACE(" - dwVariations %d\n", header.dwVariations);
- TRACE(" - rtTime %s\n", wine_dbgstr_longlong(header.rtTime));
- TRACE(" - rtStartOffset %s\n", wine_dbgstr_longlong(header.rtStartOffset));
- TRACE(" - rtReserved %s\n", wine_dbgstr_longlong(header.rtReserved));
- TRACE(" - rtDuration %s\n", wine_dbgstr_longlong(header.rtDuration));
- TRACE(" - dwLoopStart %d\n", header.dwLoopStart);
- TRACE(" - dwLoopEnd %d\n", header.dwLoopEnd);
- TRACE(" - dwFlags 0x%08x\n", header.dwFlags);
- TRACE(" - wVolumeRange %d\n", header.wVolumeRange);
- TRACE(" - wPitchRange %d\n", header.wPitchRange);
-
- if (FAILED(hr = stream_next_chunk(stream, &child)))
- return hr;
-
- if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object)))
- return hr;
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &item->header, sizeof(item->header)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ goto error;
}
- else
+
+ TRACE("Found DMUS_IO_WAVE_ITEM_HEADER\n");
+ TRACE("\tlVolume %d\n", item->header.lVolume);
+ TRACE("\tdwVariations %d\n", item->header.dwVariations);
+ TRACE("\trtTime %s\n", wine_dbgstr_longlong(item->header.rtTime));
+ TRACE("\trtStartOffset %s\n", wine_dbgstr_longlong(item->header.rtStartOffset));
+ TRACE("\trtReserved %s\n", wine_dbgstr_longlong(item->header.rtReserved));
+ TRACE("\trtDuration %s\n", wine_dbgstr_longlong(item->header.rtDuration));
+ TRACE("\tdwLoopStart %d\n", item->header.dwLoopStart);
+ TRACE("\tdwLoopEnd %d\n", item->header.dwLoopEnd);
+ TRACE("\tdwFlags %#08x\n", item->header.dwFlags);
+ TRACE("\twVolumeRange %d\n", item->header.wVolumeRange);
+ TRACE("\twPitchRange %d\n", item->header.wPitchRange);
+
+ /* Second chunk is a reference list */
+ if (stream_next_chunk(stream, &chunk) != S_OK || chunk.id != FOURCC_LIST ||
+ chunk.type != DMUS_FOURCC_REF_LIST) {
hr = DMUS_E_UNSUPPORTED_STREAM;
+ goto error;
+ }
+ if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object)))
+ goto error;
- return SUCCEEDED(hr) ? S_OK : hr;
+ list_add_tail(&part->items, &item->entry);
+
+ return S_OK;
+
+error:
+ heap_free(item);
+ return hr;
}
-static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream)
+static HRESULT parse_wave_part(IDirectMusicWaveTrack *This, IStream *stream,
+ struct chunk_entry *wavp)
{
- IDirectMusicWaveTrack *This = impl_from_IPersistStream(iface);
+ struct chunk_entry chunk = {.parent = wavp};
+ struct wave_part *part;
HRESULT hr;
- struct chunk_entry chunk = {0};
-
- TRACE("%p, %p\n", This, stream);
-
- if (!stream)
- return E_POINTER;
- if ((hr = stream_get_chunk(stream, &chunk) != S_OK))
+ /* Wave part header chunk */
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
return hr;
+ if (chunk.id != DMUS_FOURCC_WAVEPART_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
- if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVETRACK_LIST)
- {
- struct chunk_entry chunklist = {.parent = &chunk};
- struct wave_item *item = NULL;
+ if (!(part = heap_alloc_zero(sizeof(*part))))
+ return E_OUTOFMEMORY;
+ list_init(&part->items);
- TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(&chunklist));
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &part->header, sizeof(part->header)))) {
+ WARN("Failed to read data of %s\n", debugstr_chunk(&chunk));
+ goto error;
+ }
- if (FAILED(hr = stream_next_chunk(stream, &chunklist)))
- return hr;
+ TRACE("Found DMUS_IO_WAVE_PART_HEADER\n");
+ TRACE("\tlVolume %d\n", part->header.lVolume);
+ TRACE("\tdwVariations %d\n", part->header.dwVariations);
+ TRACE("\tdwPChannel %d\n", part->header.dwPChannel);
+ TRACE("\tdwLockToPart %d\n", part->header.dwLockToPart);
+ TRACE("\tdwFlags %#08x\n", part->header.dwFlags);
+ TRACE("\tdwIndex %d\n", part->header.dwIndex);
- if (chunklist.id != DMUS_FOURCC_WAVETRACK_CHUNK)
- return DMUS_E_UNSUPPORTED_STREAM;
+ /* Array of wave items */
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
+ if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVEITEM_LIST)
+ if (FAILED(hr = parse_wave_item(part, stream, &chunk)))
+ break;
- item = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct wave_item));
- if (!item)
- return E_OUTOFMEMORY;
+ if (FAILED(hr))
+ goto error;
- list_add_tail (&This->items, &item->entry);
+ list_add_tail(&This->parts, &part->entry);
- if (FAILED(hr = stream_next_chunk(stream, &chunklist)))
- return hr;
+ return S_OK;
- if (chunklist.id == FOURCC_LIST && chunklist.type == DMUS_FOURCC_WAVEPART_LIST)
- {
- struct chunk_entry child = {.parent = &chunklist};
- DMUS_IO_WAVE_PART_HEADER header;
+error:
+ heap_free(part);
+ return hr;
+}
+
+static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream)
+{
+ IDirectMusicWaveTrack *This = impl_from_IPersistStream(iface);
+ struct chunk_entry wavt = {0};
+ struct chunk_entry chunk = {.parent = &wavt};
+ HRESULT hr;
- if (FAILED(hr = stream_next_chunk(stream, &child)))
- return hr;
+ TRACE("%p, %p\n", This, stream);
- if (child.id != DMUS_FOURCC_WAVEPART_CHUNK)
- return DMUS_E_UNSUPPORTED_STREAM;
+ if (!stream)
+ return E_POINTER;
- if (FAILED(hr = stream_chunk_get_data(stream, &child, &header, sizeof(header)))) {
- WARN("Failed to read data of %s\n", debugstr_chunk(&child));
- return hr;
- }
+ if ((hr = stream_get_chunk(stream, &wavt) != S_OK))
+ return hr;
+ if (wavt.id != FOURCC_LIST || wavt.type != DMUS_FOURCC_WAVETRACK_LIST)
+ return DMUS_E_UNSUPPORTED_STREAM;
- TRACE("Found DMUS_IO_WAVE_PART_HEADER\n");
- TRACE(" - lVolume %d\n", header.lVolume);
- TRACE(" - dwVariations %d\n", header.dwVariations);
- TRACE(" - dwPChannel %d\n", header.dwPChannel);
- TRACE(" - dwLockToPart %d\n", header.dwLockToPart);
- TRACE(" - dwFlags 0x%08x\n", header.dwFlags);
- TRACE(" - dwIndex %d\n", header.dwIndex);
+ TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(&wavt));
- if (FAILED(hr = stream_next_chunk(stream, &child)))
- return hr;
+ /* Track header chunk */
+ if (FAILED(hr = stream_next_chunk(stream, &chunk)))
+ return hr;
+ if (chunk.id != DMUS_FOURCC_WAVETRACK_CHUNK)
+ return DMUS_E_UNSUPPORTED_STREAM;
+ if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header))))
+ return hr;
- if(child.id != FOURCC_LIST || child.type != DMUS_FOURCC_WAVEITEM_LIST)
- return DMUS_E_UNSUPPORTED_STREAM;
+ TRACE("Found DMUS_IO_WAVE_TRACK_HEADER\n");
+ TRACE("\tlVolume %d\n", This->header.lVolume);
+ TRACE("\tdwFlags %#08x\n", This->header.dwFlags);
- hr = parse_wave_item(This, stream, &child, item);
- }
- else
- hr = DMUS_E_UNSUPPORTED_STREAM;
- }
- else
- hr = DMUS_E_UNSUPPORTED_STREAM;
+ /* Array of wave parts */
+ while ((hr = stream_next_chunk(stream, &chunk)) == S_OK)
+ if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVEPART_LIST)
+ if (FAILED(hr = parse_wave_part(This, stream, &chunk)))
+ break;
- return hr;
+ return SUCCEEDED(hr) ? S_OK : hr;
}
static const IPersistStreamVtbl persiststream_vtbl = {
@@ -456,7 +486,7 @@ HRESULT WINAPI create_dmwavetrack(REFIID lpcGUID, void **ppobj)
dmobject_init(&track->dmobj, &CLSID_DirectMusicWaveTrack,
(IUnknown *)&track->IDirectMusicTrack8_iface);
track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
- list_init(&track->items);
+ list_init(&track->parts);
DMIME_LockModule();
hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
--
2.31.1
Nov. 4, 2021
Re: Alistair Leslie-Hughes : dmime: Parse Wave track stream.
by Michael Stefaniuc
The sign-off was on my own patch attached to the reply to this patch.
Yes, 2am in the morning so I forgot to remove the sign-off as my patch wasn't
ready either...
bye
michael
On 11/4/21 23:04, Alexandre Julliard wrote:
> Module: wine
> Branch: master
> Commit: 854895f70afeeb3c098ff32318353ec4fe7b9bc1
> URL: https://source.winehq.org/git/wine.git/?a=commit;h=854895f70afeeb3c098ff323…
>
> Author: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
> Date: Mon Nov 1 17:30:54 2021 +1100
>
> dmime: Parse Wave track stream.
>
> For Tron 2.0.
>
> Signed-off-by: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
> Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
> Signed-off-by: Alexandre Julliard <julliard(a)winehq.org>
>
> ---
>
> dlls/dmime/dmime_private.h | 6 ++
> dlls/dmime/wavetrack.c | 148 ++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 152 insertions(+), 2 deletions(-)
>
> diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h
> index c2221a15fd2..6ab47292b39 100644
> --- a/dlls/dmime/dmime_private.h
> +++ b/dlls/dmime/dmime_private.h
> @@ -86,6 +86,12 @@ typedef struct _DMUS_PRIVATE_TEMPO_ITEM {
> DMUS_IO_TEMPO_ITEM item;
> } DMUS_PRIVATE_TEMPO_ITEM, *LPDMUS_PRIVATE_TEMPO_ITEM;
>
> +struct wave_item {
> + struct list entry;
> + DMUS_IO_WAVE_TRACK_HEADER header;
> + IDirectMusicObject *object;
> +};
> +
> typedef struct _DMUS_PRIVATE_GRAPH_TOOL {
> struct list entry; /* for listing elements */
> DWORD dwIndex;
> diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c
> index 1c6b08b5235..da7ef37d2c8 100644
> --- a/dlls/dmime/wavetrack.c
> +++ b/dlls/dmime/wavetrack.c
> @@ -20,6 +20,8 @@
> #include "dmime_private.h"
> #include "dmobject.h"
>
> +#include "wine/heap.h"
> +
> WINE_DEFAULT_DEBUG_CHANNEL(dmime);
>
> /*****************************************************************************
> @@ -32,6 +34,8 @@ typedef struct IDirectMusicWaveTrack {
> IDirectMusicTrack8 IDirectMusicTrack8_iface;
> struct dmobject dmobj; /* IPersistStream only */
> LONG ref;
> +
> + struct list items;
> } IDirectMusicWaveTrack;
>
> /* IDirectMusicWaveTrack IDirectMusicTrack8 part: */
> @@ -40,6 +44,11 @@ static inline IDirectMusicWaveTrack *impl_from_IDirectMusicTrack8(IDirectMusicTr
> return CONTAINING_RECORD(iface, IDirectMusicWaveTrack, IDirectMusicTrack8_iface);
> }
>
> +static inline IDirectMusicWaveTrack *impl_from_IPersistStream(IPersistStream *iface)
> +{
> + return CONTAINING_RECORD(iface, IDirectMusicWaveTrack, dmobj.IPersistStream_iface);
> +}
> +
> static HRESULT WINAPI wave_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid,
> void **ret_iface)
> {
> @@ -81,6 +90,19 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface)
> TRACE("(%p) ref=%d\n", This, ref);
>
> if (!ref) {
> + struct list *cursor, *cursor2;
> + struct wave_item *item;
> +
> + LIST_FOR_EACH_SAFE(cursor, cursor2, &This->items) {
> + item = LIST_ENTRY(cursor, struct wave_item, entry);
> + list_remove(cursor);
> +
> + if (item->object)
> + IDirectMusicObject_Release(item->object);
> +
> + heap_free(item);
> + }
> +
> HeapFree(GetProcessHeap(), 0, This);
> DMIME_UnlockModule();
> }
> @@ -280,10 +302,131 @@ static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = {
> wave_track_Join
> };
>
> +static HRESULT parse_wave_item(IDirectMusicWaveTrack *This, IStream *stream,
> + struct chunk_entry *wave, struct wave_item *item)
> +{
> + HRESULT hr;
> + struct chunk_entry chunk = {.parent = wave};
> +
> + if (FAILED(hr = stream_next_chunk(stream, &chunk)))
> + return hr;
> +
> + if(chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVE_LIST)
> + {
> + struct chunk_entry child = {.parent = &chunk};
> + DMUS_IO_WAVE_ITEM_HEADER header;
> +
> + if (FAILED(hr = stream_next_chunk(stream, &child)))
> + return hr;
> +
> + if(child.id != DMUS_FOURCC_WAVEITEM_CHUNK)
> + return DMUS_E_UNSUPPORTED_STREAM;
> +
> + if (FAILED(hr = stream_chunk_get_data(stream, &child, &header, sizeof(header)))) {
> + WARN("Failed to read data of %s\n", debugstr_chunk(&child));
> + return hr;
> + }
> +
> + TRACE("Found DMUS_IO_WAVE_ITEM_HEADER\n");
> + TRACE(" - lVolume %d\n", header.lVolume);
> + TRACE(" - dwVariations %d\n", header.dwVariations);
> + TRACE(" - rtTime %s\n", wine_dbgstr_longlong(header.rtTime));
> + TRACE(" - rtStartOffset %s\n", wine_dbgstr_longlong(header.rtStartOffset));
> + TRACE(" - rtReserved %s\n", wine_dbgstr_longlong(header.rtReserved));
> + TRACE(" - rtDuration %s\n", wine_dbgstr_longlong(header.rtDuration));
> + TRACE(" - dwLoopStart %d\n", header.dwLoopStart);
> + TRACE(" - dwLoopEnd %d\n", header.dwLoopEnd);
> + TRACE(" - dwFlags 0x%08x\n", header.dwFlags);
> + TRACE(" - wVolumeRange %d\n", header.wVolumeRange);
> + TRACE(" - wPitchRange %d\n", header.wPitchRange);
> +
> + if (FAILED(hr = stream_next_chunk(stream, &child)))
> + return hr;
> +
> + if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object)))
> + return hr;
> + }
> + else
> + hr = DMUS_E_UNSUPPORTED_STREAM;
> +
> + return SUCCEEDED(hr) ? S_OK : hr;
> +}
> +
> static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream)
> {
> - FIXME(": Loading not implemented yet\n");
> - return S_OK;
> + IDirectMusicWaveTrack *This = impl_from_IPersistStream(iface);
> + HRESULT hr;
> + struct chunk_entry chunk = {0};
> +
> + TRACE("%p, %p\n", This, stream);
> +
> + if (!stream)
> + return E_POINTER;
> +
> + if ((hr = stream_get_chunk(stream, &chunk) != S_OK))
> + return hr;
> +
> + if (chunk.id == FOURCC_LIST && chunk.type == DMUS_FOURCC_WAVETRACK_LIST)
> + {
> + struct chunk_entry chunklist = {.parent = &chunk};
> + struct wave_item *item = NULL;
> +
> + TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(&chunklist));
> +
> + if (FAILED(hr = stream_next_chunk(stream, &chunklist)))
> + return hr;
> +
> + if (chunklist.id != DMUS_FOURCC_WAVETRACK_CHUNK)
> + return DMUS_E_UNSUPPORTED_STREAM;
> +
> + item = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct wave_item));
> + if (!item)
> + return E_OUTOFMEMORY;
> +
> + list_add_tail (&This->items, &item->entry);
> +
> + if (FAILED(hr = stream_next_chunk(stream, &chunklist)))
> + return hr;
> +
> + if (chunklist.id == FOURCC_LIST && chunklist.type == DMUS_FOURCC_WAVEPART_LIST)
> + {
> + struct chunk_entry child = {.parent = &chunklist};
> + DMUS_IO_WAVE_PART_HEADER header;
> +
> + if (FAILED(hr = stream_next_chunk(stream, &child)))
> + return hr;
> +
> + if (child.id != DMUS_FOURCC_WAVEPART_CHUNK)
> + return DMUS_E_UNSUPPORTED_STREAM;
> +
> + if (FAILED(hr = stream_chunk_get_data(stream, &child, &header, sizeof(header)))) {
> + WARN("Failed to read data of %s\n", debugstr_chunk(&child));
> + return hr;
> + }
> +
> + TRACE("Found DMUS_IO_WAVE_PART_HEADER\n");
> + TRACE(" - lVolume %d\n", header.lVolume);
> + TRACE(" - dwVariations %d\n", header.dwVariations);
> + TRACE(" - dwPChannel %d\n", header.dwPChannel);
> + TRACE(" - dwLockToPart %d\n", header.dwLockToPart);
> + TRACE(" - dwFlags 0x%08x\n", header.dwFlags);
> + TRACE(" - dwIndex %d\n", header.dwIndex);
> +
> + if (FAILED(hr = stream_next_chunk(stream, &child)))
> + return hr;
> +
> + if(child.id != FOURCC_LIST || child.type != DMUS_FOURCC_WAVEITEM_LIST)
> + return DMUS_E_UNSUPPORTED_STREAM;
> +
> + hr = parse_wave_item(This, stream, &child, item);
> + }
> + else
> + hr = DMUS_E_UNSUPPORTED_STREAM;
> + }
> + else
> + hr = DMUS_E_UNSUPPORTED_STREAM;
> +
> + return hr;
> }
>
> static const IPersistStreamVtbl persiststream_vtbl = {
> @@ -313,6 +456,7 @@ HRESULT WINAPI create_dmwavetrack(REFIID lpcGUID, void **ppobj)
> dmobject_init(&track->dmobj, &CLSID_DirectMusicWaveTrack,
> (IUnknown *)&track->IDirectMusicTrack8_iface);
> track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl;
> + list_init(&track->items);
>
> DMIME_LockModule();
> hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj);
>
>
Nov. 4, 2021
[PATCH v4 2/2] ntdll: Prevent loading Wine system dependencies in place of identically named application DLLs.
by Zebediah Figura
That is, load Wine system dependencies only when they are imported from Wine
builtins or other system dependencies, and do not match a Wine system dependency
by its base name when looking for already-loaded modules.
The reasoning is that it is possible for an application to ship, and expect to
use, a newer version of a MinGW-compiled library, or one with custom patches, or
possibly an unrelated library with the same name. We don't want to offer Wine's
system dependencies in place of the application's, or vice versa.
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
v4: Use a separate field in WINE_MODREF instead of adding a private flag to the
LDR_DATA_TABLE_ENTRY.Flags field.
dlls/ntdll/loader.c | 47 ++++++++++++++++++++++++++-------------------
1 file changed, 27 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index a9578ae86bf..9e7fa6f5045 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -135,6 +135,7 @@ typedef struct _wine_modref
LDR_DATA_TABLE_ENTRY ldr;
struct file_id id;
ULONG CheckSum;
+ BOOL system;
} WINE_MODREF;
static UINT tls_module_count; /* number of modules with TLS directory */
@@ -186,7 +187,7 @@ static WINE_MODREF *last_failed_modref;
static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
- DWORD flags, WINE_MODREF** pwm );
+ DWORD flags, WINE_MODREF **pwm, BOOL system );
static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved );
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
@@ -505,21 +506,22 @@ static WINE_MODREF *get_modref( HMODULE hmod )
* Find a module from its base name.
* The loader_section must be locked while calling this function
*/
-static WINE_MODREF *find_basename_module( LPCWSTR name )
+static WINE_MODREF *find_basename_module( const WCHAR *name, BOOL system )
{
PLIST_ENTRY mark, entry;
UNICODE_STRING name_str;
RtlInitUnicodeString( &name_str, name );
- if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
+ if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE )
+ && system == cached_modref->system)
return cached_modref;
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
{
- LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
- if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE ))
+ WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks);
+ if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && system == mod->system)
{
cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
return cached_modref;
@@ -714,6 +716,8 @@ static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
*/
static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
{
+ WINE_MODREF *imp = get_modref( module );
+ BOOL system = imp->system || (imp->ldr.Flags & LDR_WINE_INTERNAL);
const IMAGE_EXPORT_DIRECTORY *exports;
DWORD exp_size;
WINE_MODREF *wm;
@@ -733,10 +737,10 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
if (!wcschr( mod_name, '.' ))
memcpy( mod_name + (end - forward), L".dll", sizeof(L".dll") );
- if (!(wm = find_basename_module( mod_name )))
+ if (!(wm = find_basename_module( mod_name, system )))
{
TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
- if (load_dll( load_path, mod_name, L".dll", 0, &wm ) == STATUS_SUCCESS &&
+ if (load_dll( load_path, mod_name, L".dll", 0, &wm, system ) == STATUS_SUCCESS &&
!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
{
if (!imports_fixup_done && current_modref)
@@ -903,6 +907,7 @@ void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
*/
static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
{
+ BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL);
NTSTATUS status;
WINE_MODREF *wmImp;
HMODULE imp_mod;
@@ -936,7 +941,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
{
ascii_to_unicode( buffer, name, len );
buffer[len] = 0;
- status = load_dll( load_path, buffer, L".dll", 0, &wmImp );
+ status = load_dll( load_path, buffer, L".dll", 0, &wmImp, system );
}
else /* need to allocate a larger buffer */
{
@@ -944,7 +949,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
if (!ptr) return FALSE;
ascii_to_unicode( ptr, name, len );
ptr[len] = 0;
- status = load_dll( load_path, ptr, L".dll", 0, &wmImp );
+ status = load_dll( load_path, ptr, L".dll", 0, &wmImp, system );
RtlFreeHeap( GetProcessHeap(), 0, ptr );
}
@@ -1216,7 +1221,7 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
prev = current_modref;
current_modref = wm;
assert( !wm->ldr.DdagNode->Dependencies.Tail );
- if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp ))
+ if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp, FALSE ))
&& !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
status = STATUS_NO_MEMORY;
current_modref = prev;
@@ -2902,7 +2907,7 @@ done:
*/
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
- SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
+ SECTION_IMAGE_INFORMATION *image_info, struct file_id *id, BOOL system )
{
WCHAR *ext, *dllname;
NTSTATUS status;
@@ -2943,7 +2948,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, con
else
{
if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
- if ((*pwm = find_basename_module( libname )) != NULL)
+ if ((*pwm = find_basename_module( libname, system )) != NULL)
{
status = STATUS_SUCCESS;
goto done;
@@ -2976,7 +2981,7 @@ done:
* The loader_section must be locked while calling this function.
*/
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
- DWORD flags, WINE_MODREF** pwm )
+ DWORD flags, WINE_MODREF **pwm, BOOL system )
{
UNICODE_STRING nt_name;
struct file_id id;
@@ -2987,10 +2992,10 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- if (system_dll_path.Buffer)
- nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ if (system && system_dll_path.Buffer)
+ nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id, TRUE );
if (nts)
- nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id, FALSE );
if (*pwm) /* found already loaded module */
{
@@ -3027,6 +3032,8 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
break;
}
+ (*pwm)->system = system;
+
if (NtCurrentTeb64())
NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev;
else
@@ -3084,7 +3091,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
RtlEnterCriticalSection( &loader_section );
- nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm );
+ nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm, FALSE );
if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
{
@@ -3159,7 +3166,7 @@ NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_ch
RtlEnterCriticalSection( &loader_section );
- status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id );
+ status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id, FALSE );
if (wm) *base = wm->ldr.DllBase;
else
@@ -3860,7 +3867,7 @@ static void init_wow64( CONTEXT *context )
NTSTATUS status;
static const WCHAR wow64_path[] = L"C:\\windows\\system32\\wow64.dll";
- if ((status = load_dll( NULL, wow64_path, NULL, 0, &wm )))
+ if ((status = load_dll( NULL, wow64_path, NULL, 0, &wm, FALSE )))
{
ERR( "could not load %s, status %x\n", debugstr_w(wow64_path), status );
NtTerminateProcess( GetCurrentProcess(), status );
@@ -4010,7 +4017,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
- if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32 )) != STATUS_SUCCESS)
+ if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32, FALSE )) != STATUS_SUCCESS)
{
MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
NtTerminateProcess( GetCurrentProcess(), status );
--
2.33.0
Nov. 4, 2021
[PATCH v4 1/2] ntdll: Allow loading system DLLs from a path specified at configure time.
by Zebediah Figura
Many distributions provide MinGW-compiled system DLLs which are currently
bundled with Wine. Unfortunately, while MinGW pkg-config can be used to detect
the linking path, there is no standardized runtime path, and many distributions
in fact use different paths.
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
Makefile.in | 1 +
configure.ac | 3 +++
dlls/ntdll/Makefile.in | 1 +
dlls/ntdll/loader.c | 10 ++++++++--
dlls/ntdll/unix/env.c | 1 +
dlls/ntdll/unix/loader.c | 3 +++
dlls/ntdll/unix/unix_private.h | 1 +
7 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 42f161e3af9..c4b0fbda616 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -32,6 +32,7 @@ nlsdir = ${datadir}/wine/nls
dlldir = ${libdir}/wine
srcdir = @srcdir@
host_cpu = @host_cpu@
+system_dlldir = @system_dlldir@
SHELL = /bin/sh
CC = @CC@
CXX = @CXX@
diff --git a/configure.ac b/configure.ac
index 57383fb2e31..77765db0490 100644
--- a/configure.ac
+++ b/configure.ac
@@ -103,6 +103,7 @@ AC_ARG_WITH(xshm, AS_HELP_STRING([--without-xshm],[do not use XShm (shared
AC_ARG_WITH(xxf86vm, AS_HELP_STRING([--without-xxf86vm],[do not use XFree video mode extension]),
[if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_xf86vmode_h=no; ac_cv_header_X11_extensions_xf86vmproto_h=no; fi])
+AC_ARG_WITH(system-dlldir, AS_HELP_STRING([--with-system-dlldir=DIR],[load external PE dependencies from directory DIR]))
AC_ARG_WITH(wine-tools,AS_HELP_STRING([--with-wine-tools=DIR],[use Wine tools from directory DIR]))
AC_ARG_WITH(wine64, AS_HELP_STRING([--with-wine64=DIR],[use the 64-bit Wine in DIR for a Wow64 build]))
@@ -256,6 +257,8 @@ then
TARGETFLAGS="-b $host_alias $TARGETFLAGS"
fi
+AC_SUBST(system_dlldir,"$with_system_dlldir")
+
dnl Check for flex
AC_CHECK_PROGS(FLEX,flex,none)
if test "$FLEX" = "none"
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index fa2ac1623ea..5b15ab5108f 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -73,5 +73,6 @@ EXTRA_OBJS = unix/version.o
unix_loader_EXTRADEFS = \
-DBINDIR=\"${bindir}\" \
+ -DSYSTEMDLLDIR=\"${system_dlldir}\" \
-DDLL_TO_BINDIR=\"`${MAKEDEP} -R ${dlldir} ${bindir}`\" \
-DBIN_TO_DATADIR=\"`${MAKEDEP} -R ${bindir} ${datadir}/wine`\"
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 255d5afef79..a9578ae86bf 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -95,6 +95,7 @@ static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
static ULONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
static ULONG dll_safe_mode = 1; /* dll search mode */
static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
+static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */
static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
static WCHAR *default_load_path; /* default dll search path */
@@ -2981,12 +2982,15 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
struct file_id id;
HANDLE mapping = 0;
SECTION_IMAGE_INFORMATION image_info;
- NTSTATUS nts;
+ NTSTATUS nts = STATUS_DLL_NOT_FOUND;
ULONG64 prev;
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ if (system_dll_path.Buffer)
+ nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ if (nts)
+ nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
if (*pwm) /* found already loaded module */
{
@@ -3997,6 +4001,8 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
load_global_options();
version_init();
+ get_env_var( L"WINESYSTEMDLLDIR", 0, &system_dll_path );
+
wm = build_main_module();
wm->ldr.LoadCount = -1;
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c
index 43a34bf831b..1647603efa5 100644
--- a/dlls/ntdll/unix/env.c
+++ b/dlls/ntdll/unix/env.c
@@ -1296,6 +1296,7 @@ static void add_dynamic_environment( WCHAR **env, SIZE_T *pos, SIZE_T *size )
add_path_var( env, pos, size, "WINEHOMEDIR", home_dir );
add_path_var( env, pos, size, "WINEBUILDDIR", build_dir );
add_path_var( env, pos, size, "WINECONFIGDIR", config_dir );
+ add_path_var( env, pos, size, "WINESYSTEMDLLDIR", system_dll_path );
for (i = 0; dll_paths[i]; i++)
{
sprintf( str, "WINEDLLDIR%u", i );
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 0ca4b1ea6dd..9fdcc236fb1 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -388,6 +388,7 @@ const char *data_dir = NULL;
const char *build_dir = NULL;
const char *config_dir = NULL;
const char **dll_paths = NULL;
+const char *system_dll_path = NULL;
const char *user_name = NULL;
SECTION_IMAGE_INFORMATION main_image_info = { NULL };
static HMODULE ntdll_module;
@@ -619,6 +620,8 @@ static void init_paths( char *argv[] )
data_dir = build_path( bin_dir, BIN_TO_DATADIR );
}
+ if (strlen(SYSTEMDLLDIR)) system_dll_path = SYSTEMDLLDIR;
+
set_dll_path();
set_home_dir();
set_config_dir();
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 792cb33710d..01c7cc1c103 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -125,6 +125,7 @@ extern const char *build_dir DECLSPEC_HIDDEN;
extern const char *config_dir DECLSPEC_HIDDEN;
extern const char *user_name DECLSPEC_HIDDEN;
extern const char **dll_paths DECLSPEC_HIDDEN;
+extern const char *system_dll_path DECLSPEC_HIDDEN;
extern PEB *peb DECLSPEC_HIDDEN;
extern USHORT *uctable DECLSPEC_HIDDEN;
extern USHORT *lctable DECLSPEC_HIDDEN;
--
2.33.0
Nov. 4, 2021
Re: [PATCH] msxml3: Allow DOMDocument in VT_DISPATCH slot for put_output.
by Nikolay Sivov
On 11/4/21 11:58 PM, Jefferson Carpenter wrote:
> Regarding locking the DOMDocument while it is being written to:
>
> It looks like DOMDocument is meant to be used in a single-threaded
> manner[1], so it should be all right to just grab an interface and not
> worry about threads attempting to manipulate the document while it is
> being written to by an mxwriter.
There are freethreaded classes as well.
>
> For how to lock it, unless anyone has a better idea I think it would
> work to add an IWineXMLDOMDocumentLock interface with lock() and
> unlock() methods, and output a FIXME if this interface is unavailable.
I think your best bet at the moment is to load whole document at once
from stream, on endDocument. Right way would probably be similar to how
libxml2 does it - using SAX callbacks to construct DOM tree, and then
using SAX reader when loading from stream, or writer calling them.
>
>
> thanks,
> Jefferson
>
> [1]
> https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms756987…
Nov. 4, 2021
Re: AppDB: Bug #49999 - It should be possible to submit results for all versions of the current stable branch
by Rosanne DiMesio
On Thu, 4 Nov 2021 20:57:18 +0100
Joerg Schiermeier <news(a)Schiermeier-IT.de> wrote:
>
> Therefore the AppDB list should include the "outdated" minor releases
> of the current stable branch for selection aswell. This is currently
> not the case (only 5.0.2 is available for selection currently).
The AppDB reads the list of Wine versions directly from Bugzilla, which does not distinguish branches; it is simply a list of numbers, in order of release. After Wine 1.0 came out, the AppDB code was changed to keep all the stable releases available for selection in a separate list, while still getting the development releases from Bugzilla. Since doing that required someone to actively send patches to manually add each stable release to the stable list, that worked out about as well as you might expect. One of the changes I made to the AppDB a few years ago was to get rid of the separate list, but expand the the number of releases available for selection from six to ten. With stable updates on roughly a three month cycle, that has meant the latest stable release is always available for selection, without any manual intervention.
Expanding the number of versions available for selection is the easiest way to keep all the current stable updates available, but that list will then also include all the development releases in the same range, leading to a very long dropdown list. Maintaining a separate list of stable releases would require more extensive changes to the code, and if it does not include some mechanism to automatically fetch the stable versions from Bugzilla, will probably fail for the same reason the last attempt did.
--
Rosanne DiMesio <dimesio(a)earthlink.net>
Nov. 4, 2021
[PATCH] msxml3: Allow DOMDocument in VT_DISPATCH slot for put_output.
by Jefferson Carpenter
Regarding locking the DOMDocument while it is being written to:
It looks like DOMDocument is meant to be used in a single-threaded
manner[1], so it should be all right to just grab an interface and not
worry about threads attempting to manipulate the document while it is
being written to by an mxwriter.
For how to lock it, unless anyone has a better idea I think it would
work to add an IWineXMLDOMDocumentLock interface with lock() and
unlock() methods, and output a FIXME if this interface is unavailable.
thanks,
Jefferson
[1]
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms756987…
Nov. 4, 2021
[PATCH 5/5] winegstreamer: Implement IWMReaderAdvanced::SetUserProvidedClock().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/wm_asyncreader.c | 67 ++++++++++++++++++++++-------
dlls/wmvcore/tests/wmvcore.c | 47 ++++++++++----------
2 files changed, 74 insertions(+), 40 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index d4bd8914dd6..4193d7d75de 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -41,6 +41,9 @@ struct async_reader
CONDITION_VARIABLE stream_cv;
bool running;
+
+ bool user_clock;
+ QWORD user_time;
};
static REFERENCE_TIME get_current_time(const struct async_reader *reader)
@@ -85,22 +88,35 @@ static DWORD WINAPI stream_thread(void *arg)
hr = wm_reader_get_stream_sample(&reader->reader.streams[i], &sample, &pts, &duration, &flags);
if (hr == S_OK)
{
- for (;;)
+ if (reader->user_clock)
{
- REFERENCE_TIME current_time = get_current_time(reader);
-
- if (pts <= current_time - start_time)
- break;
-
- SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs,
- (pts - (current_time - start_time)) / 10000);
-
+ while (pts > reader->user_time && reader->running)
+ SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE);
if (!reader->running)
{
INSSBuffer_Release(sample);
goto out;
}
}
+ else
+ {
+ for (;;)
+ {
+ REFERENCE_TIME current_time = get_current_time(reader);
+
+ if (pts <= current_time - start_time)
+ break;
+
+ SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs,
+ (pts - (current_time - start_time)) / 10000);
+
+ if (!reader->running)
+ {
+ INSSBuffer_Release(sample);
+ goto out;
+ }
+ }
+ }
IWMReaderCallback_OnSample(callback, i, pts, duration, flags, sample, reader->context);
INSSBuffer_Release(sample);
@@ -276,6 +292,7 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface,
wm_reader_seek(&reader->reader, start, duration);
reader->running = true;
+ reader->user_time = 0;
if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL)))
{
@@ -360,9 +377,14 @@ static ULONG WINAPI WMReaderAdvanced_Release(IWMReaderAdvanced6 *iface)
static HRESULT WINAPI WMReaderAdvanced_SetUserProvidedClock(IWMReaderAdvanced6 *iface, BOOL user_clock)
{
- struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
- FIXME("(%p)->(%x)\n", This, user_clock);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+
+ TRACE("reader %p, user_clock %d.\n", reader, user_clock);
+
+ EnterCriticalSection(&reader->stream_cs);
+ reader->user_clock = !!user_clock;
+ LeaveCriticalSection(&reader->stream_cs);
+ return S_OK;
}
static HRESULT WINAPI WMReaderAdvanced_GetUserProvidedClock(IWMReaderAdvanced6 *iface, BOOL *user_clock)
@@ -374,9 +396,24 @@ static HRESULT WINAPI WMReaderAdvanced_GetUserProvidedClock(IWMReaderAdvanced6 *
static HRESULT WINAPI WMReaderAdvanced_DeliverTime(IWMReaderAdvanced6 *iface, QWORD time)
{
- struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
- FIXME("(%p)->(%s)\n", This, wine_dbgstr_longlong(time));
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+
+ TRACE("reader %p, time %s.\n", reader, debugstr_time(time));
+
+ EnterCriticalSection(&reader->stream_cs);
+
+ if (!reader->user_clock)
+ {
+ LeaveCriticalSection(&reader->stream_cs);
+ WARN("Not using a user-provided clock; returning E_UNEXPECTED.\n");
+ return E_UNEXPECTED;
+ }
+
+ reader->user_time = time;
+
+ LeaveCriticalSection(&reader->stream_cs);
+ WakeConditionVariable(&reader->stream_cv);
+ return S_OK;
}
static HRESULT WINAPI WMReaderAdvanced_SetManualStreamSelection(IWMReaderAdvanced6 *iface, BOOL selection)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 4cc285c2c73..0e7c6380c92 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1288,38 +1288,35 @@ static void test_async_reader_streaming(void)
* according to their presentation time. Call DeliverTime with the file
* duration in order to request all samples as fast as possible. */
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
- todo_wine ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
+ ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
- if (hr == S_OK)
- {
- hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
- ret = WaitForSingleObject(callback.eof_event, 1000);
- ok(!ret, "Wait timed out.\n");
- ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
+ ret = WaitForSingleObject(callback.eof_event, 1000);
+ ok(!ret, "Wait timed out.\n");
+ ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
- hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
- ret = WaitForSingleObject(callback.eof_event, 1000);
- ok(!ret, "Wait timed out.\n");
- ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
+ ret = WaitForSingleObject(callback.eof_event, 1000);
+ ok(!ret, "Wait timed out.\n");
+ ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
- hr = IWMReader_Stop(reader);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ret = WaitForSingleObject(callback.got_stopped, 1000);
- ok(!ret, "Wait timed out.\n");
+ hr = IWMReader_Stop(reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
- hr = IWMReader_Stop(reader);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ret = WaitForSingleObject(callback.got_stopped, 1000);
- ok(!ret, "Wait timed out.\n");
- }
+ hr = IWMReader_Stop(reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
test_reader_attributes(profile);
--
2.33.0
Nov. 4, 2021
[PATCH 4/5] winegstreamer: Implement IWMReader::Start().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/wm_asyncreader.c | 167 ++++++++++++++++++++++++++--
dlls/wmvcore/tests/wmvcore.c | 25 +++--
2 files changed, 178 insertions(+), 14 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 860ec1cdd5e..d4bd8914dd6 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -34,8 +34,23 @@ struct async_reader
IWMReaderCallback *callback;
void *context;
+
+ LARGE_INTEGER clock_frequency;
+ HANDLE stream_thread;
+ CRITICAL_SECTION stream_cs;
+ CONDITION_VARIABLE stream_cv;
+
+ bool running;
};
+static REFERENCE_TIME get_current_time(const struct async_reader *reader)
+{
+ LARGE_INTEGER time;
+
+ QueryPerformanceCounter(&time);
+ return (time.QuadPart * 1000) / reader->clock_frequency.QuadPart * 10000;
+}
+
static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
{
static const DWORD zero;
@@ -45,6 +60,92 @@ static void open_stream(struct async_reader *reader, IWMReaderCallback *callback
IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
}
+static DWORD WINAPI stream_thread(void *arg)
+{
+ struct async_reader *reader = arg;
+ WORD i, stream_count = reader->reader.stream_count;
+ IWMReaderCallback *callback = reader->callback;
+ REFERENCE_TIME start_time;
+ static const DWORD zero;
+ QWORD pts, duration;
+ INSSBuffer *sample;
+ DWORD flags;
+ HRESULT hr;
+
+ start_time = get_current_time(reader);
+
+ EnterCriticalSection(&reader->stream_cs);
+
+ while (reader->running)
+ {
+ bool all_eos = true;
+
+ for (i = 0; i < stream_count; ++i)
+ {
+ hr = wm_reader_get_stream_sample(&reader->reader.streams[i], &sample, &pts, &duration, &flags);
+ if (hr == S_OK)
+ {
+ for (;;)
+ {
+ REFERENCE_TIME current_time = get_current_time(reader);
+
+ if (pts <= current_time - start_time)
+ break;
+
+ SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs,
+ (pts - (current_time - start_time)) / 10000);
+
+ if (!reader->running)
+ {
+ INSSBuffer_Release(sample);
+ goto out;
+ }
+ }
+
+ IWMReaderCallback_OnSample(callback, i, pts, duration, flags, sample, reader->context);
+ INSSBuffer_Release(sample);
+ all_eos = false;
+ }
+ else if (hr != NS_E_NO_MORE_SAMPLES)
+ {
+ ERR("Failed to get sample, hr %#x.\n", hr);
+ return 0;
+ }
+ }
+
+ if (all_eos)
+ {
+ IWMReaderCallback_OnStatus(callback, WMT_END_OF_STREAMING, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ IWMReaderCallback_OnStatus(callback, WMT_EOF, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ TRACE("Reached end of stream; exiting.\n");
+ LeaveCriticalSection(&reader->stream_cs);
+ return 0;
+ }
+ }
+
+out:
+ LeaveCriticalSection(&reader->stream_cs);
+
+ TRACE("Reader is stopping; exiting.\n");
+ return 0;
+}
+
+static void stop_streaming(struct async_reader *reader)
+{
+ if (reader->stream_thread)
+ {
+ EnterCriticalSection(&reader->stream_cs);
+ reader->running = false;
+ LeaveCriticalSection(&reader->stream_cs);
+ WakeConditionVariable(&reader->stream_cv);
+ WaitForSingleObject(reader->stream_thread, INFINITE);
+ CloseHandle(reader->stream_thread);
+ reader->stream_thread = NULL;
+ }
+}
+
static struct async_reader *impl_from_IWMReader(IWMReader *iface)
{
return CONTAINING_RECORD(iface, struct async_reader, IWMReader_iface);
@@ -88,6 +189,8 @@ static HRESULT WINAPI WMReader_Close(IWMReader *iface)
EnterCriticalSection(&reader->reader.cs);
+ stop_streaming(reader);
+
hr = wm_reader_close(&reader->reader);
if (reader->callback)
{
@@ -151,18 +254,54 @@ static HRESULT WINAPI WMReader_GetOutputFormat(IWMReader *iface, DWORD output,
return wm_reader_get_output_format(&reader->reader, output, index, props);
}
-static HRESULT WINAPI WMReader_Start(IWMReader *iface, QWORD start, QWORD duration, float rate, void *context)
+static HRESULT WINAPI WMReader_Start(IWMReader *iface,
+ QWORD start, QWORD duration, float rate, void *context)
{
- struct async_reader *This = impl_from_IWMReader(iface);
- FIXME("(%p)->(%s %s %f %p)\n", This, wine_dbgstr_longlong(start), wine_dbgstr_longlong(duration), rate, context);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReader(iface);
+ static const DWORD zero;
+
+ TRACE("reader %p, start %s, duration %s, rate %.8e, context %p.\n",
+ reader, debugstr_time(start), debugstr_time(duration), rate, context);
+
+ if (rate != 1.0f)
+ FIXME("Ignoring rate %.8e.\n", rate);
+
+ EnterCriticalSection(&reader->reader.cs);
+
+ stop_streaming(reader);
+
+ IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
+ reader->context = context;
+
+ wm_reader_seek(&reader->reader, start, duration);
+
+ reader->running = true;
+
+ if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL)))
+ {
+ LeaveCriticalSection(&reader->reader.cs);
+ return E_OUTOFMEMORY;
+ }
+
+ LeaveCriticalSection(&reader->reader.cs);
+ WakeConditionVariable(&reader->stream_cv);
+
+ return S_OK;
}
static HRESULT WINAPI WMReader_Stop(IWMReader *iface)
{
- struct async_reader *This = impl_from_IWMReader(iface);
- FIXME("(%p)\n", This);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReader(iface);
+ static const DWORD zero;
+
+ TRACE("reader %p.\n", reader);
+
+ EnterCriticalSection(&reader->reader.cs);
+ stop_streaming(reader);
+ IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ LeaveCriticalSection(&reader->reader.cs);
+ return S_OK;
}
static HRESULT WINAPI WMReader_Pause(IWMReader *iface)
@@ -1302,6 +1441,15 @@ static void async_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
+ if (reader->stream_thread)
+ {
+ WaitForSingleObject(reader->stream_thread, INFINITE);
+ CloseHandle(reader->stream_thread);
+ }
+
+ reader->stream_cs.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection(&reader->stream_cs);
+
wm_reader_close(&reader->reader);
if (reader->callback)
@@ -1336,6 +1484,11 @@ HRESULT WINAPI winegstreamer_create_wm_async_reader(IWMReader **reader)
object->IWMReaderStreamClock_iface.lpVtbl = &WMReaderStreamClockVtbl;
object->IWMReaderTypeNegotiation_iface.lpVtbl = &WMReaderTypeNegotiationVtbl;
+ InitializeCriticalSection(&object->stream_cs);
+ object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": async_reader.stream_cs");
+
+ QueryPerformanceFrequency(&object->clock_frequency);
+
TRACE("Created async reader %p.\n", object);
*reader = (IWMReader *)&object->IWMReader_iface;
return S_OK;
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index c1972b29eb9..4cc285c2c73 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1125,6 +1125,7 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ callback->got_end_of_streaming = callback->got_eof = callback->got_sample = 0;
++callback->got_started;
break;
@@ -1138,7 +1139,7 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
case WMT_CLOSED:
ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
- todo_wine ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
++callback->got_closed;
break;
@@ -1281,17 +1282,27 @@ static void test_async_reader_streaming(void)
}
hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ /* By default the reader will time itself, and attempt to deliver samples
+ * according to their presentation time. Call DeliverTime with the file
+ * duration in order to request all samples as fast as possible. */
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ todo_wine ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
if (hr == S_OK)
{
- /* By default the reader will time itself, and attempt to deliver samples
- * according to their presentation time. Call DeliverTime with the file
- * duration in order to request all samples as fast as possible. */
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
- ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
- hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ret = WaitForSingleObject(callback.eof_event, 1000);
+ ok(!ret, "Wait timed out.\n");
+ ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
+
+ hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
ok(hr == S_OK, "Got hr %#x.\n", hr);
--
2.33.0
Nov. 4, 2021