Compare commits

..

1 commit

Author SHA1 Message Date
eric pouech
512e694e7a Merge branch 'mr-dh-refresh' into 'master'
Implement dbghelp.SymRefreshModuleList().

See merge request wine/wine!6825
2024-11-16 10:32:14 +00:00
10 changed files with 67 additions and 496 deletions

View file

@ -275,11 +275,10 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void *
.serialnumber = {'0','0','0','0',0},
};
struct iohid_device *impl;
USAGE_AND_PAGE usages;
CFStringRef str;
usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey)));
usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey)));
desc.usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey)));
desc.usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey)));
desc.vid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDVendorIDKey)));
desc.pid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDProductIDKey)));
@ -290,8 +289,8 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void *
desc.is_bluetooth = !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothValue), 0) ||
!CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0);
if (usages.UsagePage != HID_USAGE_PAGE_GENERIC ||
!(usages.Usage == HID_USAGE_GENERIC_JOYSTICK || usages.Usage == HID_USAGE_GENERIC_GAMEPAD))
if (desc.usages.UsagePage != HID_USAGE_PAGE_GENERIC ||
!(desc.usages.Usage == HID_USAGE_GENERIC_JOYSTICK || desc.usages.Usage == HID_USAGE_GENERIC_GAMEPAD))
{
/* winebus isn't currently meant to handle anything but these, and
* opening keyboards, mice, or the Touch Bar on older MacBooks triggers

View file

@ -198,7 +198,7 @@ static void set_hat_value(struct unix_device *iface, int index, int value)
hid_device_set_hatswitch_y(iface, index, y);
}
static BOOL descriptor_add_haptic(struct sdl_device *impl, BOOL force)
static BOOL descriptor_add_haptic(struct sdl_device *impl)
{
USHORT i, count = 0;
USAGE usages[16];
@ -227,16 +227,16 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl, BOOL force)
if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL))
{
/* SDL_HAPTIC_SQUARE doesn't exist */
if (force || (impl->effect_support & SDL_HAPTIC_SINE)) usages[count++] = PID_USAGE_ET_SINE;
if (force || (impl->effect_support & SDL_HAPTIC_TRIANGLE)) usages[count++] = PID_USAGE_ET_TRIANGLE;
if (force || (impl->effect_support & SDL_HAPTIC_SAWTOOTHUP)) usages[count++] = PID_USAGE_ET_SAWTOOTH_UP;
if (force || (impl->effect_support & SDL_HAPTIC_SAWTOOTHDOWN)) usages[count++] = PID_USAGE_ET_SAWTOOTH_DOWN;
if (force || (impl->effect_support & SDL_HAPTIC_SPRING)) usages[count++] = PID_USAGE_ET_SPRING;
if (force || (impl->effect_support & SDL_HAPTIC_DAMPER)) usages[count++] = PID_USAGE_ET_DAMPER;
if (force || (impl->effect_support & SDL_HAPTIC_INERTIA)) usages[count++] = PID_USAGE_ET_INERTIA;
if (force || (impl->effect_support & SDL_HAPTIC_FRICTION)) usages[count++] = PID_USAGE_ET_FRICTION;
if (force || (impl->effect_support & SDL_HAPTIC_CONSTANT)) usages[count++] = PID_USAGE_ET_CONSTANT_FORCE;
if (force || (impl->effect_support & SDL_HAPTIC_RAMP)) usages[count++] = PID_USAGE_ET_RAMP;
if (impl->effect_support & SDL_HAPTIC_SINE) usages[count++] = PID_USAGE_ET_SINE;
if (impl->effect_support & SDL_HAPTIC_TRIANGLE) usages[count++] = PID_USAGE_ET_TRIANGLE;
if (impl->effect_support & SDL_HAPTIC_SAWTOOTHUP) usages[count++] = PID_USAGE_ET_SAWTOOTH_UP;
if (impl->effect_support & SDL_HAPTIC_SAWTOOTHDOWN) usages[count++] = PID_USAGE_ET_SAWTOOTH_DOWN;
if (impl->effect_support & SDL_HAPTIC_SPRING) usages[count++] = PID_USAGE_ET_SPRING;
if (impl->effect_support & SDL_HAPTIC_DAMPER) usages[count++] = PID_USAGE_ET_DAMPER;
if (impl->effect_support & SDL_HAPTIC_INERTIA) usages[count++] = PID_USAGE_ET_INERTIA;
if (impl->effect_support & SDL_HAPTIC_FRICTION) usages[count++] = PID_USAGE_ET_FRICTION;
if (impl->effect_support & SDL_HAPTIC_CONSTANT) usages[count++] = PID_USAGE_ET_CONSTANT_FORCE;
if (impl->effect_support & SDL_HAPTIC_RAMP) usages[count++] = PID_USAGE_ET_RAMP;
if (!hid_device_add_physical(&impl->unix_device, usages, count))
return FALSE;
@ -360,7 +360,7 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface)
if (!hid_device_end_input_report(iface))
return STATUS_NO_MEMORY;
if (!descriptor_add_haptic(impl, physical_usage.Usage == HID_USAGE_SIMULATION_AUTOMOBILE_SIMULATION_DEVICE))
if (!descriptor_add_haptic(impl))
return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface))
@ -414,7 +414,7 @@ static NTSTATUS build_controller_report_descriptor(struct unix_device *iface)
if (!hid_device_end_input_report(iface))
return STATUS_NO_MEMORY;
if (!descriptor_add_haptic(impl, FALSE))
if (!descriptor_add_haptic(impl))
return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface))
@ -443,12 +443,17 @@ static void sdl_device_destroy(struct unix_device *iface)
static NTSTATUS sdl_device_start(struct unix_device *iface)
{
struct sdl_device *impl = impl_from_unix_device(iface);
NTSTATUS status;
pthread_mutex_lock(&sdl_cs);
impl->started = TRUE;
if (impl->sdl_controller) status = build_controller_report_descriptor(iface);
else status = build_joystick_report_descriptor(iface);
impl->started = !status;
pthread_mutex_unlock(&sdl_cs);
return STATUS_SUCCESS;
return status;
}
static void sdl_device_stop(struct unix_device *iface)
@ -590,7 +595,7 @@ static NTSTATUS sdl_device_physical_effect_control(struct unix_device *iface, BY
TRACE("iface %p, index %u, control %04x, iterations %u.\n", iface, index, control, iterations);
if (id < 0) return STATUS_SUCCESS;
if (impl->effect_ids[index] < 0) return STATUS_UNSUCCESSFUL;
switch (control)
{
@ -986,6 +991,8 @@ static void sdl_add_device(unsigned int index)
if (controller)
{
desc.is_gamepad = TRUE;
desc.usages.UsagePage = HID_USAGE_PAGE_GENERIC;
desc.usages.Usage = HID_USAGE_GENERIC_GAMEPAD;
axis_count = 6;
}
else
@ -993,12 +1000,12 @@ static void sdl_add_device(unsigned int index)
int button_count = pSDL_JoystickNumButtons(joystick);
axis_count = pSDL_JoystickNumAxes(joystick);
desc.is_gamepad = (axis_count == 6 && button_count >= 14);
desc.usages.UsagePage = HID_USAGE_PAGE_GENERIC;
desc.usages.Usage = HID_USAGE_GENERIC_JOYSTICK;
}
for (axis_offset = 0; axis_offset < axis_count; axis_offset += (options.split_controllers ? 6 : axis_count))
{
NTSTATUS status;
if (!axis_offset) strcpy(buffer, product);
else snprintf(buffer, ARRAY_SIZE(buffer), "%s %d", product, axis_offset / 6);
ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.product, ARRAY_SIZE(desc.product));
@ -1012,15 +1019,6 @@ static void sdl_add_device(unsigned int index)
impl->id = id;
impl->axis_offset = axis_offset;
if (impl->sdl_controller) status = build_controller_report_descriptor(&impl->unix_device);
else status = build_joystick_report_descriptor(&impl->unix_device);
if (status)
{
list_remove(&impl->unix_device.entry);
impl->unix_device.vtbl->destroy(&impl->unix_device);
return;
}
bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc);
}
}

