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
April 2022
- 87 participants
- 3124 messages
Re: [PATCH 3/6] wineoss: Introduce a helper to retrieve the time.
by Andrew Eikum
Signed-off-by: Andrew Eikum <aeikum(a)codeweavers.com>
On Fri, Apr 29, 2022 at 08:29:55AM +0100, Huw Davies wrote:
> The motivation is that this will need to be called from a
> non-Win32 thread and so shouldn't use the Win32 API. An
> added benefit is that it will eliminate the 16ms jitter
> associated with GetTickCount().
>
> Signed-off-by: Huw Davies <huw(a)codeweavers.com>
> ---
> dlls/wineoss.drv/ossmidi.c | 20 +++++++++++++++++---
> 1 file changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c
> index 1695f1d2f7b..9c8ca8a8f39 100644
> --- a/dlls/wineoss.drv/ossmidi.c
> +++ b/dlls/wineoss.drv/ossmidi.c
> @@ -30,6 +30,8 @@
> #include <stdarg.h>
> #include <string.h>
> #include <stdio.h>
> +#include <stdint.h>
> +#include <time.h>
> #include <unistd.h>
> #include <errno.h>
> #include <sys/types.h>
> @@ -155,6 +157,18 @@ static void in_buffer_unlock(void)
> pthread_mutex_unlock(&in_buffer_mutex);
> }
>
> +static uint64_t get_time_msec(void)
> +{
> + struct timespec now = {0, 0};
> +
> +#ifdef CLOCK_MONOTONIC_RAW
> + if (!clock_gettime(CLOCK_MONOTONIC_RAW, &now))
> + return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
> +#endif
> + clock_gettime(CLOCK_MONOTONIC, &now);
> + return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
> +}
> +
> /*
> * notify buffer: The notification ring buffer is implemented so that
> * there is always at least one unused sentinel before the current
> @@ -1304,7 +1318,7 @@ NTSTATUS midi_handle_data(void *args)
> struct midi_handle_data_params *params = args;
> unsigned char *buffer = params->buffer;
> unsigned int len = params->len;
> - unsigned int time = NtGetTickCount(), i;
> + unsigned int time = get_time_msec(), i;
> struct midi_src *src;
> unsigned char value;
> WORD dev_id;
> @@ -1415,7 +1429,7 @@ static UINT midi_in_start(WORD dev_id)
> if (src->state == -1) return MIDIERR_NODEVICE;
>
> src->state = 1;
> - src->startTime = NtGetTickCount();
> + src->startTime = get_time_msec();
> return MMSYSERR_NOERROR;
> }
>
> @@ -1435,7 +1449,7 @@ static UINT midi_in_stop(WORD dev_id)
>
> static UINT midi_in_reset(WORD dev_id, struct notify_context *notify)
> {
> - UINT cur_time = NtGetTickCount();
> + UINT cur_time = get_time_msec();
> UINT err = MMSYSERR_NOERROR;
> struct midi_src *src;
> MIDIHDR *hdr;
> --
> 2.25.1
>
>
April 29, 2022
Re: [PATCH 2/6] wineoss: Move the midi in data handlers to the unixlib.
by Andrew Eikum
Signed-off-by: Andrew Eikum <aeikum(a)codeweavers.com>
On Fri, Apr 29, 2022 at 08:29:54AM +0100, Huw Davies wrote:
> The syscall itself is temporary.
>
> Signed-off-by: Huw Davies <huw(a)codeweavers.com>
> ---
> dlls/wineoss.drv/midi.c | 129 +------------------------
> dlls/wineoss.drv/oss.c | 2 +-
> dlls/wineoss.drv/ossmidi.c | 189 +++++++++++++++++++++++++++++++++++--
> dlls/wineoss.drv/unixlib.h | 10 +-
> 4 files changed, 196 insertions(+), 134 deletions(-)
>
> diff --git a/dlls/wineoss.drv/midi.c b/dlls/wineoss.drv/midi.c
> index b3f980ab3da..0afd9985c03 100644
> --- a/dlls/wineoss.drv/midi.c
> +++ b/dlls/wineoss.drv/midi.c
> @@ -126,16 +126,6 @@ static LRESULT OSS_MidiExit(void)
> return 0;
> }
>
> -static void in_buffer_lock(void)
> -{
> - OSS_CALL(midi_in_lock, ULongToPtr(1));
> -}
> -
> -static void in_buffer_unlock(void)
> -{
> - OSS_CALL(midi_in_lock, ULongToPtr(0));
> -}
> -
> static void notify_client(struct notify_context *notify)
> {
> TRACE("dev_id = %d msg = %d param1 = %04lX param2 = %04lX\n",
> @@ -210,123 +200,13 @@ static int midiCloseSeq(int fd)
> return 0;
> }
>
> -static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time)
> -{
> - MIDIHDR *hdr;
> - BOOL done = FALSE;
> -
> - src->state |= 2;
> - src->incLen = 0;
> -
> - in_buffer_lock();
> -
> - hdr = src->lpQueueHdr;
> - if (hdr)
> - {
> - BYTE *data = (BYTE *)hdr->lpData;
> -
> - data[hdr->dwBytesRecorded++] = value;
> - if (hdr->dwBytesRecorded == hdr->dwBufferLength)
> - done = TRUE;
> - }
> -
> - if (value == 0xf7) /* end */
> - {
> - src->state &= ~2;
> - done = TRUE;
> - }
> -
> - if (done && hdr)
> - {
> - src->lpQueueHdr = hdr->lpNext;
> - hdr->dwFlags &= ~MHDR_INQUEUE;
> - hdr->dwFlags |= MHDR_DONE;
> - MIDI_NotifyClient(src - MidiInDev, MIM_LONGDATA, (UINT_PTR)hdr, time);
> - }
> -
> - in_buffer_unlock();
> -}
> -
> -static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time)
> -{
> - UINT to_send = 0;
> -
> -#define IS_CMD(_x) (((_x) & 0x80) == 0x80)
> -#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
> -
> - if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */
> - {
> - if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev))
> - {
> - src->incoming[0] = src->incPrev;
> - src->incLen = 1;
> - }
> - else
> - {
> - /* FIXME: should generate MIM_ERROR notification */
> - return;
> - }
> - }
> - src->incoming[(int)src->incLen++] = value;
> - if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0]))
> - /* store new cmd, just in case */
> - src->incPrev = src->incoming[0];
> -
> -#undef IS_CMD
> -#undef IS_SYS_CMD
> -
> - switch (src->incoming[0] & 0xF0)
> - {
> - case MIDI_NOTEOFF:
> - case MIDI_NOTEON:
> - case MIDI_KEY_PRESSURE:
> - case MIDI_CTL_CHANGE:
> - case MIDI_PITCH_BEND:
> - if (src->incLen == 3)
> - to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) |
> - src->incoming[0];
> - break;
> - case MIDI_PGM_CHANGE:
> - case MIDI_CHN_PRESSURE:
> - if (src->incLen == 2)
> - to_send = (src->incoming[1] << 8) | src->incoming[0];
> - break;
> - case MIDI_SYSTEM_PREFIX:
> - if (src->incLen == 1)
> - to_send = src->incoming[0];
> - break;
> - }
> -
> - if (to_send)
> - {
> - src->incLen = 0;
> - MIDI_NotifyClient(src - MidiInDev, MIM_DATA, to_send, time);
> - }
> -}
> -
> static void handle_midi_data(unsigned char *buffer, unsigned int len)
> {
> - unsigned int time = GetTickCount(), i;
> - struct midi_src *src;
> - unsigned char value;
> - WORD dev_id;
> + struct midi_handle_data_params params;
>
> - for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4)
> - {
> - if (buffer[i] != SEQ_MIDIPUTC) continue;
> -
> - dev_id = buffer[i + 2];
> - value = buffer[i + 1];
> -
> - if (dev_id >= MIDM_NumDevs) continue;
> - src = MidiInDev + dev_id;
> - if (src->state <= 0) continue;
> -
> - if (value == 0xf0 || src->state & 2) /* system exclusive */
> - handle_sysex_data(src, value, time - src->startTime);
> - else
> - handle_regular_data(src, value, time - src->startTime);
> - }
> + params.buffer = buffer;
> + params.len = len;
> + OSS_CALL(midi_handle_data, ¶ms);
> }
>
> static DWORD WINAPI midRecThread(void *arg)
> @@ -565,6 +445,7 @@ static DWORD WINAPI notify_thread(void *p)
> {
> OSS_CALL(midi_notify_wait, ¶ms);
> if (quit) break;
> + if (notify.send_notify) notify_client(¬ify);
> }
> return 0;
> }
> diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c
> index 8fda9270a4e..c5b422a60c9 100644
> --- a/dlls/wineoss.drv/oss.c
> +++ b/dlls/wineoss.drv/oss.c
> @@ -1412,5 +1412,5 @@ unixlib_entry_t __wine_unix_call_funcs[] =
> midi_notify_wait,
>
> midi_seq_open,
> - midi_in_lock,
> + midi_handle_data,
> };
> diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c
> index 0790eaaec1a..1695f1d2f7b 100644
> --- a/dlls/wineoss.drv/ossmidi.c
> +++ b/dlls/wineoss.drv/ossmidi.c
> @@ -68,7 +68,11 @@ static struct midi_src srcs[MAX_MIDIINDRV];
>
> static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
> static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER;
> +static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER;
> static BOOL notify_quit;
> +#define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */
> +static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE];
> +static struct notify_context *notify_read = notify_buffer, *notify_write = notify_buffer;
>
> typedef struct sVoice
> {
> @@ -151,19 +155,59 @@ static void in_buffer_unlock(void)
> pthread_mutex_unlock(&in_buffer_mutex);
> }
>
> -NTSTATUS midi_in_lock(void *args)
> +/*
> + * notify buffer: The notification ring buffer is implemented so that
> + * there is always at least one unused sentinel before the current
> + * read position in order to allow detection of the full vs empty
> + * state.
> + */
> +static struct notify_context *notify_buffer_next(struct notify_context *notify)
> {
> - if (args) in_buffer_lock();
> - else in_buffer_unlock();
> + if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer))
> + notify = notify_buffer;
>
> - return STATUS_SUCCESS;
> + return notify;
> +}
> +
> +static BOOL notify_buffer_empty(void)
> +{
> + return notify_read == notify_write;
> +}
> +
> +static BOOL notify_buffer_full(void)
> +{
> + return notify_buffer_next(notify_write) == notify_read;
> +}
> +
> +static BOOL notify_buffer_add(struct notify_context *notify)
> +{
> + if (notify_buffer_full()) return FALSE;
> +
> + *notify_write = *notify;
> + notify_write = notify_buffer_next(notify_write);
> + return TRUE;
> +}
> +
> +static BOOL notify_buffer_remove(struct notify_context *notify)
> +{
> + if (notify_buffer_empty()) return FALSE;
> +
> + *notify = *notify_read;
> + notify_read = notify_buffer_next(notify_read);
> + return TRUE;
> }
>
> static void notify_post(struct notify_context *notify)
> {
> pthread_mutex_lock(¬ify_mutex);
>
> - if (notify) FIXME("Not yet handled\n");
> + if (notify)
> + {
> + while (notify_buffer_full())
> + pthread_cond_wait(¬ify_write_cond, ¬ify_mutex);
> +
> + notify_buffer_add(notify);
> + }
> else notify_quit = TRUE;
> pthread_cond_signal(¬ify_read_cond);
>
> @@ -1157,6 +1201,133 @@ static UINT midi_out_reset(WORD dev_id)
> return MMSYSERR_NOERROR;
> }
>
> +static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time)
> +{
> + struct notify_context notify;
> + MIDIHDR *hdr;
> + BOOL done = FALSE;
> +
> + src->state |= 2;
> + src->incLen = 0;
> +
> + in_buffer_lock();
> +
> + hdr = src->lpQueueHdr;
> + if (hdr)
> + {
> + BYTE *data = (BYTE *)hdr->lpData;
> +
> + data[hdr->dwBytesRecorded++] = value;
> + if (hdr->dwBytesRecorded == hdr->dwBufferLength)
> + done = TRUE;
> + }
> +
> + if (value == 0xf7) /* end */
> + {
> + src->state &= ~2;
> + done = TRUE;
> + }
> +
> + if (done && hdr)
> + {
> + src->lpQueueHdr = hdr->lpNext;
> + hdr->dwFlags &= ~MHDR_INQUEUE;
> + hdr->dwFlags |= MHDR_DONE;
> + set_in_notify(¬ify, src, src - srcs, MIM_LONGDATA, (UINT_PTR)hdr, time);
> + notify_post(¬ify);
> + }
> +
> + in_buffer_unlock();
> +}
> +
> +static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time)
> +{
> + struct notify_context notify;
> + UINT to_send = 0;
> +
> +#define IS_CMD(_x) (((_x) & 0x80) == 0x80)
> +#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
> +
> + if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */
> + {
> + if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev))
> + {
> + src->incoming[0] = src->incPrev;
> + src->incLen = 1;
> + }
> + else
> + {
> + /* FIXME: should generate MIM_ERROR notification */
> + return;
> + }
> + }
> + src->incoming[(int)src->incLen++] = value;
> + if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0]))
> + /* store new cmd, just in case */
> + src->incPrev = src->incoming[0];
> +
> +#undef IS_CMD
> +#undef IS_SYS_CMD
> +
> + switch (src->incoming[0] & 0xF0)
> + {
> + case MIDI_NOTEOFF:
> + case MIDI_NOTEON:
> + case MIDI_KEY_PRESSURE:
> + case MIDI_CTL_CHANGE:
> + case MIDI_PITCH_BEND:
> + if (src->incLen == 3)
> + to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) |
> + src->incoming[0];
> + break;
> + case MIDI_PGM_CHANGE:
> + case MIDI_CHN_PRESSURE:
> + if (src->incLen == 2)
> + to_send = (src->incoming[1] << 8) | src->incoming[0];
> + break;
> + case MIDI_SYSTEM_PREFIX:
> + if (src->incLen == 1)
> + to_send = src->incoming[0];
> + break;
> + }
> +
> + if (to_send)
> + {
> + src->incLen = 0;
> + set_in_notify(¬ify, src, src - srcs, MIM_DATA, to_send, time);
> + notify_post(¬ify);
> + }
> +}
> +
> +NTSTATUS midi_handle_data(void *args)
> +{
> + struct midi_handle_data_params *params = args;
> + unsigned char *buffer = params->buffer;
> + unsigned int len = params->len;
> + unsigned int time = NtGetTickCount(), i;
> + struct midi_src *src;
> + unsigned char value;
> + WORD dev_id;
> +
> + for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4)
> + {
> + if (buffer[i] != SEQ_MIDIPUTC) continue;
> +
> + dev_id = buffer[i + 2];
> + value = buffer[i + 1];
> +
> + if (dev_id >= num_srcs) continue;
> + src = srcs + dev_id;
> + if (src->state <= 0) continue;
> +
> + if (value == 0xf0 || src->state & 2) /* system exclusive */
> + handle_sysex_data(src, value, time - src->startTime);
> + else
> + handle_regular_data(src, value, time - src->startTime);
> + }
> + return STATUS_SUCCESS;
> +}
> +
> static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
> {
> struct midi_src *src;
> @@ -1397,11 +1568,15 @@ NTSTATUS midi_notify_wait(void *args)
>
> pthread_mutex_lock(¬ify_mutex);
>
> - while (!notify_quit)
> + while (!notify_quit && notify_buffer_empty())
> pthread_cond_wait(¬ify_read_cond, ¬ify_mutex);
>
> *params->quit = notify_quit;
> -
> + if (!notify_quit)
> + {
> + notify_buffer_remove(params->notify);
> + pthread_cond_signal(¬ify_write_cond);
> + }
> pthread_mutex_unlock(¬ify_mutex);
>
> return STATUS_SUCCESS;
> diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h
> index ddeba49556c..90d0c47421c 100644
> --- a/dlls/wineoss.drv/unixlib.h
> +++ b/dlls/wineoss.drv/unixlib.h
> @@ -279,6 +279,12 @@ struct midi_seq_open_params
> int fd;
> };
>
> +struct midi_handle_data_params
> +{
> + unsigned char *buffer;
> + unsigned int len;
> +};
> +
> enum oss_funcs
> {
> oss_test_connect,
> @@ -311,7 +317,7 @@ enum oss_funcs
> oss_midi_notify_wait,
>
> oss_midi_seq_open, /* temporary */
> - oss_midi_in_lock,
> + oss_midi_handle_data,
> };
>
> NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
> @@ -320,7 +326,7 @@ NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
> -NTSTATUS midi_in_lock(void *args) DECLSPEC_HIDDEN;
> +NTSTATUS midi_handle_data(void *args) DECLSPEC_HIDDEN;
>
> extern unixlib_handle_t oss_handle;
>
> --
> 2.25.1
>
>
April 29, 2022
Re: [PATCH 1/6] wineoss: Introduce a notification thread.
by Andrew Eikum
Signed-off-by: Andrew Eikum <aeikum(a)codeweavers.com>
On Fri, Apr 29, 2022 at 08:29:53AM +0100, Huw Davies wrote:
> Currently the thread just blocks until told to quit by midi_release.
> Eventually this thread will dispatch the MIM_DATA and MIM_LONGDATA
> notifications.
>
> Signed-off-by: Huw Davies <huw(a)codeweavers.com>
> ---
> dlls/wineoss.drv/midi.c | 21 ++++++++++++++++++++
> dlls/wineoss.drv/oss.c | 2 ++
> dlls/wineoss.drv/ossmidi.c | 39 ++++++++++++++++++++++++++++++++++++++
> dlls/wineoss.drv/unixlib.h | 10 ++++++++++
> 4 files changed, 72 insertions(+)
>
> diff --git a/dlls/wineoss.drv/midi.c b/dlls/wineoss.drv/midi.c
> index e36a737624a..b3f980ab3da 100644
> --- a/dlls/wineoss.drv/midi.c
> +++ b/dlls/wineoss.drv/midi.c
> @@ -552,6 +552,23 @@ DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
> return err;
> }
>
> +static DWORD WINAPI notify_thread(void *p)
> +{
> + struct midi_notify_wait_params params;
> + struct notify_context notify;
> + BOOL quit;
> +
> + params.notify = ¬ify;
> + params.quit = &quit;
> +
> + while (1)
> + {
> + OSS_CALL(midi_notify_wait, ¶ms);
> + if (quit) break;
> + }
> + return 0;
> +}
> +
> /**************************************************************************
> * DriverProc (WINEOSS.1)
> */
> @@ -563,7 +580,11 @@ LRESULT CALLBACK OSS_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
>
> switch(wMsg) {
> case DRV_LOAD:
> + CloseHandle(CreateThread(NULL, 0, notify_thread, NULL, 0, NULL));
> + return 1;
> case DRV_FREE:
> + OSS_CALL(midi_release, NULL);
> + return 1;
> case DRV_OPEN:
> case DRV_CLOSE:
> case DRV_ENABLE:
> diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c
> index a9081f2cac9..8fda9270a4e 100644
> --- a/dlls/wineoss.drv/oss.c
> +++ b/dlls/wineoss.drv/oss.c
> @@ -1406,8 +1406,10 @@ unixlib_entry_t __wine_unix_call_funcs[] =
> set_event_handle,
> is_started,
> midi_init,
> + midi_release,
> midi_out_message,
> midi_in_message,
> + midi_notify_wait,
>
> midi_seq_open,
> midi_in_lock,
> diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c
> index 86d766eceaf..0790eaaec1a 100644
> --- a/dlls/wineoss.drv/ossmidi.c
> +++ b/dlls/wineoss.drv/ossmidi.c
> @@ -66,6 +66,10 @@ static unsigned int num_dests, num_srcs, num_synths, seq_refs;
> static struct midi_dest dests[MAX_MIDIOUTDRV];
> static struct midi_src srcs[MAX_MIDIINDRV];
>
> +static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
> +static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER;
> +static BOOL notify_quit;
> +
> typedef struct sVoice
> {
> int note; /* 0 means not used */
> @@ -155,6 +159,17 @@ NTSTATUS midi_in_lock(void *args)
> return STATUS_SUCCESS;
> }
>
> +static void notify_post(struct notify_context *notify)
> +{
> + pthread_mutex_lock(¬ify_mutex);
> +
> + if (notify) FIXME("Not yet handled\n");
> + else notify_quit = TRUE;
> + pthread_cond_signal(¬ify_read_cond);
> +
> + pthread_mutex_unlock(¬ify_mutex);
> +}
> +
> static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg,
> UINT_PTR param_1, UINT_PTR param_2)
> {
> @@ -432,6 +447,14 @@ wrapup:
> return STATUS_SUCCESS;
> }
>
> +NTSTATUS midi_release(void *args)
> +{
> + /* stop the notify_wait thread */
> + notify_post(NULL);
> +
> + return STATUS_SUCCESS;
> +}
> +
> /* FIXME: this is a bad idea, it's even not static... */
> SEQ_DEFINEBUF(1024);
>
> @@ -1367,3 +1390,19 @@ NTSTATUS midi_in_message(void *args)
>
> return STATUS_SUCCESS;
> }
> +
> +NTSTATUS midi_notify_wait(void *args)
> +{
> + struct midi_notify_wait_params *params = args;
> +
> + pthread_mutex_lock(¬ify_mutex);
> +
> + while (!notify_quit)
> + pthread_cond_wait(¬ify_read_cond, ¬ify_mutex);
> +
> + *params->quit = notify_quit;
> +
> + pthread_mutex_unlock(¬ify_mutex);
> +
> + return STATUS_SUCCESS;
> +}
> diff --git a/dlls/wineoss.drv/unixlib.h b/dlls/wineoss.drv/unixlib.h
> index 867e1ff656e..ddeba49556c 100644
> --- a/dlls/wineoss.drv/unixlib.h
> +++ b/dlls/wineoss.drv/unixlib.h
> @@ -267,6 +267,12 @@ struct midi_in_message_params
> struct notify_context *notify;
> };
>
> +struct midi_notify_wait_params
> +{
> + BOOL *quit;
> + struct notify_context *notify;
> +};
> +
> struct midi_seq_open_params
> {
> int close;
> @@ -299,16 +305,20 @@ enum oss_funcs
> oss_set_event_handle,
> oss_is_started,
> oss_midi_init,
> + oss_midi_release,
> oss_midi_out_message,
> oss_midi_in_message,
> + oss_midi_notify_wait,
>
> oss_midi_seq_open, /* temporary */
> oss_midi_in_lock,
> };
>
> NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
> +NTSTATUS midi_release(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN;
> +NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
> NTSTATUS midi_in_lock(void *args) DECLSPEC_HIDDEN;
>
> --
> 2.25.1
>
>
April 29, 2022
[PATCH 2/2] uiautomationcore/tests: Add tests for UiaProviderFromIAccessible.
by Connor McAdams
Signed-off-by: Connor McAdams <cmcadams(a)codeweavers.com>
---
dlls/uiautomationcore/tests/Makefile.in | 2 +-
dlls/uiautomationcore/tests/uiautomation.c | 424 +++++++++++++++++++++
2 files changed, 425 insertions(+), 1 deletion(-)
diff --git a/dlls/uiautomationcore/tests/Makefile.in b/dlls/uiautomationcore/tests/Makefile.in
index fbd53507fbe..53ed6f6e380 100644
--- a/dlls/uiautomationcore/tests/Makefile.in
+++ b/dlls/uiautomationcore/tests/Makefile.in
@@ -1,5 +1,5 @@
TESTDLL = uiautomationcore.dll
-IMPORTS = uiautomationcore user32 ole32 oleaut32
+IMPORTS = uiautomationcore user32 ole32 oleaut32 oleacc
C_SRCS = \
uiautomation.c
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index 501875a20e7..246f8aba7c1 100644
--- a/dlls/uiautomationcore/tests/uiautomation.c
+++ b/dlls/uiautomationcore/tests/uiautomation.c
@@ -23,9 +23,322 @@
#include "windows.h"
#include "initguid.h"
#include "uiautomation.h"
+#include "ocidl.h"
#include "wine/test.h"
+static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD, IRawElementProviderSimple **);
+
+#define DEFINE_EXPECT(func) \
+ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+ do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
+
+#define CHECK_EXPECT2(func) \
+ do { \
+ ok(expect_ ##func, "unexpected call " #func "\n"); \
+ called_ ## func = TRUE; \
+ }while(0)
+
+#define CHECK_EXPECT(func) \
+ do { \
+ CHECK_EXPECT2(func); \
+ expect_ ## func = FALSE; \
+ }while(0)
+
+#define CHECK_CALLED(func) \
+ do { \
+ ok(called_ ## func, "expected " #func "\n"); \
+ expect_ ## func = called_ ## func = FALSE; \
+ }while(0)
+
+DEFINE_EXPECT(Accessible_accNavigate);
+
+static LONG Accessible_ref = 1;
+static IAccessible Accessible;
+static IOleWindow OleWindow;
+static HWND Accessible_hwnd = NULL;
+static HWND OleWindow_hwnd = NULL;
+
+static BOOL check_variant_i4(VARIANT *v, int val)
+{
+ if (V_VT(v) == VT_I4 && V_I4(v) == val)
+ return TRUE;
+
+ return FALSE;
+}
+
+static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid, void **obj)
+{
+ *obj = NULL;
+ if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) ||
+ IsEqualIID(riid, &IID_IAccessible))
+ *obj = iface;
+ else if (IsEqualIID(riid, &IID_IOleWindow))
+ *obj = &OleWindow;
+ else
+ return E_NOINTERFACE;
+
+ IAccessible_AddRef(iface);
+ return S_OK;
+}
+
+static ULONG WINAPI Accessible_AddRef(IAccessible *iface)
+{
+ return InterlockedIncrement(&Accessible_ref);
+}
+
+static ULONG WINAPI Accessible_Release(IAccessible *iface)
+{
+ return InterlockedDecrement(&Accessible_ref);
+}
+
+static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_GetTypeInfo(IAccessible *iface, UINT iTInfo,
+ LCID lcid, ITypeInfo **out_tinfo)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_GetIDsOfNames(IAccessible *iface, REFIID riid,
+ LPOLESTR *rg_names, UINT name_count, LCID lcid, DISPID *rg_disp_id)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID disp_id_member,
+ REFIID riid, LCID lcid, WORD flags, DISPPARAMS *disp_params,
+ VARIANT *var_result, EXCEPINFO *excep_info, UINT *arg_err)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **out_parent)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *out_count)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT child_id,
+ IDispatch **out_child)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT child_id,
+ BSTR *out_name)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accValue(IAccessible *iface, VARIANT child_id,
+ BSTR *out_value)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT child_id,
+ BSTR *out_description)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT child_id,
+ VARIANT *out_role)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT child_id,
+ VARIANT *out_state)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accHelp(IAccessible *iface, VARIANT child_id,
+ BSTR *out_help)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accHelpTopic(IAccessible *iface,
+ BSTR *out_help_file, VARIANT child_id, LONG *out_topic_id)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accKeyboardShortcut(IAccessible *iface, VARIANT child_id,
+ BSTR *out_kbd_shortcut)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accFocus(IAccessible *iface, VARIANT *pchild_id)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accSelection(IAccessible *iface, VARIANT *out_selection)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_get_accDefaultAction(IAccessible *iface, VARIANT child_id,
+ BSTR *out_default_action)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, LONG select_flags,
+ VARIANT child_id)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *out_left,
+ LONG *out_top, LONG *out_width, LONG *out_height, VARIANT child_id)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG nav_direction,
+ VARIANT child_id_start, VARIANT *out_var)
+{
+ CHECK_EXPECT(Accessible_accNavigate);
+ VariantInit(out_var);
+
+ /*
+ * This is an undocumented way for UI Automation to get an HWND for
+ * IAccessible's contained in a Direct Annotation wrapper object.
+ */
+ if ((nav_direction == 10) && check_variant_i4(&child_id_start, CHILDID_SELF))
+ {
+ V_VT(out_var) = VT_I4;
+ V_I4(out_var) = HandleToUlong(Accessible_hwnd);
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT WINAPI Accessible_accHitTest(IAccessible *iface, LONG left, LONG top,
+ VARIANT *out_child_id)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_accDoDefaultAction(IAccessible *iface, VARIANT child_id)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_put_accName(IAccessible *iface, VARIANT child_id,
+ BSTR name)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Accessible_put_accValue(IAccessible *iface, VARIANT child_id,
+ BSTR value)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static IAccessibleVtbl AccessibleVtbl = {
+ Accessible_QueryInterface,
+ Accessible_AddRef,
+ Accessible_Release,
+ Accessible_GetTypeInfoCount,
+ Accessible_GetTypeInfo,
+ Accessible_GetIDsOfNames,
+ Accessible_Invoke,
+ Accessible_get_accParent,
+ Accessible_get_accChildCount,
+ Accessible_get_accChild,
+ Accessible_get_accName,
+ Accessible_get_accValue,
+ Accessible_get_accDescription,
+ Accessible_get_accRole,
+ Accessible_get_accState,
+ Accessible_get_accHelp,
+ Accessible_get_accHelpTopic,
+ Accessible_get_accKeyboardShortcut,
+ Accessible_get_accFocus,
+ Accessible_get_accSelection,
+ Accessible_get_accDefaultAction,
+ Accessible_accSelect,
+ Accessible_accLocation,
+ Accessible_accNavigate,
+ Accessible_accHitTest,
+ Accessible_accDoDefaultAction,
+ Accessible_put_accName,
+ Accessible_put_accValue
+};
+
+static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **obj)
+{
+ return IAccessible_QueryInterface(&Accessible, riid, obj);
+}
+
+static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
+{
+ return IAccessible_AddRef(&Accessible);
+}
+
+static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
+{
+ return IAccessible_Release(&Accessible);
+}
+
+static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
+{
+ *hwnd = OleWindow_hwnd;
+ return S_OK;
+}
+
+static HRESULT WINAPI OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL f_enter_mode)
+{
+ return E_NOTIMPL;
+}
+
+static const IOleWindowVtbl OleWindowVtbl = {
+ OleWindow_QueryInterface,
+ OleWindow_AddRef,
+ OleWindow_Release,
+ OleWindow_GetWindow,
+ OleWindow_ContextSensitiveHelp
+};
+
+static IAccessible Accessible = {&AccessibleVtbl};
+static IOleWindow OleWindow = {&OleWindowVtbl};
+
static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProcA(hwnd, message, wParam, lParam);
@@ -264,8 +577,119 @@ static void test_uia_reserved_value_ifaces(void)
CoUninitialize();
}
+static void test_UiaProviderFromIAccessible(void)
+{
+ IRawElementProviderSimple *elprov;
+ enum ProviderOptions prov_opt;
+ IAccessible *acc;
+ WNDCLASSA cls;
+ HRESULT hr;
+ HWND hwnd;
+ VARIANT v;
+
+
+ cls.style = 0;
+ cls.lpfnWndProc = test_wnd_proc;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = GetModuleHandleA(NULL);
+ cls.hIcon = 0;
+ cls.hCursor = NULL;
+ cls.hbrBackground = NULL;
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = "UiaProviderFromIAccessible class";
+
+ RegisterClassA(&cls);
+
+ hwnd = CreateWindowA("UiaProviderFromIAccessible class", "Test window", WS_OVERLAPPEDWINDOW,
+ 0, 0, 100, 100, NULL, NULL, NULL, NULL);
+
+ hr = pUiaProviderFromIAccessible(NULL, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+ hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
+
+ /*
+ * UiaProviderFromIAccessible will not wrap an MSAA proxy, this is
+ * detected by checking for the 'IIS_IsOleaccProxy' service from the
+ * IServiceProvider interface.
+ */
+ hr = CreateStdAccessibleObject(hwnd, OBJID_CLIENT, &IID_IAccessible, (void**)&acc);
+ ok(hr == S_OK, "got %#lx\n", hr);
+ ok(!!acc, "acc == NULL\n");
+
+ hr = pUiaProviderFromIAccessible(acc, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+ IAccessible_Release(acc);
+
+ /* Don't return an HWND from accNavigate or OleWindow. */
+ SET_EXPECT(Accessible_accNavigate);
+ Accessible_hwnd = NULL;
+ OleWindow_hwnd = NULL;
+ hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+ CHECK_CALLED(Accessible_accNavigate);
+
+ /* Return an HWND from accNavigate, not OleWindow. */
+ SET_EXPECT(Accessible_accNavigate);
+ Accessible_hwnd = hwnd;
+ OleWindow_hwnd = NULL;
+ hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ CHECK_CALLED(Accessible_accNavigate);
+ ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
+ IRawElementProviderSimple_Release(elprov);
+ ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+
+ /* Return an HWND from OleWindow, not accNavigate. */
+ Accessible_hwnd = NULL;
+ OleWindow_hwnd = hwnd;
+ hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
+
+ hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opt);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok((prov_opt == (ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading)) ||
+ broken(prov_opt == ProviderOptions_ClientSideProvider), /* Windows < 10 1507 */
+ "Unexpected provider options %#x\n", prov_opt);
+
+ hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ProviderDescriptionPropertyId, &v);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v));
+ VariantClear(&v);
+
+ IRawElementProviderSimple_Release(elprov);
+ ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+
+ /* ChildID other than CHILDID_SELF. */
+ hr = pUiaProviderFromIAccessible(&Accessible, 1, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
+ IRawElementProviderSimple_Release(elprov);
+ ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+
+ DestroyWindow(hwnd);
+ UnregisterClassA("pUiaProviderFromIAccessible class", NULL);
+ Accessible_hwnd = NULL;
+ OleWindow_hwnd = NULL;
+}
+
START_TEST(uiautomation)
{
+ HMODULE uia_dll = LoadLibraryA("uiautomationcore.dll");
+
test_UiaHostProviderFromHwnd();
test_uia_reserved_value_ifaces();
+ if (uia_dll)
+ {
+ pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible");
+ if (pUiaProviderFromIAccessible)
+ test_UiaProviderFromIAccessible();
+ else
+ win_skip("UiaProviderFromIAccessible not exported by uiautomationcore.dll\n");
+
+ FreeLibrary(uia_dll);
+ }
}
--
2.25.1
April 29, 2022
[PATCH 1/2] uiautomationcore: Implement UiaProviderFromIAccessible.
by Connor McAdams
Signed-off-by: Connor McAdams <cmcadams(a)codeweavers.com>
---
dlls/uiautomationcore/Makefile.in | 3 +-
dlls/uiautomationcore/uia_main.c | 1 +
dlls/uiautomationcore/uia_provider.c | 226 ++++++++++++++++++++
dlls/uiautomationcore/uiautomationcore.spec | 2 +-
include/uiautomationcoreapi.h | 4 +
5 files changed, 234 insertions(+), 2 deletions(-)
create mode 100644 dlls/uiautomationcore/uia_provider.c
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in
index f0973fdec4c..bda3614f051 100644
--- a/dlls/uiautomationcore/Makefile.in
+++ b/dlls/uiautomationcore/Makefile.in
@@ -5,4 +5,5 @@ IMPORTS = uuid ole32 oleaut32 user32
EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \
- uia_main.c
+ uia_main.c \
+ uia_provider.c
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c
index a303e71cf76..9f257684333 100644
--- a/dlls/uiautomationcore/uia_main.c
+++ b/dlls/uiautomationcore/uia_main.c
@@ -20,6 +20,7 @@
#include "initguid.h"
#include "uiautomation.h"
+#include "ocidl.h"
#include "wine/debug.h"
#include "wine/heap.h"
diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c
new file mode 100644
index 00000000000..790593dbcab
--- /dev/null
+++ b/dlls/uiautomationcore/uia_provider.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2022 Connor McAdams 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 "uiautomation.h"
+#include "ocidl.h"
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+
+static void variant_init_i4(VARIANT *v, int val)
+{
+ V_VT(v) = VT_I4;
+ V_I4(v) = val;
+}
+
+/*
+ * UiaProviderFromIAccessible IRawElementProviderSimple interface.
+ */
+struct msaa_provider {
+ IRawElementProviderSimple IRawElementProviderSimple_iface;
+ LONG refcount;
+
+ IAccessible *acc;
+ VARIANT cid;
+ HWND hwnd;
+};
+
+static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
+{
+ return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface);
+}
+
+HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv)
+{
+ *ppv = NULL;
+ if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown))
+ *ppv = iface;
+ else
+ return E_NOINTERFACE;
+
+ IRawElementProviderSimple_AddRef(iface);
+ return S_OK;
+}
+
+ULONG WINAPI msaa_provider_AddRef(IRawElementProviderSimple *iface)
+{
+ struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
+ ULONG refcount = InterlockedIncrement(&msaa_prov->refcount);
+
+ TRACE("%p, refcount %ld\n", iface, refcount);
+
+ return refcount;
+}
+
+ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface)
+{
+ struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
+ ULONG refcount = InterlockedDecrement(&msaa_prov->refcount);
+
+ TRACE("%p, refcount %ld\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IAccessible_Release(msaa_prov->acc);
+ heap_free(msaa_prov);
+ }
+
+ return refcount;
+}
+
+HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface,
+ enum ProviderOptions *ret_val)
+{
+ TRACE("%p, %p\n", iface, ret_val);
+ *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading;
+ return S_OK;
+}
+
+HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface,
+ PATTERNID pattern_id, IUnknown **ret_val)
+{
+ FIXME("%p, %d, %p: stub!\n", iface, pattern_id, ret_val);
+ *ret_val = NULL;
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
+ PROPERTYID prop_id, VARIANT *ret_val)
+{
+ TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
+
+ VariantInit(ret_val);
+ switch (prop_id)
+ {
+ case UIA_ProviderDescriptionPropertyId:
+ V_VT(ret_val) = VT_BSTR;
+ V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy");
+ break;
+
+ default:
+ FIXME("Unimplemented propertyId %d\n", prop_id);
+ break;
+ }
+
+ return S_OK;
+}
+
+HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
+ IRawElementProviderSimple **ret_val)
+{
+ FIXME("%p, %p: stub!\n", iface, ret_val);
+ *ret_val = NULL;
+ return E_NOTIMPL;
+}
+
+static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
+ msaa_provider_QueryInterface,
+ msaa_provider_AddRef,
+ msaa_provider_Release,
+ msaa_provider_get_ProviderOptions,
+ msaa_provider_GetPatternProvider,
+ msaa_provider_GetPropertyValue,
+ msaa_provider_get_HostRawElementProvider,
+};
+
+/***********************************************************************
+ * UiaProviderFromIAccessible (uiautomationcore.@)
+ */
+HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
+ IRawElementProviderSimple **elprov)
+{
+ struct msaa_provider *msaa_prov;
+ IServiceProvider *serv_prov;
+ HWND hwnd = NULL;
+ IOleWindow *win;
+ HRESULT hr;
+
+ TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov);
+
+ if (elprov)
+ *elprov = NULL;
+
+ if (!elprov)
+ return E_POINTER;
+ if (!acc)
+ return E_INVALIDARG;
+
+ if (flags != UIA_PFIA_DEFAULT)
+ {
+ FIXME("unsupported flags %#lx\n", flags);
+ return E_NOTIMPL;
+ }
+
+ hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
+ if (SUCCEEDED(hr))
+ {
+ IUnknown *unk;
+
+ hr = IServiceProvider_QueryService(serv_prov, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk);
+ if (SUCCEEDED(hr))
+ {
+ WARN("Cannot wrap an oleacc proxy IAccessible!\n");
+ IUnknown_Release(unk);
+ IServiceProvider_Release(serv_prov);
+ return E_INVALIDARG;
+ }
+
+ IServiceProvider_Release(serv_prov);
+ }
+
+ hr = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void **)&win);
+ if (SUCCEEDED(hr))
+ {
+ hr = IOleWindow_GetWindow(win, &hwnd);
+ if (FAILED(hr))
+ hwnd = NULL;
+ IOleWindow_Release(win);
+ }
+
+ if (!IsWindow(hwnd))
+ {
+ VARIANT v, cid;
+
+ VariantInit(&v);
+ variant_init_i4(&cid, CHILDID_SELF);
+ hr = IAccessible_accNavigate(acc, 10, cid, &v);
+ if (SUCCEEDED(hr) && V_VT(&v) == VT_I4)
+ hwnd = ULongToHandle(V_I4(&v));
+
+ if (!IsWindow(hwnd))
+ return E_FAIL;
+ }
+
+ msaa_prov = heap_alloc(sizeof(*msaa_prov));
+ if (!msaa_prov)
+ return E_OUTOFMEMORY;
+
+ msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
+ msaa_prov->refcount = 1;
+ msaa_prov->hwnd = hwnd;
+ variant_init_i4(&msaa_prov->cid, child_id);
+ msaa_prov->acc = acc;
+ IAccessible_AddRef(acc);
+ *elprov = &msaa_prov->IRawElementProviderSimple_iface;
+
+ return S_OK;
+}
diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec
index 82071bd2317..70d78d52085 100644
--- a/dlls/uiautomationcore/uiautomationcore.spec
+++ b/dlls/uiautomationcore/uiautomationcore.spec
@@ -83,7 +83,7 @@
@ stub UiaNodeRelease
@ stub UiaPatternRelease
#@ stub UiaProviderForNonClient
-#@ stub UiaProviderFromIAccessible
+@ stdcall UiaProviderFromIAccessible(ptr long long ptr)
@ stub UiaRaiseAsyncContentLoadedEvent
@ stdcall UiaRaiseAutomationEvent(ptr long)
@ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128)
diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h
index 563d5c602bd..22b3888dc6e 100644
--- a/include/uiautomationcoreapi.h
+++ b/include/uiautomationcoreapi.h
@@ -34,6 +34,9 @@ extern "C" {
#define UiaAppendRuntimeId 3
#define UiaRootObjectId -25
+#define UIA_PFIA_DEFAULT 0x00
+#define UIA_PFIA_UNWRAP_BRIDGE 0x01
+
DECLARE_HANDLE(HUIANODE);
DECLARE_HANDLE(HUIAPATTERNOBJECT);
DECLARE_HANDLE(HUIATEXTRANGE);
@@ -71,6 +74,7 @@ void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback);
LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov);
BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj);
HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **elprov);
+HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags, IRawElementProviderSimple **elprov);
#ifdef __cplusplus
}
--
2.25.1
April 29, 2022
Re: [PATCH vkd3d 1/8] vkd3d-shader/hlsl: Detect missing loads on rhs when splitting copies of non-numeric types.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
April 29, 2022
Re: [PATCH vkd3d 3/8] tests: Test initialization of implicit size arrays.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
April 29, 2022
Re: [PATCH vkd3d 8/8] vkd3d-shader/hlsl: Handle branches in copy propagation.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
April 29, 2022
Re: [PATCH vkd3d 7/8] vkd3d-shader/hlsl: Allow storing to matrices.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
April 29, 2022
Re: [PATCH vkd3d 2/8] tests: Test complex broadcasts.
by Henri Verbeet
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
April 29, 2022