Wine-devel
Threads by month
- ----- 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
October 2021
- 81 participants
- 772 discussions
[PATCH 1/2] qedit/tests: Check the Sample Grabber's buffer during and after flushing.
by Gabriel Ivăncescu 04 Oct '22
by Gabriel Ivăncescu 04 Oct '22
04 Oct '22
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/qedit/tests/samplegrabber.c | 234 +++++++++++++++++++++++++++++++
1 file changed, 234 insertions(+)
diff --git a/dlls/qedit/tests/samplegrabber.c b/dlls/qedit/tests/samplegrabber.c
index 8e68e3e..e66180f 100644
--- a/dlls/qedit/tests/samplegrabber.c
+++ b/dlls/qedit/tests/samplegrabber.c
@@ -1036,6 +1036,239 @@ static void test_connect_pin(void)
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
+struct frame_thread_params
+{
+ IMemInputPin *sink;
+ IMediaSample *sample;
+ DWORD delay;
+};
+
+static DWORD WINAPI frame_thread(void *arg)
+{
+ struct frame_thread_params *params = arg;
+ HRESULT hr;
+
+ if (params->delay)
+ {
+ if (winetest_debug > 1) trace("%04x: Sleeping %u ms.\n", GetCurrentThreadId(), params->delay);
+ Sleep(params->delay);
+ }
+ if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
+ hr = IMemInputPin_Receive(params->sink, params->sample);
+ if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
+ IMediaSample_Release(params->sample);
+ free(params);
+ return hr;
+}
+
+static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, unsigned char color, DWORD delay)
+{
+ struct frame_thread_params *params = malloc(sizeof(*params));
+ IMemAllocator *allocator;
+ REFERENCE_TIME end_time;
+ IMediaSample *sample;
+ HANDLE thread;
+ HRESULT hr;
+ BYTE *data;
+
+ hr = IMemInputPin_GetAllocator(sink, &allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ if (hr == VFW_E_NOT_COMMITTED)
+ {
+ IMemAllocator_Commit(allocator);
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ }
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaSample_GetPointer(sample, &data);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ memset(data, 0x55, 32 * 16 * 2);
+
+ hr = IMediaSample_SetActualDataLength(sample, 32 * 16 * 2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ start_time *= 10000000;
+ end_time = start_time + 10000000;
+ hr = IMediaSample_SetTime(sample, &start_time, &end_time);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ params->sink = sink;
+ params->sample = sample;
+ params->delay = delay;
+ thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
+
+ IMemAllocator_Release(allocator);
+ return thread;
+}
+
+static HANDLE send_frame(IMemInputPin *sink, DWORD delay)
+{
+ return send_frame_time(sink, 0, 0x55, delay); /* purple */
+}
+
+static HRESULT join_thread_(int line, HANDLE thread)
+{
+ DWORD ret;
+ ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n");
+ GetExitCodeThread(thread, &ret);
+ CloseHandle(thread);
+ return ret;
+}
+#define join_thread(a) join_thread_(__LINE__, a)
+
+static void test_buffer_flush(void)
+{
+ AM_MEDIA_TYPE req_mt =
+ {
+ .majortype = MEDIATYPE_Video,
+ .subtype = MEDIASUBTYPE_RGB565,
+ .formattype = FORMAT_VideoInfo,
+ .bTemporalCompression = TRUE,
+ };
+ LONG buf[(32 * 16 * 2) / sizeof(LONG)], size = sizeof(buf);
+ IPin *sink, *source, *renderer_pin;
+ struct testfilter testsource;
+ ISampleGrabber *grabber;
+ IMediaControl *control;
+ IFilterGraph2 *graph;
+ IMemInputPin *input;
+ IBaseFilter *filter;
+ OAFilterState state;
+ IMediaFilter *mf;
+ HANDLE thread;
+ DWORD ticks;
+ unsigned i;
+ HRESULT hr;
+ ULONG ref;
+
+ testfilter_init(&testsource);
+ CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IFilterGraph2, (void **)&graph);
+ CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IBaseFilter, (void **)&filter);
+ IFilterGraph2_AddFilter(graph, filter, L"sink");
+ IBaseFilter_FindPin(filter, L"In", &renderer_pin);
+ IBaseFilter_Release(filter);
+
+ filter = create_sample_grabber();
+ IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source");
+ IFilterGraph2_AddFilter(graph, filter, L"sample grabber");
+ IBaseFilter_FindPin(filter, L"In", &sink);
+ IBaseFilter_FindPin(filter, L"Out", &source);
+ IBaseFilter_QueryInterface(filter, &IID_ISampleGrabber, (void **)&grabber);
+ IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
+ IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input);
+
+ ISampleGrabber_SetMediaType(grabber, &req_mt);
+ ISampleGrabber_SetBufferSamples(grabber, TRUE);
+
+ testsource.sink_mt = &req_mt;
+ hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IFilterGraph2_ConnectDirect(graph, source, renderer_pin, &req_mt);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IPin_Release(renderer_pin);
+
+ IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&mf);
+ IMediaFilter_SetSyncSource(mf, NULL);
+ IMediaFilter_Release(mf);
+
+ hr = IMemInputPin_ReceiveCanBlock(input);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf);
+ ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ thread = send_frame(input, 0);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
+
+ for (i = 0; i < 3; i++)
+ {
+ ticks = GetTickCount();
+ hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf);
+ ticks = GetTickCount() - ticks;
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(ticks < 100, "Got %u ticks.\n", ticks);
+ ok(size == sizeof(buf), "Got size %d.\n", size);
+ }
+
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = join_thread(thread);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(state == State_Stopped, "Got state %d.\n", state);
+ hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaControl_Pause(control);
+ ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+ hr = IMediaControl_GetState(control, 0, &state);
+ ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ thread = send_frame(input, 0);
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
+
+ for (i = 0; i < 3; i++)
+ {
+ ticks = GetTickCount();
+ hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf);
+ ticks = GetTickCount() - ticks;
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(ticks < 100, "Got %u ticks.\n", ticks);
+ ok(size == sizeof(buf), "Got size %d.\n", size);
+ }
+
+ IPin_BeginFlush(sink);
+ hr = join_thread(thread);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IPin_EndFlush(sink);
+
+ hr = IMediaControl_GetState(control, 0, &state);
+ todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
+
+ ticks = GetTickCount();
+ thread = send_frame(input, 150);
+ hr = ISampleGrabber_GetCurrentBuffer(grabber, &size, buf);
+ ticks = GetTickCount() - ticks;
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(ticks < 100, "Got %u ticks.\n", ticks);
+ ok(size == sizeof(buf), "Got size %d.\n", size);
+
+ hr = IMediaControl_GetState(control, 1000, &state);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaControl_Stop(control);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = join_thread(thread);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ IPin_Release(sink);
+ IPin_Release(source);
+ IMemInputPin_Release(input);
+ IMediaControl_Release(control);
+ ref = IFilterGraph2_Release(graph);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ISampleGrabber_Release(grabber);
+ ref = IBaseFilter_Release(filter);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+}
+
START_TEST(samplegrabber)
{
IBaseFilter *filter;
@@ -1059,6 +1292,7 @@ START_TEST(samplegrabber)
test_aggregation();
test_media_types();
test_connect_pin();
+ test_buffer_flush();
CoUninitialize();
}
--
2.21.0
5
7
24 Jan '22
To help gdb reload symbol files from /proc/<pid>/maps, making it
possible to load debug info for ELF and PE modules for Wine processes.
When sourced (from ~/.gdbinit for instance), this adds a new
"load-symbol-files" command (with an "lsf" alias), which automatically
calls add-symbol-file on every mapped file that can be read as ELF or
PE, with the correct section offset.
The command has to be run manually, for instance after executing for
a while, to load new modules that may have been loaded, as there's no
way for gdb to be notified of such changes automatically.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
This is some script I've been using for a while, and more or less broken
versions are also used by other people, so I figured maybe it would be
better to have a proper working version officially distributed with Wine
source instead, as it's pretty useful for debugging Wine under gdb.
It's still a bit manual to use, as gdb cannot easily be notified of
dynamic library loading [1], but I think it's much better than having
nothing.
[1] in theory there's ways to do it using systemtap probes, but it's
going to be hard to make it work, especially for PE modules.
tools/gdbinit.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 tools/gdbinit.py
diff --git a/tools/gdbinit.py b/tools/gdbinit.py
new file mode 100644
index 00000000000..265d97722b7
--- /dev/null
+++ b/tools/gdbinit.py
@@ -0,0 +1,108 @@
+#!/bin/env python3
+
+# Copyright 2021 Rémi Bernon 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
+
+from __future__ import print_function
+
+import gdb
+import re
+import subprocess
+import sys
+
+class LoadSymbolFiles(gdb.Command):
+ 'Command to load symbol files directly from /proc/<pid>/maps.'
+
+ def __init__(self):
+ sup = super(LoadSymbolFiles, self)
+ sup.__init__('load-symbol-files', gdb.COMMAND_FILES, gdb.COMPLETE_NONE,
+ False)
+
+ self.libs = {}
+ gdb.execute('alias -a lsf = load-symbol-files', True)
+
+ def invoke(self, arg, from_tty):
+ pid = gdb.selected_inferior().pid
+ if not pid in self.libs: self.libs[pid] = {}
+
+ def command(cmd, confirm=from_tty):
+ to_string = not from_tty
+ gdb.execute(cmd, from_tty=confirm, to_string=to_string)
+
+ def execute(cmd):
+ return subprocess.check_output(cmd, stderr=subprocess.STDOUT) \
+ .decode('utf-8')
+
+ # load mappings addresses
+ libs = {}
+ with open('/proc/{}/maps'.format(pid), 'r') as maps:
+ for line in maps:
+ addr, _, _, _, node, path = re.split(r'\s+', line, 5)
+ path = path.strip()
+ if node == '0': continue
+ if path in libs: continue
+ libs[path] = int(addr.split('-')[0], 16)
+
+ # unload symbol file if address changed
+ for k in set(libs) & set(self.libs[pid]):
+ if libs[k] != self.libs[pid][k]:
+ command('remove-symbol-file "{}"'.format(k), confirm=False)
+ del self.libs[k]
+
+ # load symbol file for new mappings
+ for k in set(libs) - set(self.libs[pid]):
+ if arg is not None and re.search(arg, k) is None: continue
+ addr = self.libs[pid][k] = libs[k]
+ offs = None
+
+ try:
+ out = execute(['file', k])
+ except:
+ continue
+
+ # try loading mapping as ELF
+ try:
+ out = execute(['readelf', '-l', k])
+ for line in out.split('\n'):
+ if not 'LOAD' in line: continue
+ base = int(line.split()[2], 16)
+ break
+
+ out = execute(['objdump', '-h', k])
+ for line in out.split('\n'):
+ if not '.text' in line: continue
+ offs = int(line.split()[3], 16) - base
+ break
+ if offs is None: continue
+
+ # try again, assuming mapping is PE
+ except:
+ try:
+ out = execute(['objdump', '-h', k])
+ for line in out.split('\n'):
+ if not '.text' in line: continue
+ offs = int(line.split()[5], 16)
+ break
+ if offs is None: continue
+
+ except:
+ continue
+
+ command('add-symbol-file "{}" 0x{:x}'.format(k, addr + offs),
+ confirm=False)
+
+
+LoadSymbolFiles()
--
2.31.0
3
7
Applications expect a path starting with a drive like
'\Device\Harddisk1\' instead of a drive letter.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51687
Signed-off-by: Matias Zuniga <matias.nicolas.zc(a)gmail.com>
---
v2: Fix info.c test breakage
---
dlls/ntdll/unix/virtual.c | 97 ++++++++++++++++++++++++++++++++---
dlls/psapi/tests/psapi_main.c | 5 +-
2 files changed, 90 insertions(+), 12 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 984af2d4a21..48bfaf3cf99 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -133,6 +133,8 @@ struct file_view
} \
} while (0);
+#define SYMBOLIC_LINK_QUERY 0x0001
+
/* per-page protection flags */
#define VPROT_READ 0x01
#define VPROT_WRITE 0x02
@@ -4273,34 +4275,113 @@ static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr,
return STATUS_SUCCESS;
}
+static NTSTATUS read_nt_symlink( UNICODE_STRING *name, WCHAR *target, DWORD size )
+{
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES attr;
+ HANDLE handle;
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ if (!(status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &attr )))
+ {
+ UNICODE_STRING targetW;
+ targetW.Buffer = target;
+ targetW.MaximumLength = (size - 1) * sizeof(WCHAR);
+ status = NtQuerySymbolicLinkObject( handle, &targetW, NULL );
+ if (!status) target[targetW.Length / sizeof(WCHAR)] = 0;
+ NtClose( handle );
+ }
+ return status;
+}
+
+static NTSTATUS follow_device_symlink( WCHAR *name, SIZE_T max_path_len, WCHAR *buffer,
+ SIZE_T buffer_len, SIZE_T *current_path_len )
+{
+ WCHAR *p;
+ NTSTATUS status = STATUS_SUCCESS;
+ SIZE_T devname_len = 6 * sizeof(WCHAR); // e.g. \??\C:
+ UNICODE_STRING devname;
+ SIZE_T target_len;
+
+ if (*current_path_len > buffer_len) return STATUS_INVALID_PARAMETER;
+
+ if (*current_path_len >= devname_len && buffer[devname_len / sizeof(WCHAR) - 1] == ':') {
+ devname.Buffer = buffer;
+ devname.Length = devname_len;
+
+ p = buffer + (*current_path_len / sizeof(WCHAR));
+ if (!(status = read_nt_symlink( &devname, p, (buffer_len - *current_path_len) / sizeof(WCHAR) )))
+ {
+ *current_path_len -= devname_len; // skip the device name
+ target_len = lstrlenW(p) * sizeof(WCHAR);
+ *current_path_len += target_len;
+
+ if (*current_path_len <= max_path_len)
+ {
+ memcpy( name, p, target_len );
+ p = buffer + devname_len / sizeof(WCHAR);
+ memcpy( name + target_len / sizeof(WCHAR), p, *current_path_len - target_len);
+ }
+ else status = STATUS_BUFFER_OVERFLOW;
+ }
+ }
+ else if (*current_path_len <= max_path_len) {
+ memcpy( name, buffer, *current_path_len );
+ }
+ else status = STATUS_BUFFER_OVERFLOW;
+
+ return status;
+}
+
static NTSTATUS get_memory_section_name( HANDLE process, LPCVOID addr,
MEMORY_SECTION_NAME *info, SIZE_T len, SIZE_T *ret_len )
{
+ SIZE_T current_path_len, max_path_len = 0;
+ // buffer to hold the path + 6 chars devname (e.g. \??\C:)
+ SIZE_T buffer_len = (MAX_PATH + 6) * sizeof(WCHAR);
+ WCHAR *buffer = NULL;
NTSTATUS status;
if (!info) return STATUS_ACCESS_VIOLATION;
+ if (!(buffer = malloc( buffer_len ))) return STATUS_NO_MEMORY;
+ if (len > sizeof(*info) + sizeof(WCHAR))
+ {
+ max_path_len = len - sizeof(*info) - sizeof(WCHAR); // dont count null char
+ }
SERVER_START_REQ( get_mapping_filename )
{
req->process = wine_server_obj_handle( process );
req->addr = wine_server_client_ptr( addr );
- if (len > sizeof(*info) + sizeof(WCHAR))
- wine_server_set_reply( req, info + 1, len - sizeof(*info) - sizeof(WCHAR) );
+ wine_server_set_reply( req, buffer, MAX_PATH );
status = wine_server_call( req );
- if (!status || status == STATUS_BUFFER_OVERFLOW)
+ if (!status)
{
- if (ret_len) *ret_len = sizeof(*info) + reply->len + sizeof(WCHAR);
- if (len < sizeof(*info)) status = STATUS_INFO_LENGTH_MISMATCH;
+ current_path_len = reply->len;
+ status = follow_device_symlink( (WCHAR *)(info + 1), max_path_len, buffer, buffer_len, ¤t_path_len);
+ if (len < sizeof(*info))
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ if (ret_len) *ret_len = sizeof(*info) + current_path_len + sizeof(WCHAR);
if (!status)
{
info->SectionFileName.Buffer = (WCHAR *)(info + 1);
- info->SectionFileName.Length = reply->len;
- info->SectionFileName.MaximumLength = reply->len + sizeof(WCHAR);
- info->SectionFileName.Buffer[reply->len / sizeof(WCHAR)] = 0;
+ info->SectionFileName.Length = current_path_len;
+ info->SectionFileName.MaximumLength = current_path_len + sizeof(WCHAR);
+ info->SectionFileName.Buffer[current_path_len / sizeof(WCHAR)] = 0;
}
}
}
SERVER_END_REQ;
+ free(buffer);
return status;
}
diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c
index c4a740310a4..d6fb8e69384 100644
--- a/dlls/psapi/tests/psapi_main.c
+++ b/dlls/psapi/tests/psapi_main.c
@@ -471,7 +471,6 @@ static void test_GetMappedFileName(void)
ret = GetMappedFileNameA(GetCurrentProcess(), base, map_name, sizeof(map_name));
ok(ret, "GetMappedFileName error %d\n", GetLastError());
ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
- todo_wine
ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
SetLastError(0xdeadbeef);
@@ -482,7 +481,6 @@ static void test_GetMappedFileName(void)
{
ok(memcmp(map_nameW, nt_map_name, lstrlenW(map_nameW)) == 0, "map name does not start with a device name: %s\n", map_name);
WideCharToMultiByte(CP_ACP, 0, map_nameW, -1, map_name, MAX_PATH, NULL, NULL);
- todo_wine
ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
}
@@ -490,7 +488,6 @@ static void test_GetMappedFileName(void)
ret = GetMappedFileNameA(GetCurrentProcess(), base + 0x2000, map_name, sizeof(map_name));
ok(ret, "GetMappedFileName error %d\n", GetLastError());
ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
- todo_wine
ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
SetLastError(0xdeadbeef);
@@ -566,7 +563,7 @@ static void test_GetProcessImageFileName(void)
{
/* Windows returns 2*strlen-1 */
ok(ret >= strlen(szImgPath), "szImgPath=\"%s\" ret=%d\n", szImgPath, ret);
- todo_wine ok(!strcmp(szImgPath, szMapPath), "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath);
+ ok(!strcmp(szImgPath, szMapPath), "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath);
}
SetLastError(0xdeadbeef);
--
2.31.1
3
2
Despite what msdn states, I and I32 are supported width modifiers.
V2:
- better code structure
- added support and tests for I32
Signed-off-by: Eric Pouech <eric.pouech(a)gmail.com>
---
dlls/msvcrt/scanf.h | 10 ++++++++--
dlls/msvcrt/tests/scanf.c | 46 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcrt/scanf.h b/dlls/msvcrt/scanf.h
index 3ab2efef13d..02284379854 100644
--- a/dlls/msvcrt/scanf.h
+++ b/dlls/msvcrt/scanf.h
@@ -279,13 +279,19 @@ _FUNCTION_ {
*(format + 2) == '4') {
I64_prefix = 1;
format += 2;
+ break;
}
- break;
+ else if (*(format + 1) == '3' &&
+ *(format + 2) == '2') {
+ format += 2;
+ break;
+ }
+ /* fall through */
#if _MSVCR_VER == 0 || _MSVCR_VER >= 140
case 'z':
+#endif
if (sizeof(void *) == sizeof(LONGLONG)) I64_prefix = 1;
break;
-#endif
default:
prefix_finished = 1;
}
diff --git a/dlls/msvcrt/tests/scanf.c b/dlls/msvcrt/tests/scanf.c
index e175342796b..6541f5fd5cb 100644
--- a/dlls/msvcrt/tests/scanf.c
+++ b/dlls/msvcrt/tests/scanf.c
@@ -74,6 +74,7 @@ static void test_sscanf( void )
int hour=21,min=59,sec=20;
int number,number_so_far;
HMODULE hmod = GetModuleHandleA("msvcrt.dll");
+ DWORD_PTR result_ptr;
p_sprintf = (void *)GetProcAddress( hmod, "sprintf" );
p_sscanf = (void *)GetProcAddress( hmod, "sscanf" );
@@ -264,6 +265,51 @@ static void test_sscanf( void )
if(ret == 14)
ok(!strcmp(buffer, buffer1), "got %s, expected %s\n", buffer1, buffer);
+ strcpy(buffer,"12345678901234");
+ ret = p_sscanf(buffer, "%I64d", &result64);
+ ok(ret == 1, "Wrong number of arguments read: %d\n", ret);
+ ret = p_sprintf(buffer1, "%I64d", result64);
+ ok(ret==14 || broken(ret==10), "sprintf returned %d\n", ret);
+ if(ret == 14)
+ ok(!strcmp(buffer, buffer1), "got %s, expected %s\n", buffer1, buffer);
+
+ result = 0;
+ strcpy(buffer,"0x123456789");
+ ret = p_sscanf(buffer, "%I32x", &result);
+ ok(ret == 1, "Wrong number of arguments read: %d\n", ret);
+ ok(result == 0x23456789, "got %x, expected 0x23456789\n", result);
+
+ result_ptr = 0;
+ strcpy(buffer,"0x87654321");
+ ret = p_sscanf(buffer, "%Ix", &result_ptr);
+ ok(ret == 1, "Wrong number of arguments read: %d\n", ret);
+ if (sizeof(void*) == sizeof(LONGLONG))
+ {
+ ret = p_sprintf(buffer1, "%#Ix", result_ptr);
+ ok(ret==9, "sprintf returned %d\n", ret);
+ if(ret == 9)
+ ok(!strcmp(buffer, buffer1), "got %s, expected %s\n", buffer1, buffer);
+ }
+ else
+ {
+ ok(result_ptr == 0x87654321, "got %x, expected 0x23456789\n", result);
+ }
+ result_ptr = 0;
+ strcpy(buffer,"0x123456789");
+ ret = p_sscanf(buffer, "%Ix", &result_ptr);
+ ok(ret == 1, "Wrong number of arguments read: %d\n", ret);
+ if (sizeof(void*) == sizeof(LONGLONG))
+ {
+ ret = p_sprintf(buffer1, "%#Ix", result_ptr);
+ ok(ret==11, "sprintf returned %d\n", ret);
+ if(ret == 11)
+ ok(!strcmp(buffer, buffer1), "got %s, expected %s\n", buffer1, buffer);
+ }
+ else
+ {
+ ok(result_ptr == 0x23456789, "got %x, expected 0x23456789\n", result);
+ }
+
/* Check %i according to bug 1878 */
strcpy(buffer,"123");
ret = p_sscanf(buffer, "%i", &result);
4
6
20 Dec '21
GCC11 implements new warnings. This serie of patches:
- works around a couple of false positive
- fixes a couple of bad handling of corner cases in error handling
- last patch should be reviewed by D3D folks. The fix is consistent with
function definition, and no regression appear in make test...
A+
---
Eric Pouech (6):
dlls/msvcrt*: ensure variable sse2_cw is set for all code paths in _control87 (GCC11)
In tests, ensure buffers passed as const pointers are always initialized (GCC11)
kernelbase: always return NULL in case of error in GetModuleHandleA (GCC11)
kernel32/tests: mark pointer as volatile when reading after allocated size
Workaround GCC11 complaining about sizeof(a)/sizeof(b) constructs when it's
d3dx9_36/tests: fixed order of parameters
dlls/d3dx9_36/mesh.c | 2 +-
dlls/d3dx9_36/tests/effect.c | 4 ++--
dlls/d3dx9_36/tests/mesh.c | 4 ++--
dlls/kernel32/tests/heap.c | 3 ++-
dlls/kernelbase/loader.c | 2 +-
dlls/kernelbase/tests/path.c | 1 +
dlls/msvcirt/tests/msvcirt.c | 5 +++--
dlls/msvcrt/math.c | 2 +-
dlls/shlwapi/tests/clist.c | 1 +
9 files changed, 14 insertions(+), 10 deletions(-)
8
23
12 Nov '21
v2: Fix the spaces.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/user32/tests/win.c | 29 ++++++++++++++++----
dlls/user32/win.c | 59 ++++++++++++++++++++++++++++++-----------
2 files changed, 67 insertions(+), 21 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 6b13d93be14..dc18d054496 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -7923,17 +7923,36 @@ static void test_gettext(void)
if (0)
{
r = SendMessageA( hwnd, WM_GETTEXT, 0x10, 0x1000);
- ok( r == 0, "settext should return zero\n");
+ ok( r == 0, "WM_GETTEXT should return zero (%ld)\n", r );
r = SendMessageA( hwnd, WM_GETTEXT, 0x10000, 0);
- ok( r == 0, "settext should return zero (%ld)\n", r);
+ ok( r == 0, "WM_GETTEXT should return zero (%ld)\n", r );
r = SendMessageA( hwnd, WM_GETTEXT, 0xff000000, 0x1000);
- ok( r == 0, "settext should return zero (%ld)\n", r);
+ ok( r == 0, "WM_GETTEXT should return zero (%ld)\n", r );
r = SendMessageA( hwnd, WM_GETTEXT, 0x1000, 0xff000000);
- ok( r == 0, "settext should return zero (%ld)\n", r);
- }
+ ok( r == 0, "WM_GETTEXT should return zero (%ld)\n", r );
+ }
+
+ /* GetWindowText doesn't crash */
+ r = GetWindowTextA( hwnd, (LPSTR)0x10, 0x1000 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+ r = GetWindowTextA( hwnd, (LPSTR)0x10000, 0 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+ r = GetWindowTextA( hwnd, (LPSTR)0xff000000, 0x1000 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+ r = GetWindowTextA( hwnd, (LPSTR)0x1000, 0xff000000 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+
+ r = GetWindowTextW( hwnd, (LPWSTR)0x10, 0x1000 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+ r = GetWindowTextW( hwnd, (LPWSTR)0x10000, 0 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+ r = GetWindowTextW( hwnd, (LPWSTR)0xff000000, 0x1000 );
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
+ r = GetWindowTextW( hwnd, (LPWSTR)0x1000, 0xff000000);
+ ok( r == 0, "GetWindowText should return zero (%ld)\n", r );
DestroyWindow(hwnd);
}
diff --git a/dlls/user32/win.c b/dlls/user32/win.c
index 5e89f4c2c97..e57f291be35 100644
--- a/dlls/user32/win.c
+++ b/dlls/user32/win.c
@@ -35,6 +35,7 @@
#include "controls.h"
#include "winerror.h"
#include "wine/gdi_driver.h"
+#include "wine/exception.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(win);
@@ -3001,22 +3002,34 @@ LONG WINAPI DECLSPEC_HOTPATCH SetWindowLongW(
INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
{
WCHAR *buffer;
+ int ret = 0;
if (!lpString || nMaxCount <= 0) return 0;
- if (WIN_IsCurrentProcess( hwnd ))
+ __TRY
{
- lpString[0] = 0;
- return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
+ if (WIN_IsCurrentProcess( hwnd ))
+ {
+ lpString[0] = 0;
+ ret = (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
+ }
+ else if ((buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) )))
+ {
+ /* when window belongs to other process, don't send a message */
+ get_server_window_text( hwnd, buffer, nMaxCount );
+ if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
+ lpString[nMaxCount-1] = 0;
+ HeapFree( GetProcessHeap(), 0, buffer );
+ ret = strlen(lpString);
+ }
+ }
+ __EXCEPT_ALL
+ {
+ ret = 0;
}
+ __ENDTRY
- /* when window belongs to other process, don't send a message */
- if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
- get_server_window_text( hwnd, buffer, nMaxCount );
- if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
- lpString[nMaxCount-1] = 0;
- HeapFree( GetProcessHeap(), 0, buffer );
- return strlen(lpString);
+ return ret;
}
@@ -3049,17 +3062,31 @@ INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
*/
INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
{
+ int ret;
+
if (!lpString || nMaxCount <= 0) return 0;
- if (WIN_IsCurrentProcess( hwnd ))
+ __TRY
{
- lpString[0] = 0;
- return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
+ if (WIN_IsCurrentProcess( hwnd ))
+ {
+ lpString[0] = 0;
+ ret = (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
+ }
+ else
+ {
+ /* when window belongs to other process, don't send a message */
+ get_server_window_text( hwnd, lpString, nMaxCount );
+ ret = lstrlenW(lpString);
+ }
}
+ __EXCEPT_ALL
+ {
+ ret = 0;
+ }
+ __ENDTRY
- /* when window belongs to other process, don't send a message */
- get_server_window_text( hwnd, lpString, nMaxCount );
- return lstrlenW(lpString);
+ return ret;
}
--
2.31.1
3
5
12 Nov '21
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/ole32/moniker.h | 4 +-
dlls/ole32/ole32.spec | 2 +-
dlls/ole32/ole32_objidl.idl | 6 +
dlls/ole32/oleproxy.c | 13 ++
dlls/ole32/pointermoniker.c | 418 +++++++++++++++++++++++++++++++++++-
dlls/ole32/tests/moniker.c | 249 ++++++++++++++++++++-
include/objidl.idl | 5 +-
7 files changed, 691 insertions(+), 6 deletions(-)
diff --git a/dlls/ole32/moniker.h b/dlls/ole32/moniker.h
index 8549bd46c1e..2106e374394 100644
--- a/dlls/ole32/moniker.h
+++ b/dlls/ole32/moniker.h
@@ -26,15 +26,17 @@
DEFINE_OLEGUID( CLSID_FileMoniker, 0x303, 0, 0 );
DEFINE_OLEGUID( CLSID_ItemMoniker, 0x304, 0, 0 );
DEFINE_OLEGUID( CLSID_AntiMoniker, 0x305, 0, 0 );
+DEFINE_OLEGUID( CLSID_PointerMoniker, 0x306, 0, 0 );
DEFINE_OLEGUID( CLSID_CompositeMoniker, 0x309, 0, 0 );
DEFINE_OLEGUID( CLSID_ClassMoniker, 0x31a, 0, 0 );
-DEFINE_OLEGUID( CLSID_PointerMoniker, 0x306, 0, 0 );
+DEFINE_OLEGUID( CLSID_ObjrefMoniker, 0x327, 0, 0 );
HRESULT WINAPI FileMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
HRESULT WINAPI ItemMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
HRESULT WINAPI AntiMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
HRESULT WINAPI ClassMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
+HRESULT WINAPI ObjrefMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
HRESULT WINAPI PointerMoniker_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
HRESULT WINAPI ComCat_CreateInstance(IClassFactory *iface, IUnknown *pUnk, REFIID riid, void **ppv);
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec
index 8e73fdd16b4..d9ffd63585c 100644
--- a/dlls/ole32/ole32.spec
+++ b/dlls/ole32/ole32.spec
@@ -103,7 +103,7 @@
@ stdcall CreateGenericComposite(ptr ptr ptr)
@ stdcall CreateILockBytesOnHGlobal(ptr long ptr)
@ stdcall CreateItemMoniker(wstr wstr ptr)
-@ stub CreateObjrefMoniker
+@ stdcall CreateObjrefMoniker(ptr ptr)
@ stdcall CreateOleAdviseHolder(ptr)
@ stdcall CreatePointerMoniker(ptr ptr)
@ stdcall CreateStreamOnHGlobal(ptr long ptr) combase.CreateStreamOnHGlobal
diff --git a/dlls/ole32/ole32_objidl.idl b/dlls/ole32/ole32_objidl.idl
index 0cc3ccea9e5..97f91224839 100644
--- a/dlls/ole32/ole32_objidl.idl
+++ b/dlls/ole32/ole32_objidl.idl
@@ -105,6 +105,12 @@ coclass ClassMoniker { interface IMoniker; }
]
coclass PSFactoryBuffer { interface IFactoryBuffer; }
+[
+ threading(both),
+ uuid(00000327-0000-0000-c000-000000000046)
+]
+coclass ObjrefMoniker { interface IMoniker; }
+
[
helpstring("Component Categories Manager"),
threading(both),
diff --git a/dlls/ole32/oleproxy.c b/dlls/ole32/oleproxy.c
index e40e2b073e5..c429ce02b3b 100644
--- a/dlls/ole32/oleproxy.c
+++ b/dlls/ole32/oleproxy.c
@@ -137,6 +137,17 @@ static const IClassFactoryVtbl PointerMonikerCFVtbl =
static IClassFactory PointerMonikerCF = { &PointerMonikerCFVtbl };
+static const IClassFactoryVtbl ObjrefMonikerCFVtbl =
+{
+ ClassFactory_QueryInterface,
+ ClassFactory_AddRef,
+ ClassFactory_Release,
+ ObjrefMoniker_CreateInstance,
+ ClassFactory_LockServer
+};
+
+static IClassFactory ObjrefMonikerCF = { &ObjrefMonikerCFVtbl };
+
static const IClassFactoryVtbl ComCatCFVtbl =
{
ClassFactory_QueryInterface,
@@ -198,6 +209,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
return IClassFactory_QueryInterface(&CompositeMonikerCF, iid, ppv);
if (IsEqualCLSID(rclsid, &CLSID_ClassMoniker))
return IClassFactory_QueryInterface(&ClassMonikerCF, iid, ppv);
+ if (IsEqualCLSID(rclsid, &CLSID_ObjrefMoniker))
+ return IClassFactory_QueryInterface(&ObjrefMonikerCF, iid, ppv);
if (IsEqualCLSID(rclsid, &CLSID_PointerMoniker))
return IClassFactory_QueryInterface(&PointerMonikerCF, iid, ppv);
if (IsEqualGUID(rclsid, &CLSID_StdComponentCategoriesMgr))
diff --git a/dlls/ole32/pointermoniker.c b/dlls/ole32/pointermoniker.c
index 051d42aca6d..c95c835e9e3 100644
--- a/dlls/ole32/pointermoniker.c
+++ b/dlls/ole32/pointermoniker.c
@@ -1,5 +1,5 @@
/*
- * Pointer Moniker Implementation
+ * Pointer and Objref Monikers Implementation
*
* Copyright 1999 Noomen Hamza
* Copyright 2008 Robert Shearman (for CodeWeavers)
@@ -641,3 +641,419 @@ HRESULT WINAPI PointerMoniker_CreateInstance(IClassFactory *iface,
return hr;
}
+
+/* ObjrefMoniker implementation */
+
+typedef struct
+{
+ IMoniker IMoniker_iface;
+ IMarshal IMarshal_iface;
+
+ LONG refcount;
+
+ IUnknown *pObject;
+} ObjrefMonikerImpl;
+
+static inline ObjrefMonikerImpl *objref_impl_from_IMoniker(IMoniker *iface)
+{
+ return CONTAINING_RECORD(iface, ObjrefMonikerImpl, IMoniker_iface);
+}
+
+static ObjrefMonikerImpl *objref_impl_from_IMarshal(IMarshal *iface)
+{
+ return CONTAINING_RECORD(iface, ObjrefMonikerImpl, IMarshal_iface);
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_QueryInterface(IMoniker *iface, REFIID iid, void **obj)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMoniker(iface);
+
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), obj);
+
+ if (!obj)
+ return E_INVALIDARG;
+
+ *obj = 0;
+
+ if (IsEqualIID(iid, &IID_IUnknown) ||
+ IsEqualIID(iid, &IID_IPersist) ||
+ IsEqualIID(iid, &IID_IPersistStream) ||
+ IsEqualIID(iid, &IID_IMoniker) ||
+ IsEqualGUID(iid, &CLSID_ObjrefMoniker) ||
+ IsEqualGUID(iid, &CLSID_PointerMoniker))
+ {
+ *obj = iface;
+ }
+ else if (IsEqualIID(iid, &IID_IMarshal))
+ *obj = &moniker->IMarshal_iface;
+ else
+ return E_NOINTERFACE;
+
+ IMoniker_AddRef(iface);
+
+ return S_OK;
+}
+
+static ULONG WINAPI ObjrefMonikerImpl_AddRef(IMoniker *iface)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMoniker(iface);
+ ULONG refcount = InterlockedIncrement(&moniker->refcount);
+
+ TRACE("%p, refcount %u\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI ObjrefMonikerImpl_Release(IMoniker *iface)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMoniker(iface);
+ ULONG refcount = InterlockedDecrement(&moniker->refcount);
+
+ TRACE("%p, refcount %u\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (moniker->pObject) IUnknown_Release(moniker->pObject);
+ heap_free(moniker);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_GetClassID(IMoniker *iface, CLSID *clsid)
+{
+ TRACE("(%p,%p)\n", iface, clsid);
+
+ if (!clsid)
+ return E_POINTER;
+
+ *clsid = CLSID_ObjrefMoniker;
+ return S_OK;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_IsDirty(IMoniker *iface)
+{
+ FIXME("(%p): stub\n", iface);
+ return S_FALSE;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_Load(IMoniker *iface, IStream *stream)
+{
+ FIXME("(%p,%p): stub\n", iface, stream);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_Save(IMoniker *iface, IStream *stream, BOOL dirty)
+{
+ FIXME("(%p,%p,%d): stub\n", iface, stream, dirty);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *size)
+{
+ FIXME("(%p,%p): stub\n", iface, size);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_BindToObject(IMoniker *iface, IBindCtx *pbc, IMoniker *left,
+ REFIID riid, void **result)
+{
+ FIXME("(%p,%p,%p,%s,%p): stub\n", iface, pbc, left, debugstr_guid(riid), result);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *left,
+ REFIID riid, void **result)
+{
+ FIXME("(%p,%p,%p,%s,%p): stub\n", iface, pbc, left, debugstr_guid(riid), result);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD howfar,
+ IMoniker **left, IMoniker **reduced)
+{
+ FIXME("(%p,%p,%d,%p,%p): stub\n", iface, pbc, howfar, left, reduced);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_ComposeWith(IMoniker *iface, IMoniker *right,
+ BOOL only_if_not_generic, IMoniker **result)
+{
+ FIXME("(%p,%p,%d,%p): stub\n", iface, right, only_if_not_generic, result);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_Enum(IMoniker *iface, BOOL forward, IEnumMoniker **enummoniker)
+{
+ TRACE("(%p,%d,%p)\n", iface, forward, enummoniker);
+
+ if (!enummoniker)
+ return E_POINTER;
+
+ *enummoniker = NULL;
+ return S_OK;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_IsEqual(IMoniker *iface, IMoniker *other)
+{
+ FIXME("(%p,%p): stub\n", iface, other);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_Hash(IMoniker *iface, DWORD *hash)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMoniker(iface);
+
+ TRACE("(%p,%p)\n", iface, hash);
+
+ if (!hash)
+ return E_POINTER;
+
+ *hash = PtrToUlong(moniker->pObject);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *left,
+ IMoniker *running)
+{
+ FIXME("(%p,%p,%p,%p): stub\n", iface, pbc, left, running);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_GetTimeOfLastChange(IMoniker *iface,
+ IBindCtx *pbc, IMoniker *left, FILETIME *time)
+{
+ FIXME("(%p,%p,%p,%p): stub\n", iface, pbc, left, time);
+ return MK_E_UNAVAILABLE;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_Inverse(IMoniker *iface, IMoniker **moniker)
+{
+ FIXME("(%p,%p): stub\n", iface, moniker);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_CommonPrefixWith(IMoniker *iface, IMoniker *other, IMoniker **prefix)
+{
+ FIXME("(%p,%p,%p): stub\n", iface, other, prefix);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_RelativePathTo(IMoniker *iface, IMoniker *other, IMoniker **result)
+{
+ FIXME("(%p,%p,%p): stub\n", iface, other, result);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
+ IMoniker *left, LPOLESTR *name)
+{
+ FIXME("(%p,%p,%p,%p): stub\n", iface, pbc, left, name);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
+ IMoniker *left, LPOLESTR name, ULONG *eaten, IMoniker **out)
+{
+ FIXME("(%p,%p,%p,%p,%p,%p): stub\n", iface, pbc, left, name, eaten, out);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ObjrefMonikerImpl_IsSystemMoniker(IMoniker *iface, DWORD *mksys)
+{
+ TRACE("(%p,%p)\n", iface, mksys);
+
+ if (!mksys)
+ return E_POINTER;
+
+ *mksys = MKSYS_OBJREFMONIKER;
+ return S_OK;
+}
+
+static const IMonikerVtbl VT_ObjrefMonikerImpl =
+{
+ ObjrefMonikerImpl_QueryInterface,
+ ObjrefMonikerImpl_AddRef,
+ ObjrefMonikerImpl_Release,
+ ObjrefMonikerImpl_GetClassID,
+ ObjrefMonikerImpl_IsDirty,
+ ObjrefMonikerImpl_Load,
+ ObjrefMonikerImpl_Save,
+ ObjrefMonikerImpl_GetSizeMax,
+ ObjrefMonikerImpl_BindToObject,
+ ObjrefMonikerImpl_BindToStorage,
+ ObjrefMonikerImpl_Reduce,
+ ObjrefMonikerImpl_ComposeWith,
+ ObjrefMonikerImpl_Enum,
+ ObjrefMonikerImpl_IsEqual,
+ ObjrefMonikerImpl_Hash,
+ ObjrefMonikerImpl_IsRunning,
+ ObjrefMonikerImpl_GetTimeOfLastChange,
+ ObjrefMonikerImpl_Inverse,
+ ObjrefMonikerImpl_CommonPrefixWith,
+ ObjrefMonikerImpl_RelativePathTo,
+ ObjrefMonikerImpl_GetDisplayName,
+ ObjrefMonikerImpl_ParseDisplayName,
+ ObjrefMonikerImpl_IsSystemMoniker
+};
+
+static HRESULT WINAPI objref_moniker_marshal_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
+
+ return IMoniker_QueryInterface(&moniker->IMoniker_iface, riid, ppv);
+}
+
+static ULONG WINAPI objref_moniker_marshal_AddRef(IMarshal *iface)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+
+ TRACE("(%p)\n", iface);
+
+ return IMoniker_AddRef(&moniker->IMoniker_iface);
+}
+
+static ULONG WINAPI objref_moniker_marshal_Release(IMarshal *iface)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+
+ TRACE("(%p)\n", iface);
+
+ return IMoniker_Release(&moniker->IMoniker_iface);
+}
+
+static HRESULT WINAPI objref_moniker_marshal_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
+ DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+
+ TRACE("(%p,%s,%p,%08x,%p,%x,%p)\n", iface, debugstr_guid(riid), pv, dwDestContext, pvDestContext,
+ mshlflags, clsid);
+
+ return IMoniker_GetClassID(&moniker->IMoniker_iface, clsid);
+}
+
+static HRESULT WINAPI objref_moniker_marshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
+ DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *size)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+
+ TRACE("(%p,%s,%p,%08x,%p,%08x,%p)\n", iface, debugstr_guid(riid), pv, dwDestContext, pvDestContext,
+ mshlflags, size);
+
+ return CoGetMarshalSizeMax(size, &IID_IUnknown, moniker->pObject, dwDestContext, pvDestContext, mshlflags);
+}
+
+static HRESULT WINAPI objref_moniker_marshal_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid,
+ void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+
+ TRACE("(%p,%s,%p,%08x,%p,%08x)\n", stream, debugstr_guid(riid), pv, dwDestContext, pvDestContext, mshlflags);
+
+ return CoMarshalInterface(stream, &IID_IUnknown, moniker->pObject, dwDestContext, pvDestContext, mshlflags);
+}
+
+static HRESULT WINAPI objref_moniker_marshal_UnmarshalInterface(IMarshal *iface, IStream *stream,
+ REFIID riid, void **ppv)
+{
+ ObjrefMonikerImpl *moniker = objref_impl_from_IMarshal(iface);
+ IUnknown *object;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%s,%p)\n", iface, stream, debugstr_guid(riid), ppv);
+
+ hr = CoUnmarshalInterface(stream, &IID_IUnknown, (void **)&object);
+ if (FAILED(hr))
+ {
+ ERR("Couldn't unmarshal moniker, hr = %#x.\n", hr);
+ return hr;
+ }
+
+ if (moniker->pObject)
+ IUnknown_Release(moniker->pObject);
+ moniker->pObject = object;
+
+ return IMoniker_QueryInterface(&moniker->IMoniker_iface, riid, ppv);
+}
+
+static HRESULT WINAPI objref_moniker_marshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
+{
+ TRACE("(%p,%p)\n", iface, stream);
+ return S_OK;
+}
+
+static HRESULT WINAPI objref_moniker_marshal_DisconnectObject(IMarshal *iface, DWORD reserved)
+{
+ TRACE("(%p,%08x)\n", iface, reserved);
+ return S_OK;
+}
+
+static const IMarshalVtbl objref_moniker_marshal_vtbl =
+{
+ objref_moniker_marshal_QueryInterface,
+ objref_moniker_marshal_AddRef,
+ objref_moniker_marshal_Release,
+ objref_moniker_marshal_GetUnmarshalClass,
+ objref_moniker_marshal_GetMarshalSizeMax,
+ objref_moniker_marshal_MarshalInterface,
+ objref_moniker_marshal_UnmarshalInterface,
+ objref_moniker_marshal_ReleaseMarshalData,
+ objref_moniker_marshal_DisconnectObject
+};
+
+/***********************************************************************
+ * CreateObjrefMoniker (OLE32.@)
+ */
+HRESULT WINAPI CreateObjrefMoniker(IUnknown *obj, IMoniker **ret)
+{
+ ObjrefMonikerImpl *moniker;
+
+ TRACE("(%p,%p)\n", obj, ret);
+
+ if (!ret)
+ return E_INVALIDARG;
+
+ moniker = heap_alloc(sizeof(*moniker));
+ if (!moniker)
+ {
+ *ret = NULL;
+ return E_OUTOFMEMORY;
+ }
+
+ moniker->IMoniker_iface.lpVtbl = &VT_ObjrefMonikerImpl;
+ moniker->IMarshal_iface.lpVtbl = &objref_moniker_marshal_vtbl;
+ moniker->refcount = 1;
+ moniker->pObject = obj;
+ if (moniker->pObject)
+ IUnknown_AddRef(moniker->pObject);
+
+ *ret = &moniker->IMoniker_iface;
+
+ return S_OK;
+}
+
+HRESULT WINAPI ObjrefMoniker_CreateInstance(IClassFactory *iface, IUnknown *unk, REFIID iid, void **obj)
+{
+ IMoniker *moniker;
+ HRESULT hr;
+
+ TRACE("(%p,%s,%p)\n", unk, debugstr_guid(iid), obj);
+
+ *obj = NULL;
+
+ if (unk)
+ return CLASS_E_NOAGGREGATION;
+
+ hr = CreateObjrefMoniker(NULL, &moniker);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IMoniker_QueryInterface(moniker, iid, obj);
+ IMoniker_Release(moniker);
+
+ return hr;
+}
diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c
index 8d3276651bc..d2c83c173ba 100644
--- a/dlls/ole32/tests/moniker.c
+++ b/dlls/ole32/tests/moniker.c
@@ -82,9 +82,10 @@ static const CLSID CLSID_TestMoniker =
DEFINE_OLEGUID(CLSID_FileMoniker, 0x303, 0, 0);
DEFINE_OLEGUID(CLSID_ItemMoniker, 0x304, 0, 0);
DEFINE_OLEGUID(CLSID_AntiMoniker, 0x305, 0, 0);
+DEFINE_OLEGUID(CLSID_PointerMoniker, 0x306, 0, 0);
DEFINE_OLEGUID(CLSID_CompositeMoniker, 0x309, 0, 0);
DEFINE_OLEGUID(CLSID_ClassMoniker, 0x31a, 0, 0);
-DEFINE_OLEGUID(CLSID_PointerMoniker, 0x306, 0, 0);
+DEFINE_OLEGUID(CLSID_ObjrefMoniker, 0x327, 0, 0);
#define TEST_MONIKER_TYPE_TODO(m,t) _test_moniker_type(m, t, TRUE, __LINE__)
#define TEST_MONIKER_TYPE(m,t) _test_moniker_type(m, t, FALSE, __LINE__)
@@ -3861,7 +3862,7 @@ todo_wine
hr = IMarshal_GetUnmarshalClass(marshal, NULL, NULL, 0, NULL, 0, &clsid);
ok(hr == S_OK, "Failed to get class, hr %#x.\n", hr);
- ok(IsEqualGUID(&clsid, &CLSID_PointerMoniker), "Unexpected class.\n");
+ ok(IsEqualGUID(&clsid, &CLSID_PointerMoniker), "Unexpected class %s.\n", wine_dbgstr_guid(&clsid));
hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IMoniker, NULL, CLSCTX_INPROC, NULL, 0, &size);
ok(hr == S_OK, "Failed to get marshal size, hr %#x.\n", hr);
@@ -4076,6 +4077,249 @@ todo_wine
IMoniker_Release(moniker);
}
+static void test_objref_moniker(void)
+{
+ IMoniker *moniker, *moniker2, *prefix, *inverse, *anti;
+ struct test_factory factory;
+ IEnumMoniker *enummoniker;
+ DWORD hash, size;
+ HRESULT hr;
+ IBindCtx *bindctx;
+ FILETIME filetime;
+ IUnknown *unknown;
+ IStream *stream;
+ IROTData *rotdata;
+ LPOLESTR display_name;
+ IMarshal *marshal;
+ LARGE_INTEGER pos;
+ CLSID clsid;
+
+ test_factory_init(&factory);
+
+ hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, NULL);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x\n", hr);
+
+ hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker);
+ ok(hr == S_OK, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_QueryInterface(moniker, &IID_IMoniker, NULL);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_QueryInterface(moniker, &CLSID_PointerMoniker, (void **)&unknown);
+ ok(unknown == (IUnknown *)moniker, "Unexpected interface\n");
+ IUnknown_Release(unknown);
+
+ hr = IMoniker_QueryInterface(moniker, &CLSID_ObjrefMoniker, (void **)&unknown);
+ ok(unknown == (IUnknown *)moniker, "Unexpected interface\n");
+ IUnknown_Release(unknown);
+
+ hr = IMoniker_QueryInterface(moniker, &IID_IMarshal, (void **)&marshal);
+ ok(hr == S_OK, "Failed to get interface, hr %#x\n", hr);
+
+ hr = IMarshal_GetUnmarshalClass(marshal, NULL, NULL, 0, NULL, 0, &clsid);
+ ok(hr == S_OK, "Failed to get class, hr %#x\n", hr);
+ ok(IsEqualGUID(&clsid, &CLSID_ObjrefMoniker), "Unexpected class %s\n", wine_dbgstr_guid(&clsid));
+
+ hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IMoniker, NULL, CLSCTX_INPROC, NULL, 0, &size);
+ ok(hr == S_OK, "Failed to get marshal size, hr %#x\n", hr);
+ ok(size > 0, "Unexpected size %d\n", size);
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+ ok(hr == S_OK, "Failed to create a stream, hr %#x\n", hr);
+
+ hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
+ ok(hr == S_OK, "Failed to marshal moniker, hr %#x\n", hr);
+
+ pos.QuadPart = 0;
+ IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+ hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker2);
+ ok(hr == S_OK, "Failed to unmarshal, hr %#x\n", hr);
+ hr = IMoniker_IsEqual(moniker, moniker2);
+todo_wine
+ ok(hr == S_OK, "Expected equal moniker, hr %#x\n", hr);
+ IMoniker_Release(moniker2);
+
+ IStream_Release(stream);
+
+ IMarshal_Release(marshal);
+
+ ok(factory.refcount > 1, "Unexpected factory refcount %u\n", factory.refcount);
+
+ /* Display Name */
+
+ hr = CreateBindCtx(0, &bindctx);
+ ok(hr == S_OK, "CreateBindCtx failed: 0x%08x\n", hr);
+
+ hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
+todo_wine
+ ok(hr == S_OK, "IMoniker_GetDisplayName failed: 0x%08x\n", hr);
+
+ IBindCtx_Release(bindctx);
+
+ hr = IMoniker_IsDirty(moniker);
+ ok(hr == S_FALSE, "IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", hr);
+
+ /* IROTData::GetComparisonData test */
+
+ hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
+ ok(hr == E_NOINTERFACE, "IMoniker_QueryInterface(IID_IROTData) should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
+
+ /* Saving */
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+ ok(hr == S_OK, "CreateStreamOnHGlobal failed: 0x%08x\n", hr);
+
+ hr = IMoniker_Save(moniker, stream, TRUE);
+todo_wine
+ ok(hr == S_OK, "IMoniker_Save failed: 0x%08x\n", hr);
+
+ IStream_Release(stream);
+
+ /* Hashing */
+ hr = IMoniker_Hash(moniker, &hash);
+ ok(hr == S_OK, "IMoniker_Hash failed: 0x%08x\n", hr);
+ ok(hash == PtrToUlong(&factory.IClassFactory_iface), "Unexpected hash value %#x\n", hash);
+
+ /* IsSystemMoniker test */
+ TEST_MONIKER_TYPE(moniker, MKSYS_OBJREFMONIKER);
+
+ hr = IMoniker_Inverse(moniker, &inverse);
+todo_wine
+ ok(hr == S_OK, "Failed to get inverse, hr %#x\n", hr);
+if (hr == S_OK)
+{
+ TEST_MONIKER_TYPE(inverse, MKSYS_ANTIMONIKER);
+ IMoniker_Release(inverse);
+}
+
+ hr = CreateBindCtx(0, &bindctx);
+ ok(hr == S_OK, "CreateBindCtx failed: 0x%08x\n", hr);
+
+ /* IsRunning test */
+ hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
+todo_wine
+ ok(hr == S_OK, "IMoniker_IsRunning should return S_OK, not 0x%08x\n", hr);
+
+ hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
+ ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08x\n", hr);
+
+ hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
+todo_wine
+ ok(hr == S_OK, "IMoniker_BindToObject failed: 0x%08x\n", hr);
+if (hr == S_OK)
+ IUnknown_Release(unknown);
+
+ hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
+todo_wine
+ ok(hr == S_OK, "IMoniker_BindToObject failed: 0x%08x\n", hr);
+if (hr == S_OK)
+ IUnknown_Release(unknown);
+
+ IMoniker_Release(moniker);
+
+todo_wine
+ ok(factory.refcount > 1, "Unexpected factory refcount %u\n", factory.refcount);
+
+ hr = CreateObjrefMoniker(NULL, &moniker);
+ ok(hr == S_OK, "CreateObjrefMoniker failed, hr %#x\n", hr);
+
+ hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
+todo_wine
+ ok(hr == E_UNEXPECTED, "IMoniker_BindToObject should have returned E_UNEXPECTED instead of 0x%08x\n", hr);
+
+ hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
+todo_wine
+ ok(hr == E_UNEXPECTED, "IMoniker_BindToStorage should have returned E_UNEXPECTED instead of 0x%08x\n", hr);
+
+ IBindCtx_Release(bindctx);
+
+ /* Enum() */
+ enummoniker = (void *)0xdeadbeef;
+ hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
+ ok(hr == S_OK, "Unexpected hr %#x\n", hr);
+ ok(enummoniker == NULL, "got %p\n", enummoniker);
+
+ enummoniker = (void *)0xdeadbeef;
+ hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
+ ok(hr == S_OK, "Unexpected hr %#x\n", hr);
+ ok(enummoniker == NULL, "got %p\n", enummoniker);
+
+ IMoniker_Release(moniker);
+
+ /* CommonPrefixWith() */
+ hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker);
+ ok(hr == S_OK, "CreateObjrefMoniker failed: hr %#x\n", hr);
+
+ hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker2);
+ ok(hr == S_OK, "CreateObjrefMoniker failed: hr %#x\n", hr);
+
+ hr = IMoniker_IsEqual(moniker, NULL);
+todo_wine
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_IsEqual(moniker, moniker2);
+todo_wine
+ ok(hr == S_OK, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_CommonPrefixWith(moniker, moniker2, NULL);
+todo_wine
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_CommonPrefixWith(moniker, NULL, &prefix);
+todo_wine
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_CommonPrefixWith(moniker, moniker2, &prefix);
+todo_wine
+ ok(hr == MK_S_US, "Unexpected hr %#x\n", hr);
+if (hr == S_OK)
+{
+ ok(prefix == moniker, "Unexpected pointer\n");
+ IMoniker_Release(prefix);
+}
+
+ IMoniker_Release(moniker2);
+
+ hr = CreateObjrefMoniker((IUnknown *)moniker, &moniker2);
+ ok(hr == S_OK, "Failed to create moniker, hr %#x\n", hr);
+
+ hr = IMoniker_IsEqual(moniker, moniker2);
+todo_wine
+ ok(hr == S_FALSE, "Unexpected hr %#x\n", hr);
+
+ hr = IMoniker_CommonPrefixWith(moniker, moniker2, &prefix);
+todo_wine
+ ok(hr == MK_E_NOPREFIX, "Unexpected hr %#x\n", hr);
+
+ IMoniker_Release(moniker2);
+
+ /* ComposeWith() */
+
+ /* P + A -> () */
+ anti = create_antimoniker(1);
+ hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
+todo_wine
+ ok(hr == S_OK, "Failed to compose, hr %#x\n", hr);
+if (hr == S_OK)
+ ok(!moniker2, "Unexpected pointer\n");
+ IMoniker_Release(anti);
+
+ /* P + A2 -> A */
+ anti = create_antimoniker(2);
+ hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
+todo_wine
+ ok(hr == S_OK, "Failed to compose, hr %#x\n", hr);
+if (hr == S_OK)
+{
+ TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
+ IMoniker_Release(moniker2);
+}
+
+ IMoniker_Release(anti);
+
+ IMoniker_Release(moniker);
+}
+
static void test_bind_context(void)
{
IRunningObjectTable *rot, *rot2;
@@ -4385,6 +4629,7 @@ START_TEST(moniker)
test_anti_moniker();
test_generic_composite_moniker();
test_pointer_moniker();
+ test_objref_moniker();
test_save_load_filemoniker();
test_MonikerCommonPrefixWith();
diff --git a/include/objidl.idl b/include/objidl.idl
index 7576a686aeb..cd11729b292 100644
--- a/include/objidl.idl
+++ b/include/objidl.idl
@@ -330,7 +330,10 @@ interface IMoniker : IPersistStream
MKSYS_ITEMMONIKER = 4,
MKSYS_POINTERMONIKER = 5,
/* MKSYS_URLMONIKER = 6, */ /* defined in urlmon.idl */
- MKSYS_CLASSMONIKER = 7
+ MKSYS_CLASSMONIKER = 7,
+ MKSYS_OBJREFMONIKER = 8,
+ MKSYS_SESSIONMONIKER = 9,
+ MKSYS_LUAMONIKER = 10
} MKSYS;
typedef [v1_enum] enum tagMKREDUCE {
--
2.31.1
1
1
[PATCH vkd3d v3 1/6] vkd3d-shader/hlsl: Introduce a helper for getting numeric types.
by Giovanni Mascellani 10 Nov '21
by Giovanni Mascellani 10 Nov '21
10 Nov '21
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
Signed-off-by: Matteo Bruni <mbruni(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl.c | 4 ++--
libs/vkd3d-shader/hlsl.h | 28 ++++++++++++++++++++++++++++
libs/vkd3d-shader/hlsl.y | 28 ++++++++++++----------------
3 files changed, 42 insertions(+), 18 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index 9bce6beb..8a56025d 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -560,7 +560,7 @@ struct hlsl_ir_constant *hlsl_new_uint_constant(struct hlsl_ctx *ctx, unsigned i
if (!(c = hlsl_alloc(ctx, sizeof(*c))))
return NULL;
- init_node(&c->node, HLSL_IR_CONSTANT, ctx->builtin_types.scalar[HLSL_TYPE_UINT], loc);
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc);
c->value[0].u = n;
return c;
}
@@ -650,7 +650,7 @@ struct hlsl_ir_swizzle *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned
if (!(swizzle = hlsl_alloc(ctx, sizeof(*swizzle))))
return NULL;
init_node(&swizzle->node, HLSL_IR_SWIZZLE,
- ctx->builtin_types.vector[val->data_type->base_type][components - 1], *loc);
+ hlsl_get_vector_type(ctx, val->data_type->base_type, components), *loc);
hlsl_src_from_node(&swizzle->val, val);
swizzle->swizzle = s;
return swizzle;
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index e401971e..31b7ddbb 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -629,6 +629,34 @@ static inline void hlsl_release_string_buffer(struct hlsl_ctx *ctx, struct vkd3d
vkd3d_string_buffer_release(&ctx->string_buffers, buffer);
}
+static inline struct hlsl_type *hlsl_get_scalar_type(const struct hlsl_ctx *ctx, enum hlsl_base_type base_type)
+{
+ return ctx->builtin_types.scalar[base_type];
+}
+
+static inline struct hlsl_type *hlsl_get_vector_type(const struct hlsl_ctx *ctx, enum hlsl_base_type base_type,
+ unsigned int dimx)
+{
+ return ctx->builtin_types.vector[base_type][dimx - 1];
+}
+
+static inline struct hlsl_type *hlsl_get_matrix_type(const struct hlsl_ctx *ctx, enum hlsl_base_type base_type,
+ unsigned int dimx, unsigned int dimy)
+{
+ return ctx->builtin_types.matrix[base_type][dimx - 1][dimy - 1];
+}
+
+static inline struct hlsl_type *hlsl_get_numeric_type(const struct hlsl_ctx *ctx, enum hlsl_type_class type,
+ enum hlsl_base_type base_type, unsigned int dimx, unsigned int dimy)
+{
+ if (type == HLSL_CLASS_SCALAR)
+ return hlsl_get_scalar_type(ctx, base_type);
+ else if (type == HLSL_CLASS_VECTOR)
+ return hlsl_get_vector_type(ctx, base_type, dimx);
+ else
+ return hlsl_get_matrix_type(ctx, base_type, dimx, dimy);
+}
+
const char *debug_hlsl_expr_op(enum hlsl_ir_expr_op op);
const char *debug_hlsl_type(struct hlsl_ctx *ctx, const struct hlsl_type *type);
const char *debug_hlsl_writemask(unsigned int writemask);
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index ae19cd1a..61789def 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -1021,11 +1021,7 @@ static struct hlsl_type *expr_common_type(struct hlsl_ctx *ctx, struct hlsl_type
}
}
- if (type == HLSL_CLASS_SCALAR)
- return ctx->builtin_types.scalar[base];
- if (type == HLSL_CLASS_VECTOR)
- return ctx->builtin_types.vector[base][dimx - 1];
- return ctx->builtin_types.matrix[base][dimx - 1][dimy - 1];
+ return hlsl_get_numeric_type(ctx, type, base, dimx, dimy);
}
static struct hlsl_ir_expr *add_expr(struct hlsl_ctx *ctx, struct list *instrs, enum hlsl_ir_expr_op op,
@@ -1761,7 +1757,7 @@ static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type
}
if (!(arg = add_implicit_conversion(ctx, params->instrs, arg,
- ctx->builtin_types.vector[type->base_type][width - 1], &arg->loc)))
+ hlsl_get_vector_type(ctx, type->base_type, width), &arg->loc)))
continue;
if (!(store = hlsl_new_store(ctx, var, NULL, arg,
@@ -1816,9 +1812,9 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl
if (params->args_count >= 2)
FIXME("Ignoring index and/or offset parameter(s).\n");
- /* -1 for zero-indexing; +1 for the mipmap level */
+ /* +1 for the mipmap level */
if (!(coords = add_implicit_conversion(ctx, instrs, params->args[0],
- ctx->builtin_types.vector[HLSL_TYPE_INT][sampler_dim - 1 + 1], loc)))
+ hlsl_get_vector_type(ctx, HLSL_TYPE_INT, sampler_dim + 1), loc)))
return false;
if (!(load = hlsl_new_resource_load(ctx, object_type->e.resource_format, HLSL_RESOURCE_LOAD,
@@ -2500,7 +2496,7 @@ type:
YYABORT;
}
- $$ = ctx->builtin_types.vector[$3->base_type][$5 - 1];
+ $$ = hlsl_get_vector_type(ctx, $3->base_type, $5);
}
| KW_MATRIX '<' type ',' C_INTEGER ',' C_INTEGER '>'
{
@@ -2528,7 +2524,7 @@ type:
YYABORT;
}
- $$ = ctx->builtin_types.matrix[$3->base_type][$7 - 1][$5 - 1];
+ $$ = hlsl_get_matrix_type(ctx, $3->base_type, $7, $5);
}
| KW_VOID
{
@@ -2560,7 +2556,7 @@ type:
}
| texture_type
{
- $$ = hlsl_new_texture_type(ctx, $1, ctx->builtin_types.vector[HLSL_TYPE_FLOAT][4 - 1]);
+ $$ = hlsl_new_texture_type(ctx, $1, hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4));
}
| texture_type '<' type '>'
{
@@ -2971,7 +2967,7 @@ primary_expr:
if (!(c = hlsl_alloc(ctx, sizeof(*c))))
YYABORT;
- init_node(&c->node, HLSL_IR_CONSTANT, ctx->builtin_types.scalar[HLSL_TYPE_FLOAT], @1);
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_get_scalar_type(ctx, HLSL_TYPE_FLOAT), @1);
c->value[0].f = $1;
if (!($$ = make_list(ctx, &c->node)))
YYABORT;
@@ -2982,7 +2978,7 @@ primary_expr:
if (!(c = hlsl_alloc(ctx, sizeof(*c))))
YYABORT;
- init_node(&c->node, HLSL_IR_CONSTANT, ctx->builtin_types.scalar[HLSL_TYPE_INT], @1);
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_get_scalar_type(ctx, HLSL_TYPE_INT), @1);
c->value[0].i = $1;
if (!($$ = make_list(ctx, &c->node)))
YYABORT;
@@ -2993,7 +2989,7 @@ primary_expr:
if (!(c = hlsl_alloc(ctx, sizeof(*c))))
YYABORT;
- init_node(&c->node, HLSL_IR_CONSTANT, ctx->builtin_types.scalar[HLSL_TYPE_BOOL], @1);
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_get_scalar_type(ctx, HLSL_TYPE_BOOL), @1);
c->value[0].b = $1;
if (!($$ = make_list(ctx, &c->node)))
YYABORT;
@@ -3030,7 +3026,7 @@ primary_expr:
struct hlsl_ir_var *var;
if (!(var = hlsl_new_synthetic_var(ctx, "<state-block-expr>",
- ctx->builtin_types.scalar[HLSL_TYPE_INT], @1)))
+ hlsl_get_scalar_type(ctx, HLSL_TYPE_INT), @1)))
YYABORT;
if (!(load = hlsl_new_var_load(ctx, var, @1)))
YYABORT;
@@ -3116,7 +3112,7 @@ postfix_expr:
YYABORT;
}
- if (!(cast = hlsl_new_cast(ctx, index, ctx->builtin_types.scalar[HLSL_TYPE_UINT], &index->loc)))
+ if (!(cast = hlsl_new_cast(ctx, index, hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), &index->loc)))
{
destroy_instr_list($1);
YYABORT;
--
2.33.0
4
13
08 Nov '21
Planet Coaster adds this attribute to its media type when loading user
music in some of the supported formats, and missing it will make media
type matching only partially succeed.
This will also be useful for WMA/XMA compressed formats.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
dlls/winegstreamer/mfplat.c | 10 ++++++++--
dlls/winegstreamer/unixlib.h | 1 +
dlls/winegstreamer/wg_parser.c | 8 +++++++-
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 58200dc409a..340cb92e87a 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -547,8 +547,8 @@ static inline UINT64 make_uint64(UINT32 high, UINT32 low)
static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format *format)
{
+ unsigned int i, block_alignment;
IMFMediaType *type;
- unsigned int i;
for (i = 0; i < ARRAY_SIZE(audio_formats); ++i)
{
@@ -564,6 +564,8 @@ static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format *
IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, format->u.audio.channels);
IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask);
IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ block_alignment = format->u.audio.channels * audio_formats[i].depth / 8;
+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment);
return type;
}
@@ -621,7 +623,7 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format)
static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_format *format)
{
- UINT32 rate, channels, channel_mask, depth;
+ UINT32 rate, channels, channel_mask, depth, block_alignment;
unsigned int i;
GUID subtype;
@@ -658,10 +660,14 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma
}
}
+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
+ block_alignment = 0;
+
format->major_type = WG_MAJOR_TYPE_AUDIO;
format->u.audio.channels = channels;
format->u.audio.channel_mask = channel_mask;
format->u.audio.rate = rate;
+ format->u.audio.block_alignment = block_alignment;
for (i = 0; i < ARRAY_SIZE(audio_formats); ++i)
{
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index 90101893541..9a98e97e7d7 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -87,6 +87,7 @@ struct wg_format
uint32_t channels;
uint32_t channel_mask; /* In WinMM format. */
uint32_t rate;
+ uint32_t block_alignment;
} audio;
} u;
};
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index c3c9051a174..3b341dad9eb 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -411,13 +411,19 @@ static GstCaps *wg_format_to_caps_audio(const struct wg_format *format)
GstAudioChannelPosition positions[32];
GstAudioFormat audio_format;
GstAudioInfo info;
+ GstCaps *caps;
if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN)
return NULL;
wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels);
gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions);
- return gst_audio_info_to_caps(&info);
+ caps = gst_audio_info_to_caps(&info);
+
+ if (format->u.audio.block_alignment)
+ gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.audio.block_alignment, NULL);
+
+ return caps;
}
static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format)
--
2.33.0
3
10
[PATCH v5 1/2] nsiproxy: Fill the reply with exact ICMP_ECHO_REPLY in the output buffer.
by Gabriel Ivăncescu 08 Nov '21
by Gabriel Ivăncescu 08 Nov '21
08 Nov '21
Because iphlpapi has no opportunity to convert the reply in async mode.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/iphlpapi/iphlpapi_main.c | 44 +-----
dlls/nsiproxy.sys/device.c | 36 ++++-
dlls/nsiproxy.sys/icmp_echo.c | 203 ++++++++++++++++++---------
dlls/nsiproxy.sys/nsiproxy_private.h | 39 +++++
include/wine/nsi.h | 21 +--
5 files changed, 212 insertions(+), 131 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index d9a85be..8a31241 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -4579,33 +4579,6 @@ DWORD WINAPI IcmpParseReplies( void *reply, DWORD reply_size )
return num_pkts;
}
-/*************************************************************************
- * icmpv4_echo_reply_fixup
- *
- * Convert struct nsiproxy_icmpv4_echo_reply into ICMP_ECHO_REPLY.
- *
- * This is necessary due to the different sizes of ICMP_ECHO_REPLY on
- * 32 and 64-bits. Despite mention of ICMP_ECHO_REPLY32, 64-bit Windows
- * actually does return a full 64-bit version.
- */
-static void icmpv4_echo_reply_fixup( ICMP_ECHO_REPLY *dst, struct nsiproxy_icmp_echo_reply *reply )
-{
- dst->Address = reply->addr.Ipv4.sin_addr.s_addr;
- dst->Status = reply->status;
- dst->RoundTripTime = reply->round_trip_time;
- dst->DataSize = reply->data_size;
- dst->Reserved = reply->num_of_pkts;
- dst->Data = (BYTE *)(dst + 1) + ((reply->opts.options_size + 3) & ~3);
- dst->Options.Ttl = reply->opts.ttl;
- dst->Options.Tos = reply->opts.tos;
- dst->Options.Flags = reply->opts.flags;
- dst->Options.OptionsSize = reply->opts.options_size;
- dst->Options.OptionsData = (BYTE *)(reply + 1);
-
- memcpy( dst->Options.OptionsData, (BYTE *)reply + reply->opts.options_offset, reply->opts.options_size );
- memcpy( dst->Data, (BYTE *)reply + reply->data_offset, reply->data_size );
-}
-
/***********************************************************************
* IcmpSendEcho (IPHLPAPI.@)
*/
@@ -4636,9 +4609,8 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
void *reply, DWORD reply_size, DWORD timeout )
{
struct icmp_handle_data *data = (struct icmp_handle_data *)handle;
- DWORD opt_size, in_size, ret = 0, out_size;
+ DWORD opt_size, in_size, ret = 0;
struct nsiproxy_icmp_echo *in;
- struct nsiproxy_icmp_echo_reply *out;
HANDLE request_event;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
@@ -4658,17 +4630,15 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
opt_size = opts ? (opts->OptionsSize + 3) & ~3 : 0;
in_size = FIELD_OFFSET(struct nsiproxy_icmp_echo, data[opt_size + request_size]);
in = heap_alloc_zero( in_size );
- out_size = reply_size - sizeof(ICMP_ECHO_REPLY) + sizeof(*out);
- out = heap_alloc( out_size );
- if (!in || !out)
+ if (!in)
{
- heap_free( out );
- heap_free( in );
SetLastError( IP_NO_RESOURCES );
return 0;
}
+ in->user_reply_ptr = (ULONG_PTR)reply;
+ in->bits = sizeof(void*) * 8;
in->src.Ipv4.sin_family = AF_INET;
in->src.Ipv4.sin_addr.s_addr = src;
in->dst.Ipv4.sin_family = AF_INET;
@@ -4689,19 +4659,15 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r
status = NtDeviceIoControlFile( data->nsi_device, request_event, NULL, NULL,
&iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, in, in_size,
- out, out_size );
+ reply, reply_size );
if (status == STATUS_PENDING && !WaitForSingleObject( request_event, INFINITE ))
status = iosb.Status;
if (!status)
- {
- icmpv4_echo_reply_fixup( reply, out );
ret = IcmpParseReplies( reply, reply_size );
- }
CloseHandle( request_event );
- heap_free( out );
heap_free( in );
if (status) SetLastError( RtlNtStatusToDosError( status ) );
diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c
index 90a7a3d..4ace66d 100644
--- a/dlls/nsiproxy.sys/device.c
+++ b/dlls/nsiproxy.sys/device.c
@@ -31,6 +31,7 @@
#include "netiodef.h"
#include "wine/nsi.h"
#include "wine/debug.h"
+#include "wine/heap.h"
#include "wine/unixlib.h"
#include "nsiproxy_private.h"
@@ -211,6 +212,13 @@ static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp )
LeaveCriticalSection( &nsiproxy_cs );
}
+static int icmp_echo_reply_struct_len( ULONG family, ULONG bits )
+{
+ if (family == AF_INET)
+ return (bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64);
+ return 0;
+}
+
static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
{
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
@@ -222,7 +230,7 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp )
if (in_len < offsetof(struct nsiproxy_icmp_echo, data[0]) ||
in_len < offsetof(struct nsiproxy_icmp_echo, data[((in->opt_size + 3) & ~3) + in->req_size]) ||
- out_len < sizeof(struct nsiproxy_icmp_echo_reply))
+ out_len < icmp_echo_reply_struct_len( in->dst.si_family, in->bits ))
return STATUS_INVALID_PARAMETER;
switch (in->dst.si_family)
@@ -326,8 +334,10 @@ static DWORD WINAPI listen_thread_proc( void *arg )
TRACE( "\n" );
+ params.user_reply_ptr = in->user_reply_ptr;
params.handle = irp_get_icmp_handle( irp );
params.timeout = in->timeout;
+ params.bits = in->bits;
params.reply = irp->AssociatedIrp.SystemBuffer;
params.reply_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
@@ -353,8 +363,10 @@ static DWORD WINAPI listen_thread_proc( void *arg )
static void handle_queued_send_echo( IRP *irp )
{
struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer;
- struct nsiproxy_icmp_echo_reply *reply = (struct nsiproxy_icmp_echo_reply *)irp->AssociatedIrp.SystemBuffer;
+ void *out = irp->AssociatedIrp.SystemBuffer;
struct icmp_send_echo_params params;
+ ULONG family = in->dst.si_family;
+ ULONG bits = in->bits;
NTSTATUS status;
TRACE( "\n" );
@@ -372,9 +384,23 @@ static void handle_queued_send_echo( IRP *irp )
irp->IoStatus.Status = status;
if (status == STATUS_SUCCESS)
{
- memset( reply, 0, sizeof(*reply) );
- reply->status = params.ip_status;
- irp->IoStatus.Information = sizeof(*reply);
+ if (family == AF_INET)
+ {
+ if (bits == 32)
+ {
+ struct icmp_echo_reply_32 *reply = out;
+ memset( reply, 0, sizeof(*reply) );
+ reply->status = params.ip_status;
+ irp->IoStatus.Information = sizeof(*reply);
+ }
+ else
+ {
+ struct icmp_echo_reply_64 *reply = out;
+ memset( reply, 0, sizeof(*reply) );
+ reply->status = params.ip_status;
+ irp->IoStatus.Information = sizeof(*reply);
+ }
+ }
}
IoCompleteRequest( irp, IO_NO_INCREMENT );
}
diff --git a/dlls/nsiproxy.sys/icmp_echo.c b/dlls/nsiproxy.sys/icmp_echo.c
index 955fdfd..1e106c6 100644
--- a/dlls/nsiproxy.sys/icmp_echo.c
+++ b/dlls/nsiproxy.sys/icmp_echo.c
@@ -93,6 +93,20 @@ struct icmp_hdr
} un;
};
+struct icmp_reply_ctx
+{
+ SOCKADDR_INET addr;
+ ULONG status;
+ ULONG round_trip_time;
+ LONG data_size;
+ BYTE ttl;
+ BYTE tos;
+ BYTE flags;
+ BYTE options_size;
+ void *options_data;
+ void *data;
+};
+
struct family_ops;
struct icmp_data
{
@@ -232,20 +246,22 @@ static void ipv4_linux_ping_set_socket_opts( struct icmp_data *data, struct icmp
}
#endif
-static int ipv4_reply_buffer_len( int reply_len )
+static int ipv4_reply_buffer_len( struct icmp_listen_params *params )
{
- return sizeof(struct ip_hdr) + sizeof(struct icmp_hdr) + reply_len - sizeof(struct nsiproxy_icmp_echo_reply);
+ int struct_len = (params->bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64);
+ return sizeof(struct ip_hdr) + sizeof(struct icmp_hdr) + params->reply_len - struct_len;
}
#ifdef __linux__
-static int ipv4_linux_ping_reply_buffer_len( int reply_len )
+static int ipv4_linux_ping_reply_buffer_len( struct icmp_listen_params *params )
{
- return sizeof(struct icmp_hdr) + reply_len - sizeof(struct nsiproxy_icmp_echo_reply);
+ int struct_len = (params->bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64);
+ return sizeof(struct icmp_hdr) + params->reply_len - struct_len;
}
#endif
-static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd,
- int *ip_hdr_len, struct nsiproxy_icmp_echo_reply *reply, void **opts )
+static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+ struct icmp_reply_ctx *ctx )
{
struct ip_hdr *ip_hdr;
@@ -254,27 +270,27 @@ static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd,
if (ip_hdr->v_hl >> 4 != 4 || ip_hdr->protocol != IPPROTO_ICMP) return FALSE;
*ip_hdr_len = (ip_hdr->v_hl & 0xf) << 2;
if (*ip_hdr_len < sizeof(*ip_hdr)) return FALSE;
- *opts = ip_hdr + 1;
- reply->opts.ttl = ip_hdr->ttl;
- reply->opts.tos = ip_hdr->tos;
- reply->opts.flags = ip_hdr->frag_off >> 13;
- reply->opts.options_size = *ip_hdr_len - sizeof(*ip_hdr);
+ ctx->options_data = ip_hdr + 1;
+ ctx->ttl = ip_hdr->ttl;
+ ctx->tos = ip_hdr->tos;
+ ctx->flags = ip_hdr->frag_off >> 13;
+ ctx->options_size = *ip_hdr_len - sizeof(*ip_hdr);
return TRUE;
}
#ifdef __linux__
-static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd,
- int *ip_hdr_len, struct nsiproxy_icmp_echo_reply *reply, void **opts )
+static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+ struct icmp_reply_ctx *ctx )
{
struct cmsghdr *cmsg;
*ip_hdr_len = 0;
- *opts = NULL;
- reply->opts.ttl = 0;
- reply->opts.tos = 0;
- reply->opts.flags = 0;
- reply->opts.options_size = 0; /* FIXME from IP_OPTIONS but will require checking for space in the reply */
+ ctx->options_data = NULL;
+ ctx->ttl = 0;
+ ctx->tos = 0;
+ ctx->flags = 0;
+ ctx->options_size = 0; /* FIXME from IP_OPTIONS but will require checking for space in the reply */
for (cmsg = CMSG_FIRSTHDR( msg ); cmsg; cmsg = CMSG_NXTHDR( msg, cmsg ))
{
@@ -282,10 +298,10 @@ static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd,
switch (cmsg->cmsg_type)
{
case IP_TTL:
- reply->opts.ttl = *(BYTE *)CMSG_DATA( cmsg );
+ ctx->ttl = *(BYTE *)CMSG_DATA( cmsg );
break;
case IP_TOS:
- reply->opts.tos = *(BYTE *)CMSG_DATA( cmsg );
+ ctx->tos = *(BYTE *)CMSG_DATA( cmsg );
break;
}
}
@@ -294,7 +310,7 @@ static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd,
#endif
static int ipv4_parse_icmp_hdr_( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
- struct nsiproxy_icmp_echo_reply *reply, int ping_socket )
+ struct icmp_reply_ctx *ctx, int ping_socket )
{
static const IP_STATUS unreach_codes[] =
{
@@ -326,7 +342,7 @@ static int ipv4_parse_icmp_hdr_( struct icmp_data *data, struct icmp_hdr *icmp,
if ((!ping_socket && icmp->un.echo.id != data->id) ||
icmp->un.echo.sequence != data->seq) return -1;
- reply->status = IP_SUCCESS;
+ ctx->status = IP_SUCCESS;
return icmp_size - sizeof(*icmp);
case ICMP4_DST_UNREACH:
@@ -369,24 +385,90 @@ static int ipv4_parse_icmp_hdr_( struct icmp_data *data, struct icmp_hdr *icmp,
(!ping_socket && orig_icmp_hdr->un.echo.id != data->id) ||
orig_icmp_hdr->un.echo.sequence != data->seq) return -1;
- reply->status = status;
+ ctx->status = status;
return 0;
}
-static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
- struct nsiproxy_icmp_echo_reply *reply )
+static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
+ int icmp_size, struct icmp_reply_ctx *ctx)
{
- return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, reply, 0 );
+ return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, ctx, 0 );
}
#ifdef __linux__
-static int ipv4_linux_ping_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
- struct nsiproxy_icmp_echo_reply *reply )
+static int ipv4_linux_ping_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
+ int icmp_size, struct icmp_reply_ctx *ctx )
{
- return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, reply, 1 );
+ return ipv4_parse_icmp_hdr_( data, icmp, icmp_size, ctx, 1 );
}
#endif
+static NTSTATUS ipv4_set_reply_ip_status( struct icmp_listen_params *params, IP_STATUS ip_status )
+{
+ if (params->bits == 32)
+ {
+ struct icmp_echo_reply_32 *reply = params->reply;
+ memset( reply, 0, sizeof(*reply) );
+ reply->status = ip_status;
+ params->reply_len = sizeof(*reply);
+ }
+ else
+ {
+ struct icmp_echo_reply_64 *reply = params->reply;
+ memset( reply, 0, sizeof(*reply) );
+ reply->status = ip_status;
+ params->reply_len = sizeof(*reply);
+ }
+ return STATUS_SUCCESS;
+}
+
+static void ipv4_fill_reply( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx)
+{
+ void *options_data;
+ ULONG data_offset;
+ if (params->bits == 32)
+ {
+ struct icmp_echo_reply_32 *reply = params->reply;
+ data_offset = sizeof(*reply) + ((ctx->options_size + 3) & ~3);
+ reply->addr = ctx->addr.Ipv4.sin_addr.WS_s_addr;
+ reply->status = ctx->status;
+ reply->round_trip_time = ctx->round_trip_time;
+ reply->data_size = ctx->data_size;
+ reply->num_of_pkts = 1;
+ reply->data_ptr = params->user_reply_ptr + data_offset;
+ reply->opts.ttl = ctx->ttl;
+ reply->opts.tos = ctx->tos;
+ reply->opts.flags = ctx->flags;
+ reply->opts.options_size = ctx->options_size;
+ reply->opts.options_ptr = params->user_reply_ptr + sizeof(*reply);
+ options_data = reply + 1;
+ }
+ else
+ {
+ struct icmp_echo_reply_64 *reply = params->reply;
+ data_offset = sizeof(*reply) + ((ctx->options_size + 3) & ~3);
+ reply->addr = ctx->addr.Ipv4.sin_addr.WS_s_addr;
+ reply->status = ctx->status;
+ reply->round_trip_time = ctx->round_trip_time;
+ reply->data_size = ctx->data_size;
+ reply->num_of_pkts = 1;
+ reply->data_ptr = params->user_reply_ptr + data_offset;
+ reply->opts.ttl = ctx->ttl;
+ reply->opts.tos = ctx->tos;
+ reply->opts.flags = ctx->flags;
+ reply->opts.options_size = ctx->options_size;
+ reply->opts.options_ptr = params->user_reply_ptr + sizeof(*reply);
+ options_data = reply + 1;
+ }
+
+ memcpy( options_data, ctx->options_data, ctx->options_size );
+ if (ctx->options_size & 3)
+ memset( (char *)options_data + ctx->options_size, 0, 4 - (ctx->options_size & 3) );
+
+ memcpy( (char *)params->reply + data_offset, ctx->data, ctx->data_size );
+ params->reply_len = data_offset + ctx->data_size;
+}
+
struct family_ops
{
int family;
@@ -394,11 +476,11 @@ struct family_ops
void (*init_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp_hdr );
unsigned short (*chksum)( BYTE *data, unsigned int count );
void (*set_socket_opts)( struct icmp_data *data, struct icmp_send_echo_params *params );
- int (*reply_buffer_len)( int reply_len );
- BOOL (*parse_ip_hdr)( struct msghdr *msg, int recvd,
- int *ip_hdr_len, struct nsiproxy_icmp_echo_reply *reply, void **opts );
- int (*parse_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_len,
- struct nsiproxy_icmp_echo_reply *reply );
+ int (*reply_buffer_len)( struct icmp_listen_params *params );
+ BOOL (*parse_ip_hdr)( struct msghdr *msg, int recvd, int *ip_hdr_len, struct icmp_reply_ctx *ctx );
+ int (*parse_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_len, struct icmp_reply_ctx *ctx );
+ NTSTATUS (*set_reply_ip_status)( struct icmp_listen_params *params, IP_STATUS ip_status );
+ void (*fill_reply)( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx );
};
static const struct family_ops ipv4 =
@@ -411,6 +493,8 @@ static const struct family_ops ipv4 =
ipv4_reply_buffer_len,
ipv4_parse_ip_hdr,
ipv4_parse_icmp_hdr,
+ ipv4_set_reply_ip_status,
+ ipv4_fill_reply,
};
#ifdef __linux__
@@ -425,6 +509,8 @@ static const struct family_ops ipv4_linux_ping =
ipv4_linux_ping_reply_buffer_len,
ipv4_linux_ping_parse_ip_hdr,
ipv4_linux_ping_parse_icmp_hdr,
+ ipv4_set_reply_ip_status,
+ ipv4_fill_reply,
};
#endif
@@ -584,16 +670,6 @@ NTSTATUS icmp_send_echo( void *args )
return params->handle ? STATUS_PENDING : STATUS_NO_MEMORY;
}
-static NTSTATUS set_reply_ip_status( struct icmp_listen_params *params, IP_STATUS ip_status )
-{
- struct nsiproxy_icmp_echo_reply *reply = params->reply;
-
- memset( reply, 0, sizeof(*reply) );
- reply->status = ip_status;
- params->reply_len = sizeof(*reply);
- return STATUS_SUCCESS;
-}
-
static int get_timeout( LARGE_INTEGER start, DWORD timeout )
{
LARGE_INTEGER now, end;
@@ -615,19 +691,18 @@ static ULONG get_rtt( LARGE_INTEGER start )
static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *params )
{
- struct nsiproxy_icmp_echo_reply *reply = (struct nsiproxy_icmp_echo_reply *)params->reply;
struct sockaddr_storage addr;
+ struct icmp_reply_ctx ctx;
struct iovec iov[1];
BYTE cmsg_buf[1024];
struct msghdr msg = { .msg_name = &addr, .msg_namelen = sizeof(addr),
.msg_iov = iov, .msg_iovlen = ARRAY_SIZE(iov),
.msg_control = cmsg_buf, .msg_controllen = sizeof(cmsg_buf) };
- int ip_hdr_len, recvd, reply_buf_len, data_size;
+ int ip_hdr_len, recvd, reply_buf_len;
char *reply_buf;
- void *opts;
struct icmp_hdr *icmp_hdr;
- reply_buf_len = data->ops->reply_buffer_len( params->reply_len );
+ reply_buf_len = data->ops->reply_buffer_len( params );
reply_buf = malloc( reply_buf_len );
if (!reply_buf) return STATUS_NO_MEMORY;
@@ -638,31 +713,23 @@ static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *par
TRACE( "recvmsg() rets %d errno %d addr_len %d iovlen %d msg_flags %x\n",
recvd, errno, msg.msg_namelen, (int)iov[0].iov_len, msg.msg_flags );
- if (!data->ops->parse_ip_hdr( &msg, recvd, &ip_hdr_len, reply, &opts )) goto skip;
+ if (!data->ops->parse_ip_hdr( &msg, recvd, &ip_hdr_len, &ctx )) goto skip;
if (recvd < ip_hdr_len + sizeof(*icmp_hdr)) goto skip;
icmp_hdr = (struct icmp_hdr *)(reply_buf + ip_hdr_len);
- if ((data_size = data->ops->parse_icmp_hdr( data, icmp_hdr, recvd - ip_hdr_len, reply )) < 0) goto skip;
- reply->data_size = data_size;
- if (reply->data_size && msg.msg_flags & MSG_TRUNC)
+ if ((ctx.data_size = data->ops->parse_icmp_hdr( data, icmp_hdr, recvd - ip_hdr_len, &ctx )) < 0) goto skip;
+ if (ctx.data_size && msg.msg_flags & MSG_TRUNC)
{
free( reply_buf );
- return set_reply_ip_status( params, IP_GENERAL_FAILURE );
+ return data->ops->set_reply_ip_status( params, IP_GENERAL_FAILURE );
}
- sockaddr_to_SOCKADDR_INET( (struct sockaddr *)&addr, &reply->addr );
- reply->round_trip_time = get_rtt( data->send_time );
- reply->num_of_pkts = 1;
- reply->opts.options_offset = sizeof(*reply);
- reply->data_offset = sizeof(*reply) + ((reply->opts.options_size + 3) & ~3);
- if (reply->opts.options_size)
- memcpy( (char *)reply + reply->opts.options_offset, opts, reply->opts.options_size );
- if (reply->opts.options_size & 3)
- memset( (char *)reply + reply->opts.options_offset + reply->opts.options_size, 0, 4 - (reply->opts.options_size & 3) );
- if (reply->data_size)
- memcpy( (char *)reply + reply->data_offset, icmp_hdr + 1, reply->data_size );
-
- params->reply_len = reply->data_offset + reply->data_size;
+ sockaddr_to_SOCKADDR_INET( (struct sockaddr *)&addr, &ctx.addr );
+ ctx.round_trip_time = get_rtt( data->send_time );
+ ctx.data = icmp_hdr + 1;
+
+ data->ops->fill_reply( params, &ctx );
+
free( reply_buf );
return STATUS_SUCCESS;
@@ -703,10 +770,10 @@ NTSTATUS icmp_listen( void *args )
if (!ret) /* timeout */
{
TRACE( "timeout\n" );
- return set_reply_ip_status( params, IP_REQ_TIMED_OUT );
+ return data->ops->set_reply_ip_status( params, IP_REQ_TIMED_OUT );
}
/* ret < 0 */
- return set_reply_ip_status( params, errno_to_ip_status( errno ) );
+ return data->ops->set_reply_ip_status( params, errno_to_ip_status( errno ) );
}
NTSTATUS icmp_cancel_listen( void *args )
diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h
index 91dd393..c0b8ca0 100644
--- a/dlls/nsiproxy.sys/nsiproxy_private.h
+++ b/dlls/nsiproxy.sys/nsiproxy_private.h
@@ -21,7 +21,9 @@ struct icmp_listen_params
{
HANDLE handle;
void *reply;
+ ULONGLONG user_reply_ptr;
unsigned int reply_len;
+ unsigned int bits;
int timeout;
};
@@ -34,3 +36,40 @@ struct icmp_send_echo_params
HANDLE handle;
ULONG ip_status;
};
+
+/* output for IOCTL_NSIPROXY_WINE_ICMP_ECHO - cf. ICMP_ECHO_REPLY */
+struct icmp_echo_reply_32
+{
+ ULONG addr;
+ ULONG status;
+ ULONG round_trip_time;
+ USHORT data_size;
+ USHORT num_of_pkts;
+ ULONG data_ptr;
+ struct
+ {
+ BYTE ttl;
+ BYTE tos;
+ BYTE flags;
+ BYTE options_size;
+ ULONG options_ptr;
+ } opts;
+};
+
+struct icmp_echo_reply_64
+{
+ ULONG addr;
+ ULONG status;
+ ULONG round_trip_time;
+ USHORT data_size;
+ USHORT num_of_pkts;
+ ULONGLONG data_ptr;
+ struct
+ {
+ BYTE ttl;
+ BYTE tos;
+ BYTE flags;
+ BYTE options_size;
+ ULONGLONG options_ptr;
+ } opts;
+};
diff --git a/include/wine/nsi.h b/include/wine/nsi.h
index 9664b53..8c3488d 100644
--- a/include/wine/nsi.h
+++ b/include/wine/nsi.h
@@ -426,6 +426,8 @@ struct nsiproxy_icmp_echo
{
SOCKADDR_INET src;
SOCKADDR_INET dst;
+ ULONGLONG user_reply_ptr;
+ BYTE bits;
BYTE ttl;
BYTE tos;
BYTE flags;
@@ -435,25 +437,6 @@ struct nsiproxy_icmp_echo
BYTE data[1]; /* ((opt_size + 3) & ~3) + req_size */
};
-/* output for IOCTL_NSIPROXY_WINE_ICMP_ECHO - cf. ICMP_ECHO_REPLY */
-struct nsiproxy_icmp_echo_reply
-{
- SOCKADDR_INET addr;
- ULONG status;
- ULONG round_trip_time;
- USHORT data_size;
- USHORT num_of_pkts;
- DWORD data_offset;
- struct
- {
- BYTE ttl;
- BYTE tos;
- BYTE flags;
- BYTE options_size;
- DWORD options_offset;
- } opts;
-};
-
/* Undocumented Nsi api */
#define NSI_PARAM_TYPE_RW 0
--
2.31.1
2
2