View file

@ -728,6 +728,12 @@ static void lnxev_device_destroy(struct unix_device *iface)
static NTSTATUS lnxev_device_start(struct unix_device *iface)
{
struct lnxev_device *impl = lnxev_impl_from_unix_device(iface);
NTSTATUS status;
if ((status = build_report_descriptor(iface, impl->base.udev_device)))
return status;
pthread_mutex_lock(&udev_cs);
start_polling_device(iface);
pthread_mutex_unlock(&udev_cs);
@ -1248,6 +1254,7 @@ static void udev_add_device(struct udev_device *dev, int fd)
#ifdef HAS_PROPER_INPUT_HEADER
else if (!strcmp(subsystem, "input"))
{
const USAGE_AND_PAGE device_usage = *what_am_I(dev, fd);
static const WCHAR evdev[] = {'e','v','d','e','v',0};
struct input_id device_id = {0};
char buffer[MAX_PATH];
@ -1268,6 +1275,8 @@ static void udev_add_device(struct udev_device *dev, int fd)
if (!desc.serialnumber[0] && ioctl(fd, EVIOCGUNIQ(sizeof(buffer)), buffer) >= 0)
ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber));
desc.usages = device_usage;
}
#endif
@ -1312,13 +1321,6 @@ static void udev_add_device(struct udev_device *dev, int fd)
strcpy(impl->devnode, devnode);
impl->device_fd = fd;
if (build_report_descriptor(&impl->unix_device, impl->udev_device))
{
list_remove(&impl->unix_device.entry);
impl->unix_device.vtbl->destroy(&impl->unix_device);
return;
}
bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc);
}
#endif

View file

@ -417,7 +417,7 @@ static DWORD check_bus_option(const WCHAR *option, DWORD default_value)
return default_value;
}
static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, UINT buttons)
static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages)
{
char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024])];
KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
@ -436,48 +436,6 @@ static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages,
if (is_dualshock4_gamepad(vid, pid)) prefer_hidraw = TRUE;
if (is_dualsense_gamepad(vid, pid)) prefer_hidraw = TRUE;
switch (vid)
{
case 0x044f:
if (pid == 0xb679) prefer_hidraw = TRUE; /* ThrustMaster T-Rudder */
if (pid == 0xb687) prefer_hidraw = TRUE; /* ThrustMaster TWCS Throttle */
if (pid == 0xb10a) prefer_hidraw = TRUE; /* ThrustMaster T.16000M Joystick */
break;
case 0x16d0:
if (pid == 0x0d61) prefer_hidraw = TRUE; /* Simucube 2 Sport */
if (pid == 0x0d60) prefer_hidraw = TRUE; /* Simucube 2 Pro */
if (pid == 0x0d5f) prefer_hidraw = TRUE; /* Simucube 2 Ultimate */
if (pid == 0x0d5a) prefer_hidraw = TRUE; /* Simucube 1 */
break;
case 0x0eb7:
if (pid == 0x183b) prefer_hidraw = TRUE; /* Fanatec ClubSport Pedals v3 */
if (pid == 0x1839) prefer_hidraw = TRUE; /* Fanatec ClubSport Pedals v1/v2 */
break;
case 0x231d:
/* comes with 128 buttons in the default configuration */
if (buttons == 128) prefer_hidraw = TRUE;
/* if customized, less than 128 buttons may be shown, decide by PID */
if (pid == 0x0200) prefer_hidraw = TRUE; /* VKBsim Gladiator EVO Right Grip */
if (pid == 0x0201) prefer_hidraw = TRUE; /* VKBsim Gladiator EVO Left Grip */
if (pid == 0x0126) prefer_hidraw = TRUE; /* VKB-Sim Space Gunfighter */
if (pid == 0x0127) prefer_hidraw = TRUE; /* VKB-Sim Space Gunfighter L */
break;
case 0x3344:
/* comes with 31 buttons in the default configuration, or 128 max */
if ((buttons == 31) || (buttons == 128)) prefer_hidraw = TRUE;
/* users may have configured button limits, usually 32/50/64 */
if ((buttons == 32) || (buttons == 50) || (buttons == 64)) prefer_hidraw = TRUE;
/* if customized, arbitrary amount of buttons may be shown, decide by PID */
if (pid == 0x412f) prefer_hidraw = TRUE; /* Virpil Constellation ALPHA-R */
if (pid == 0x812c) prefer_hidraw = TRUE; /* Virpil Constellation ALPHA-L */
break;
case 0x03eb:
/* users may have configured button limits, usually 32/50/64 */
if ((buttons == 32) || (buttons == 50) || (buttons == 64)) prefer_hidraw = TRUE;
if (pid == 0x2055) prefer_hidraw = TRUE; /* ATMEL/VIRPIL/200325 VPC Throttle MT-50 CM2 */
break;
}
RtlInitUnicodeString(&str, L"EnableHidraw");
if (!NtQueryValueKey(driver_key, &str, KeyValuePartialInformation, info,
sizeof(buffer) - sizeof(WCHAR), &size))
@ -726,41 +684,22 @@ static NTSTATUS get_device_descriptors(UINT64 unix_device, BYTE **report_desc, U
return STATUS_SUCCESS;
}
static USAGE_AND_PAGE get_device_usages(UINT64 unix_device, UINT *buttons)
static USAGE_AND_PAGE get_hidraw_device_usages(UINT64 unix_device)
{
HIDP_DEVICE_DESC device_desc;
USAGE_AND_PAGE usages = {0};
UINT i, count = 0, report_desc_length;
HIDP_BUTTON_CAPS *button_caps;
UINT report_desc_length;
BYTE *report_desc;
NTSTATUS status;
HIDP_CAPS caps;
if (!(status = get_device_descriptors(unix_device, &report_desc, &report_desc_length, &device_desc)))
{
PHIDP_PREPARSED_DATA preparsed = device_desc.CollectionDesc[0].PreparsedData;
usages.UsagePage = device_desc.CollectionDesc[0].UsagePage;
usages.Usage = device_desc.CollectionDesc[0].Usage;
if ((status = HidP_GetCaps(preparsed, &caps)) == HIDP_STATUS_SUCCESS &&
(button_caps = malloc(sizeof(*button_caps) * caps.NumberInputButtonCaps)))
{
status = HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, preparsed);
if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetButtonCaps returned %#lx\n", status);
else for (i = 0; i < caps.NumberInputButtonCaps; i++)
{
if (button_caps[i].UsagePage != HID_USAGE_PAGE_BUTTON) continue;
if (button_caps[i].IsRange) count = max(count, button_caps[i].Range.UsageMax);
else count = max(count, button_caps[i].NotRange.Usage);
}
free(button_caps);
}
HidP_FreeCollectionDescription(&device_desc);
RtlFreeHeap(GetProcessHeap(), 0, report_desc);
}
*buttons = count;
return usages;
}
@ -810,21 +749,18 @@ static DWORD CALLBACK bus_main_thread(void *args)
case BUS_EVENT_TYPE_DEVICE_CREATED:
{
struct device_desc desc = event->device_created.desc;
USAGE_AND_PAGE usages;
UINT buttons;
usages = get_device_usages(event->device, &buttons);
if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &usages, buttons))
if (desc.is_hidraw && !desc.usages.UsagePage) desc.usages = get_hidraw_device_usages(event->device);
if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &desc.usages))
{
struct device_remove_params params = {.device = event->device};
WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-",
desc.vid, desc.pid, usages.UsagePage, usages.Usage);
desc.vid, desc.pid, desc.usages.UsagePage, desc.usages.Usage);
winebus_call(device_remove, &params);
break;
}
TRACE("creating %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-",
desc.vid, desc.pid, usages.UsagePage, usages.Usage);
desc.vid, desc.pid, desc.usages.UsagePage, desc.usages.Usage);
device = bus_create_hid_device(&event->device_created.desc, event->device);
if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations);

View file

@ -49,6 +49,14 @@ static void mouse_destroy(struct unix_device *iface)
static NTSTATUS mouse_start(struct unix_device *iface)
{
const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_MOUSE};
if (!hid_device_begin_report_descriptor(iface, &device_usage))
return STATUS_NO_MEMORY;
if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_BUTTON, 1, 3))
return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
return STATUS_SUCCESS;
}
@ -115,21 +123,9 @@ static const struct device_desc mouse_device_desc =
static NTSTATUS mouse_device_create(void *args)
{
const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_MOUSE};
struct device_create_params *params = args;
struct unix_device *iface;
if (!(iface = hid_device_create(&mouse_vtbl, sizeof(struct mouse_device))))
return STATUS_NO_MEMORY;
if (!hid_device_begin_report_descriptor(iface, &device_usage))
return STATUS_NO_MEMORY;
if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_BUTTON, 1, 3))
return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
params->desc = mouse_device_desc;
params->device = (UINT_PTR)iface;
params->device = (UINT_PTR)hid_device_create(&mouse_vtbl, sizeof(struct mouse_device));
return STATUS_SUCCESS;
}
@ -144,6 +140,14 @@ static void keyboard_destroy(struct unix_device *iface)
static NTSTATUS keyboard_start(struct unix_device *iface)
{
const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_KEYBOARD};
if (!hid_device_begin_report_descriptor(iface, &device_usage))
return STATUS_NO_MEMORY;
if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_KEYBOARD, 0, 101))
return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
return STATUS_SUCCESS;
}
@ -210,21 +214,9 @@ static const struct device_desc keyboard_device_desc =
static NTSTATUS keyboard_device_create(void *args)
{
const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_KEYBOARD};
struct device_create_params *params = args;
struct unix_device *iface;
if (!(iface = hid_device_create(&keyboard_vtbl, sizeof(struct keyboard_device))))
return STATUS_NO_MEMORY;
if (!hid_device_begin_report_descriptor(iface, &device_usage))
return STATUS_NO_MEMORY;
if (!hid_device_add_buttons(iface, HID_USAGE_PAGE_KEYBOARD, 0, 101))
return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface))
return STATUS_NO_MEMORY;
params->desc = keyboard_device_desc;
params->device = (UINT_PTR)iface;
params->device = (UINT_PTR)hid_device_create(&keyboard_vtbl, sizeof(struct keyboard_device));
return STATUS_SUCCESS;
}

View file

@ -38,6 +38,7 @@ struct device_desc
UINT version;
UINT input;
UINT uid;
USAGE_AND_PAGE usages;
BOOL is_gamepad;
BOOL is_hidraw;
BOOL is_bluetooth;
@ -150,8 +151,8 @@ enum unix_funcs
static inline const char *debugstr_device_desc(struct device_desc *desc)
{
if (!desc) return "(null)";
return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, is_gamepad %u, is_hidraw %u, is_bluetooth %u}",
desc->vid, desc->pid, desc->version, desc->input, desc->uid,
return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, usage %04x:%04x, is_gamepad %u, is_hidraw %u, is_bluetooth %u}",
desc->vid, desc->pid, desc->version, desc->input, desc->uid, desc->usages.UsagePage, desc->usages.Usage,
desc->is_gamepad, desc->is_hidraw, desc->is_bluetooth);
}

View file

@ -1240,211 +1240,3 @@ HRESULT WINAPI RoResolveNamespace(HSTRING name, HSTRING windowsMetaDataDir,
return RO_E_METADATA_NAME_NOT_FOUND;
}
struct parse_type_context
{
DWORD allocated_parts_count;
DWORD parts_count;
HSTRING *parts;
};
static HRESULT add_part(struct parse_type_context *context, const WCHAR *part, size_t length)
{
DWORD new_parts_count;
HSTRING *new_parts;
HRESULT hr;
if (context->parts_count == context->allocated_parts_count)
{
new_parts_count = context->allocated_parts_count ? context->allocated_parts_count * 2 : 4;
new_parts = CoTaskMemRealloc(context->parts, new_parts_count * sizeof(*context->parts));
if (!new_parts)
return E_OUTOFMEMORY;
context->allocated_parts_count = new_parts_count;
context->parts = new_parts;
}
if (FAILED(hr = WindowsCreateString(part, length, &context->parts[context->parts_count])))
return hr;
context->parts_count++;
return S_OK;
}
static HRESULT parse_part(struct parse_type_context *context, const WCHAR *input, unsigned int length)
{
const WCHAR *start, *end, *ptr;
start = input;
end = start + length;
/* Remove leading spaces */
while (start < end && *start == ' ')
start++;
/* Remove trailing spaces */
while (end - 1 >= start && end[-1] == ' ')
end--;
/* Only contains spaces */
if (start == end)
return RO_E_METADATA_INVALID_TYPE_FORMAT;
/* Has spaces in the middle */
for (ptr = start; ptr < end; ptr++)
{
if (*ptr == ' ')
return RO_E_METADATA_INVALID_TYPE_FORMAT;
}
return add_part(context, start, end - start);
}
static HRESULT parse_type(struct parse_type_context *context, const WCHAR *input, unsigned int length)
{
unsigned int i, parameter_count, nested_level;
const WCHAR *start, *end, *part_start, *ptr;
HRESULT hr;
start = input;
end = start + length;
part_start = start;
ptr = start;
/* Read until the end of input or '`' or '<' or '>' or ',' */
while (ptr < end && *ptr != '`' && *ptr != '<' && *ptr != '>' && *ptr != ',')
ptr++;
/* If the type name has '`' and there are characters before '`' */
if (ptr > start && ptr < end && *ptr == '`')
{
/* Move past the '`' */
ptr++;
/* Read the number of type parameters, expecting '1' to '9' */
if (!(ptr < end && *ptr >= '1' && *ptr <= '9'))
return RO_E_METADATA_INVALID_TYPE_FORMAT;
parameter_count = *ptr - '0';
/* Move past the number of type parameters, expecting '<' */
ptr++;
if (!(ptr < end && *ptr == '<'))
return RO_E_METADATA_INVALID_TYPE_FORMAT;
/* Add the name of parameterized interface, e.g., the "interface`1" in "interface`1<parameter>" */
if (FAILED(hr = parse_part(context, part_start, ptr - part_start)))
return hr;
/* Move past the '<' */
ptr++;
nested_level = 1;
/* Read parameters inside brackets, e.g., the "p1" and "p2" in "interface`2<p1, p2>" */
for (i = 0; i < parameter_count; i++)
{
/* Read a new parameter */
part_start = ptr;
/* Read until ','. The comma must be at the same nested bracket level */
while (ptr < end)
{
if (*ptr == '<')
{
nested_level++;
ptr++;
}
else if (*ptr == '>')
{
/* The last parameter before '>' */
if (i == parameter_count - 1 && nested_level == 1)
{
if (FAILED(hr = parse_type(context, part_start, ptr - part_start)))
return hr;
nested_level--;
ptr++;
/* Finish reading all parameters */
break;
}
nested_level--;
ptr++;
}
else if (*ptr == ',' && nested_level == 1)
{
/* Parse the parameter, which can be another parameterized type */
if (FAILED(hr = parse_type(context, part_start, ptr - part_start)))
return hr;
/* Move past the ',' */
ptr++;
/* Finish reading one parameter */
break;
}
else
{
ptr++;
}
}
}
/* Mismatching brackets or not enough parameters */
if (nested_level != 0 || i != parameter_count)
return RO_E_METADATA_INVALID_TYPE_FORMAT;
/* The remaining characters must be spaces */
while (ptr < end)
{
if (*ptr++ != ' ')
return RO_E_METADATA_INVALID_TYPE_FORMAT;
}
return S_OK;
}
/* Contain invalid '`', '<', '>' or ',' */
else if (ptr != end)
{
return RO_E_METADATA_INVALID_TYPE_FORMAT;
}
/* Non-parameterized */
else
{
return parse_part(context, part_start, ptr - part_start);
}
}
HRESULT WINAPI RoParseTypeName(HSTRING type_name, DWORD *parts_count, HSTRING **parts)
{
struct parse_type_context context = {0};
const WCHAR *input;
unsigned int i;
HRESULT hr;
TRACE("%s %p %p.\n", debugstr_hstring(type_name), parts_count, parts);
/* Empty string */
if (!WindowsGetStringLen(type_name))
return E_INVALIDARG;
input = WindowsGetStringRawBuffer(type_name, NULL);
/* The string has a leading space */
if (input[0] == ' ')
return RO_E_METADATA_INVALID_TYPE_FORMAT;
*parts_count = 0;
*parts = NULL;
if (FAILED(hr = parse_type(&context, input, wcslen(input))))
{
for (i = 0; i < context.parts_count; i++)
WindowsDeleteString(context.parts[i]);
CoTaskMemFree(context.parts);
return hr;
}
*parts_count = context.parts_count;
*parts = context.parts;
return S_OK;
}

View file

@ -814,159 +814,11 @@ static void test_RoResolveNamespace(void)
RoUninitialize();
}
static void test_RoParseTypeName(void)
{
static const struct
{
const WCHAR *type_name;
HRESULT hr;
DWORD parts_count;
const WCHAR *parts[16];
}
tests[] =
{
/* Invalid type names */
{L"", E_INVALIDARG},
{L" ", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"`", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"<", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L">", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L",", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"<>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"`<>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a b", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a,b", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"1<>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L" a", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L" a ", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a<", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a<>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`<>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`1<>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a<b>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`<b> ", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"`1<b>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L" a`1<b>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`1<b>c", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`1<b,>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`2<b, <c, d>>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`10<b1, b2, b3, b4, b5, b6, b7, b8, b9, b10>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`0xa<b1, b2, b3, b4, b5, b6, b7, b8, b9, b10>", RO_E_METADATA_INVALID_TYPE_FORMAT},
{L"a`a<b1, b2, b3, b4, b5, b6, b7, b8, b9, b10>", RO_E_METADATA_INVALID_TYPE_FORMAT},
/* Valid type names */
{L"1", S_OK, 1, {L"1"}},
{L"a", S_OK, 1, {L"a"}},
{L"-", S_OK, 1, {L"-"}},
{L"a ", S_OK, 1, {L"a"}},
{L"0`1<b>", S_OK, 2, {L"0`1", L"b"}},
{L"a`1<b>", S_OK, 2, {L"a`1", L"b"}},
{L"a`1<b> ", S_OK, 2, {L"a`1", L"b"}},
{L"a`1<b >", S_OK, 2, {L"a`1", L"b"}},
{L"a`1< b>", S_OK, 2, {L"a`1", L"b"}},
{L"a`1< b >", S_OK, 2, {L"a`1", L"b"}},
{L"a`2<b,c>", S_OK, 3, {L"a`2", L"b", L"c"}},
{L"a`2<b, c>", S_OK, 3, {L"a`2", L"b", L"c"}},
{L"a`2<b ,c>", S_OK, 3, {L"a`2", L"b", L"c"}},
{L"a`2<b , c>", S_OK, 3, {L"a`2", L"b", L"c"}},
{L"a`3<b, c, d>", S_OK, 4, {L"a`3", L"b", L"c", L"d"}},
{L"a`1<b`1<c>>", S_OK, 3, {L"a`1", L"b`1", L"c"}},
{L"a`1<b`2<c, d>>", S_OK, 4, {L"a`1", L"b`2", L"c", L"d"}},
{L"a`2<b`2<c, d>, e>", S_OK, 5, {L"a`2", L"b`2", L"c", L"d", L"e"}},
{L"a`2<b, c`2<d, e>>", S_OK, 5, {L"a`2", L"b", L"c`2", L"d", L"e"}},
{L"a`9<b1, b2, b3, b4, b5, b6, b7, b8, b9>", S_OK, 10, {L"a`9", L"b1", L"b2", L"b3", L"b4", L"b5", L"b6", L"b7", L"b8", L"b9"}},
{L"Windows.Foundation.IExtensionInformation", S_OK, 1, {L"Windows.Foundation.IExtensionInformation"}},
{L"Windows.Foundation.IReference`1<Windows.UI.Color>", S_OK, 2, {L"Windows.Foundation.IReference`1", L"Windows.UI.Color"}},
{L"Windows.Foundation.Collections.IIterator`1<Windows.Foundation.Collections.IMapView`2<Windows.Foundation.Collections.IVector`1<String>, String>>",
S_OK, 5, {L"Windows.Foundation.Collections.IIterator`1",
L"Windows.Foundation.Collections.IMapView`2",
L"Windows.Foundation.Collections.IVector`1",
L"String",
L"String"}},
};
HSTRING type_name, *parts;
const WCHAR *buffer;
DWORD parts_count;
unsigned int i, j;
HRESULT hr;
/* Parameter checks */
hr = WindowsCreateString(L"a", 1, &type_name);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = RoParseTypeName(NULL, &parts_count, &parts);
ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
/* Crash on Windows */
if (0)
{
hr = RoParseTypeName(type_name, NULL, &parts);
ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
hr = RoParseTypeName(type_name, &parts_count, NULL);
ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
}
hr = RoParseTypeName(type_name, &parts_count, &parts);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
ok(parts_count == 1, "Got unexpected %ld.\n", parts_count);
hr = WindowsDeleteString(parts[0]);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
CoTaskMemFree(parts);
hr = WindowsDeleteString(type_name);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
/* Parsing checks */
for (i = 0; i < ARRAY_SIZE(tests); i++)
{
winetest_push_context("%s", wine_dbgstr_w(tests[i].type_name));
if (tests[i].type_name)
{
hr = WindowsCreateString(tests[i].type_name, wcslen(tests[i].type_name), &type_name);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
}
else
{
type_name = NULL;
}
parts_count = 0;
hr = RoParseTypeName(type_name, &parts_count, &parts);
ok(hr == tests[i].hr, "Got unexpected hr %#lx.\n", hr);
if (FAILED(hr))
{
hr = WindowsDeleteString(type_name);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
winetest_pop_context();
continue;
}
ok(parts_count == tests[i].parts_count, "Got unexpected %lu.\n", parts_count);
for (j = 0; j < parts_count; j++)
{
winetest_push_context("%s", wine_dbgstr_w(tests[i].parts[j]));
buffer = WindowsGetStringRawBuffer(parts[j], NULL);
ok(!lstrcmpW(tests[i].parts[j], buffer), "Got unexpected %s.\n", wine_dbgstr_w(buffer));
hr = WindowsDeleteString(parts[j]);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
winetest_pop_context();
}
CoTaskMemFree(parts);
hr = WindowsDeleteString(type_name);
ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
winetest_pop_context();
}
}
START_TEST(wintypes)
{
IsWow64Process(GetCurrentProcess(), &is_wow64);
test_IApiInformationStatics();
test_IPropertyValueStatics();
test_RoParseTypeName();
test_RoResolveNamespace();
}

View file

@ -7,5 +7,5 @@
@ stub RoGetMetaDataFile
@ stdcall RoIsApiContractMajorVersionPresent(wstr long ptr)
@ stub RoIsApiContractPresent
@ stdcall RoParseTypeName(ptr ptr ptr)
@ stub RoParseTypeName
@ stdcall RoResolveNamespace(ptr ptr long ptr ptr ptr ptr ptr)

View file

@ -23,7 +23,6 @@
#include <hstring.h>
HRESULT WINAPI RoIsApiContractMajorVersionPresent(const WCHAR *, UINT16, BOOL *);
HRESULT WINAPI RoParseTypeName(HSTRING, DWORD *, HSTRING **);
HRESULT WINAPI RoResolveNamespace(HSTRING, HSTRING, DWORD, const HSTRING *, DWORD *, HSTRING **, DWORD *, HSTRING **);
#endif /* _ROMETADATARESOLUTION_H */