Compare commits

...

58 commits

Author SHA1 Message Date
Fabian Maurer
12925e9113 net: Correct error code for stopping non existing service.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55859
2024-11-18 21:39:32 +01:00
Fabian Maurer
bce1213281 net/tests: Add test for stopping non existing service. 2024-11-18 21:39:32 +01:00
Rémi Bernon
0cda918561 winex11: Request window state updates asynchronously. 2024-11-18 21:38:16 +01:00
Rémi Bernon
d8b5a3ae12 winex11: Update the window client config on window state changes. 2024-11-18 21:38:16 +01:00
Rémi Bernon
03738c3f22 winex11: Wait for pending ConfigureNotify before updating the client state. 2024-11-18 21:38:16 +01:00
Rémi Bernon
8bbc193178 winex11: Wait for pending _NET_WM_STATE before updating the client state. 2024-11-18 21:38:16 +01:00
Rémi Bernon
03457ece24 winex11: Don't expect WM_STATE events on override-redirect windows. 2024-11-18 21:38:16 +01:00
Rémi Bernon
be6902d072 winex11: Listen to PropertyNotify events on the virtual desktop window.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57423
2024-11-18 21:38:16 +01:00
Rémi Bernon
6ac127ebc6 dinput: Only call SetCursorPos if ClipCursor fails.
Fixes mouse sometimes jumping around in Mechwarrior Online on
KDE/Wayland.
2024-11-18 21:36:52 +01:00
Rémi Bernon
b1e54a5f04 dinput: Assume that clipping the cursor uses the requested rectangle. 2024-11-18 21:36:51 +01:00
Anton Baskanov
3f7c85f7a3 dplayx: Add groups from SUPERENUMPLAYERSREPLY to the session. 2024-11-18 21:36:41 +01:00
Anton Baskanov
0eb2f18166 dplayx: Inform the SP about group creation in DP_CreateGroup(). 2024-11-18 21:36:41 +01:00
Anton Baskanov
18a7362940 dplayx: Return HRESULT from DP_CreateGroup(). 2024-11-18 21:36:41 +01:00
Anton Baskanov
be022f350d dplayx: Set group data in DP_CreateGroup(). 2024-11-18 21:36:41 +01:00
Anton Baskanov
1b9b7a5e65 dplayx: Add group to the parent group in DP_CreateGroup(). 2024-11-18 21:36:41 +01:00
Anton Baskanov
46b79b1856 dplayx/tests: Check that groups from SUPERENUMPLAYERSREPLY are added to the session. 2024-11-18 21:36:40 +01:00
Anton Baskanov
696ef034db dplayx/tests: Add missing pragma pack directives. 2024-11-18 21:36:40 +01:00
Alexandre Julliard
ac1ff67cfd server: Use an explicit union instead of a typedef for select operations. 2024-11-18 21:35:50 +01:00
Alexandre Julliard
ab399468c2 server: Use an explicit union instead of a typedef for IRP params. 2024-11-18 21:34:40 +01:00
Alexandre Julliard
6f5e34ad14 server: Use an explicit union instead of a typedef for debug event data. 2024-11-18 21:33:42 +01:00
Alexandre Julliard
180ba49cee server: Use an explicit union instead of a typedef for hardware input. 2024-11-18 21:32:53 +01:00
Alexandre Julliard
ce946e57db server: Use an explicit union instead of a typedef for message data. 2024-11-18 21:29:14 +01:00
Eric Pouech
446f3b207f dbghelp: Implement SymRefreshModuleList().
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-18 11:54:35 +01:00
Eric Pouech
90ffd6c7dc dbghelp/tests: Add tests for SymRefreshModuleList().
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-18 11:54:35 +01:00
Eric Pouech
3ca383e34e dbghelp/tests: Add retry wrapper around SymRefreshModuleList().
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-18 11:54:35 +01:00
Rémi Bernon
c5a726e8a3 winebus: Enable hidraw by default for various HOTAS controllers.
Based on contributions from Andrew Conrad, Arkadiusz Hiler, Ivo Ivanov,
and Kai Krakow.
2024-11-18 11:53:54 +01:00
Rémi Bernon
a10ea7e662 winebus: Count HID buttons and pass it to is_hidraw_enabled. 2024-11-18 11:53:54 +01:00
Rémi Bernon
b787e0654a winebus: Lookup device HID usage and usage page on the PE side. 2024-11-18 11:53:54 +01:00
Rémi Bernon
29226ef249 winebus: Build HID report descriptors on device creation. 2024-11-18 11:53:54 +01:00
Rémi Bernon
933b885ce7 winebus: Enable all PID effect types for wheel devices.
Forza Horizon 5 doesn't like unsupported racing wheel force feedback
effects and gives up too soon.

On Windows many wheel devices have custom drivers which report support
for all types of force feedback effects.
2024-11-18 11:53:39 +01:00
Rémi Bernon
c3b1f1430c winebus: Always return success from PID effect control.
Forza Horizon 5 doesn't like unsupported racing wheel force feedback
effects.
2024-11-18 11:53:37 +01:00
Zhiyi Zhang
a308076081 wintypes/tests: Add RoParseTypeName() tests. 2024-11-18 11:52:15 +01:00
Zhiyi Zhang
6e79260df0 wintypes: Implement RoParseTypeName(). 2024-11-18 11:52:12 +01:00
Rémi Bernon
ae6366b33c winex11: Introduce a new window_update_client_config helper. 2024-11-15 19:08:41 +01:00
Rémi Bernon
d9cf4678a1 winex11: Introduce a new window_update_client_state helper. 2024-11-15 19:08:41 +01:00
Rémi Bernon
da936bcf35 winex11: Use the new window state tracker to get WM_STATE value. 2024-11-15 19:08:40 +01:00
Rémi Bernon
e75192fe72 winex11: Use the new window state tracker to get _NET_WM_STATE value. 2024-11-15 19:08:40 +01:00
Rémi Bernon
0dc7e40468 winex11: Ignore focus changes during WM_STATE transitions.
When WM_STATE is being quickly updated, and depending on the WM we might
receive transient focus changes, which will disrupt the Win32 state and
make us randomly lose focus.

Ignore them instead, when a window is being shown, and wait for WM_STATE
to be updated and stable. We will eventually receive a WM_TAKE_FOCUS /
FocusIn event *after* a window has been shown.

When a window is hidden or minimized, we will receive the FocusOut event
during the WM_STATE transition, and can safely handle it in this case,
as we should have done all the Win32 side effects and have changed the
foreground window already.

When there's no window state change pending, the focus change event is
unexpected, coming from the user or WM, and we handle it normally.
2024-11-15 19:08:20 +01:00
Biswapriyo Nath
700ee59470 include: Add UI Automation Annotation Type ID definitions.
Required for c7ba4a9640
2024-11-15 19:08:10 +01:00
Marc-Aurel Zent
c76a192bf6 winex11: Include kbd.h instead of ime.h. 2024-11-15 19:07:58 +01:00
Marc-Aurel Zent
9acdc03128 include: Add Japanese IME virtual key codes to kbd.h. 2024-11-15 19:07:57 +01:00
Hans Leidekker
8b121591be wininet: Use InternetTimeToSystemTimeW() to convert header values.
The current code calls mktime() which interprets its argument as local time while these
values are assumed to be in UTC.
2024-11-15 19:07:26 +01:00
Hans Leidekker
5a23afb34d wininet: Accept UTC as the equivalent of GMT.
Based on a patch by Etaash Mathamsetty.
2024-11-15 19:07:24 +01:00
Nikolay Sivov
6a01532899 comctl32/listview: Send LVN_HOTTRACK in response to mouse moves.
It's worth noting that comctl32 v6 have hottracking notifications enabled
by default, there is no need to set any extended styles.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
2024-11-15 19:07:06 +01:00
Nikolay Sivov
e5b0ead2b5 comctl32/listview: Initialize hot cursor handle.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
2024-11-15 19:07:04 +01:00
Eric Pouech
b9c06c4474 dbghelp: Fill-in data in SymSrvGetFileIndexIndo if BAD_EXE_FORMAT.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-15 16:25:10 +01:00
Eric Pouech
a57eedec86 dbghelp/tests: Improve SymSrvGetFileIndexInfo tests.
Esp. the failures with ERROR_BAD_EXE_FORMAT still fill all the fields
in the returned structure.

Add more flexibility to .dbg file creation (optional DEBUG_DIRECTORY).

Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-15 16:25:10 +01:00
Eric Pouech
9212706ede dbghelp: Only WARN on stripped PE images.
When stripping, binutils' objcopy also sets the flag, yet
without stripping into a .DBG file.

Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-15 16:25:10 +01:00
Eric Pouech
40b314cf34 dbghelp: Don't try to load PDB for a RSDS debug directory in .buildid section.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-11-15 16:25:10 +01:00
Brendan Shanks
aa24458086 Add .gitattributes file to mark generated files. 2024-11-15 16:25:10 +01:00
Alexandre Julliard
576d7e24cd server: Use an explicit struct instead of a typedef for async I/O data. 2024-11-15 16:25:10 +01:00
Alexandre Julliard
305ec347dc server: Use an explicit struct instead of a typedef for user APCs. 2024-11-15 16:25:10 +01:00
Alexandre Julliard
4c0103e58c server: Use an explicit union instead of a typedef for APC results. 2024-11-15 16:25:10 +01:00
Alexandre Julliard
1137a10ef7 server: Use an explicit union instead of a typedef for APC calls. 2024-11-15 16:25:10 +01:00
Alexandre Julliard
eae7db4fa4 server: Simplify updating the protocol version. 2024-11-15 16:25:09 +01:00
Alexandre Julliard
75e2ec479b server: Move the generated part of trace.c to a separate header. 2024-11-15 16:25:09 +01:00
Alexandre Julliard
45953cdbec server: Move the generated part of request.h to a separate header. 2024-11-15 16:25:09 +01:00
Alexandre Julliard
126c54cd25 server: Print a warning if page size isn't 4k. 2024-11-15 16:25:09 +01:00
70 changed files with 8679 additions and 7668 deletions

64
.gitattributes vendored Normal file
View file

@ -0,0 +1,64 @@
[attr]generated gitlab-generated linguist-generated=true
# generated by autotools
configure generated
include/config.h.in generated
# generated by dlls/dsound/make_fir
dlls/dsound/fir.h generated
# generated by dlls/opencl/make_opencl
dlls/opencl/opencl.spec generated
dlls/opencl/opencl_types.h generated
dlls/opencl/pe_thunks.c generated
dlls/opencl/unix_thunks.c generated
dlls/opencl/unixlib.h generated
# generated by dlls/opengl32/make_opengl
dlls/opengl32/opengl32.spec generated
dlls/opengl32/thunks.c generated
dlls/opengl32/unix_thunks.c generated
dlls/opengl32/unixlib.h generated
include/wine/wgl.h generated
include/wine/wgl_driver.h generated
# generated by dlls/winevulkan/make_vulkan
dlls/vulkan-1/vulkan-1.spec generated
dlls/winevulkan/loader_thunks.c generated
dlls/winevulkan/loader_thunks.h generated
dlls/winevulkan/vulkan_thunks.c generated
dlls/winevulkan/vulkan_thunks.h generated
dlls/winevulkan/winevulkan.json generated
dlls/winevulkan/winevulkan.spec generated
include/wine/vulkan.h generated
include/wine/vulkan_driver.h generated
# generated by tools/make_requests
include/wine/server_protocol.h generated
server/request_handlers.h generated
server/request_trace.h generated
# generated by tools/make_specfiles
dlls/ntdll/ntsyscalls.h generated
dlls/win32u/win32syscalls.h generated
# generated by tools/make_unicode
dlls/dwrite/bracket.c generated
dlls/dwrite/direction.c generated
dlls/dwrite/linebreak.c generated
dlls/dwrite/mirror.c generated
dlls/dwrite/scripts.c generated
dlls/dwrite/scripts.h generated
dlls/dwrite/shapers/arabic_table.c generated
dlls/gdi32/uniscribe/bracket.c generated
dlls/gdi32/uniscribe/direction.c generated
dlls/gdi32/uniscribe/indicsyllable.c generated
dlls/gdi32/uniscribe/linebreak.c generated
dlls/gdi32/uniscribe/mirror.c generated
dlls/gdi32/uniscribe/shaping.c generated
dlls/kernelbase/kernelbase.rgs generated
dlls/tzres/tzres.rc generated
dlls/win32u/vertical.c generated
dlls/wineps.drv/direction.c generated
dlls/wineps.drv/vertical.c generated
nls/*.nls generated

1
configure generated vendored
View file

@ -23070,6 +23070,7 @@ wine_fn_config_makefile programs/msidb enable_msidb
wine_fn_config_makefile programs/msiexec enable_msiexec wine_fn_config_makefile programs/msiexec enable_msiexec
wine_fn_config_makefile programs/msinfo32 enable_msinfo32 wine_fn_config_makefile programs/msinfo32 enable_msinfo32
wine_fn_config_makefile programs/net enable_net wine_fn_config_makefile programs/net enable_net
wine_fn_config_makefile programs/net/tests enable_tests
wine_fn_config_makefile programs/netsh enable_netsh wine_fn_config_makefile programs/netsh enable_netsh
wine_fn_config_makefile programs/netstat enable_netstat wine_fn_config_makefile programs/netstat enable_netstat
wine_fn_config_makefile programs/ngen enable_ngen wine_fn_config_makefile programs/ngen enable_ngen

View file

@ -3468,6 +3468,7 @@ WINE_CONFIG_MAKEFILE(programs/msidb)
WINE_CONFIG_MAKEFILE(programs/msiexec) WINE_CONFIG_MAKEFILE(programs/msiexec)
WINE_CONFIG_MAKEFILE(programs/msinfo32) WINE_CONFIG_MAKEFILE(programs/msinfo32)
WINE_CONFIG_MAKEFILE(programs/net) WINE_CONFIG_MAKEFILE(programs/net)
WINE_CONFIG_MAKEFILE(programs/net/tests)
WINE_CONFIG_MAKEFILE(programs/netsh) WINE_CONFIG_MAKEFILE(programs/netsh)
WINE_CONFIG_MAKEFILE(programs/netstat) WINE_CONFIG_MAKEFILE(programs/netstat)
WINE_CONFIG_MAKEFILE(programs/ngen) WINE_CONFIG_MAKEFILE(programs/ngen)

View file

@ -4150,6 +4150,7 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
/* see if we are supposed to be tracking mouse hovering */ /* see if we are supposed to be tracking mouse hovering */
if (LISTVIEW_IsHotTracking(infoPtr)) { if (LISTVIEW_IsHotTracking(infoPtr)) {
TRACKMOUSEEVENT trackinfo; TRACKMOUSEEVENT trackinfo;
NMLISTVIEW nmlv = { 0 };
DWORD flags; DWORD flags;
trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
@ -4170,6 +4171,15 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
/* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */ /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */
_TrackMouseEvent(&trackinfo); _TrackMouseEvent(&trackinfo);
} }
ht.pt = pt;
LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
nmlv.iItem = ht.iItem;
nmlv.iSubItem = ht.iSubItem;
nmlv.ptAction = pt;
notify_listview(infoPtr, LVN_HOTTRACK, &nmlv);
} }
return 0; return 0;
@ -9585,6 +9595,7 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, const CREATESTRUCTW *
infoPtr->iVersion = COMCTL32_VERSION; infoPtr->iVersion = COMCTL32_VERSION;
infoPtr->colRectsDirty = FALSE; infoPtr->colRectsDirty = FALSE;
infoPtr->selected_column = -1; infoPtr->selected_column = -1;
infoPtr->hHotCursor = LoadCursorW(NULL, (LPWSTR)IDC_HAND);
/* get default font (icon title) */ /* get default font (icon title) */
SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0); SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);

View file

@ -7255,6 +7255,19 @@ static void test_LVM_GETNEXTITEM(void)
DestroyWindow(hwnd); DestroyWindow(hwnd);
} }
static void test_LVM_GETHOTCURSOR(void)
{
HCURSOR cursor;
HWND hwnd;
hwnd = create_listview_control(LVS_REPORT);
cursor = (HCURSOR)SendMessageA(hwnd, LVM_GETHOTCURSOR, 0, 0);
ok(!!cursor, "Unexpected cursor %p.\n", cursor);
DestroyWindow(hwnd);
}
START_TEST(listview) START_TEST(listview)
{ {
ULONG_PTR ctx_cookie; ULONG_PTR ctx_cookie;
@ -7322,6 +7335,7 @@ START_TEST(listview)
test_LVM_SETBKIMAGE(FALSE); test_LVM_SETBKIMAGE(FALSE);
test_custom_sort(); test_custom_sort();
test_LVM_GETNEXTITEM(); test_LVM_GETNEXTITEM();
test_LVM_GETHOTCURSOR();
if (!load_v6_module(&ctx_cookie, &hCtx)) if (!load_v6_module(&ctx_cookie, &hCtx))
{ {
@ -7372,6 +7386,7 @@ START_TEST(listview)
test_LVM_GETNEXTITEMINDEX(); test_LVM_GETNEXTITEMINDEX();
test_LVM_GETNEXTITEM(); test_LVM_GETNEXTITEM();
test_LVM_SETBKIMAGE(TRUE); test_LVM_SETBKIMAGE(TRUE);
test_LVM_GETHOTCURSOR();
unload_v6_module(ctx_cookie, hCtx); unload_v6_module(ctx_cookie, hCtx);

View file

@ -300,20 +300,6 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
return ret; return ret;
} }
/******************************************************************
* invade_process
*
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
* this assumes that hProcess is a handle on a valid process
*/
static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
{
HANDLE hProcess = user;
SymLoadModuleExW(hProcess, 0, name, NULL, base, size, NULL, 0);
return TRUE;
}
const WCHAR *process_getenv(const struct process *process, const WCHAR *name) const WCHAR *process_getenv(const struct process *process, const WCHAR *name)
{ {
size_t name_len; size_t name_len;
@ -432,7 +418,10 @@ static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64)
TRACE("got debug info address %#I64x from PEB %p\n", base, pbi.PebBaseAddress); TRACE("got debug info address %#I64x from PEB %p\n", base, pbi.PebBaseAddress);
if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base)) if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base))
{
WARN("couldn't load process debug info at %#I64x\n", base); WARN("couldn't load process debug info at %#I64x\n", base);
pcs->loader = &empty_loader_ops;
}
return TRUE; return TRUE;
} }
@ -510,8 +499,9 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP
if (check_live_target(pcs, wow64, child_wow64)) if (check_live_target(pcs, wow64, child_wow64))
{ {
if (fInvadeProcess) if (fInvadeProcess)
EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess); module_refresh_list(pcs);
if (pcs->loader) pcs->loader->synchronize_module_list(pcs); else
pcs->loader->synchronize_module_list(pcs);
} }
else if (fInvadeProcess) else if (fInvadeProcess)
{ {

View file

@ -743,6 +743,7 @@ extern BOOL module_remove(struct process* pcs,
extern void module_set_module(struct module* module, const WCHAR* name); extern void module_set_module(struct module* module, const WCHAR* name);
extern WCHAR* get_wine_loader_name(struct process *pcs) __WINE_DEALLOC(HeapFree, 3) __WINE_MALLOC; extern WCHAR* get_wine_loader_name(struct process *pcs) __WINE_DEALLOC(HeapFree, 3) __WINE_MALLOC;
extern BOOL module_is_wine_host(const WCHAR* module_name, const WCHAR* ext); extern BOOL module_is_wine_host(const WCHAR* module_name, const WCHAR* ext);
extern BOOL module_refresh_list(struct process *pcs);
/* msc.c */ /* msc.c */
extern BOOL pe_load_debug_directory(const struct process* pcs, extern BOOL pe_load_debug_directory(const struct process* pcs,

View file

@ -1785,7 +1785,6 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs, ULONG_PTR addr)
{ {
ERR("Unable to access ELF libraries (outside 32bit limit)\n"); ERR("Unable to access ELF libraries (outside 32bit limit)\n");
module_remove(pcs, elf_info.module); module_remove(pcs, elf_info.module);
pcs->loader = &empty_loader_ops;
return FALSE; return FALSE;
} }
TRACE("Found ELF debug header %#I64x\n", elf_info.dbg_hdr_addr); TRACE("Found ELF debug header %#I64x\n", elf_info.dbg_hdr_addr);

View file

@ -24,6 +24,8 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h" #include "dbghelp_private.h"
#include "image_private.h" #include "image_private.h"
#include "psapi.h" #include "psapi.h"
@ -1317,7 +1319,11 @@ BOOL WINAPI EnumerateLoadedModulesW64(HANDLE process,
size_t sysdir_len = 0, wowdir_len = 0; size_t sysdir_len = 0, wowdir_len = 0;
/* process might not be a handle to a live process */ /* process might not be a handle to a live process */
if (!IsWow64Process2(process, &pcs_machine, &native_machine)) return FALSE; if (!IsWow64Process2(process, &pcs_machine, &native_machine))
{
SetLastError(STATUS_INVALID_CID);
return FALSE;
}
with_32bit_modules = sizeof(void*) > sizeof(int) && with_32bit_modules = sizeof(void*) > sizeof(int) &&
pcs_machine != IMAGE_FILE_MACHINE_UNKNOWN && pcs_machine != IMAGE_FILE_MACHINE_UNKNOWN &&
(dbghelp_options & SYMOPT_INCLUDE_32BIT_MODULES); (dbghelp_options & SYMOPT_INCLUDE_32BIT_MODULES);
@ -1600,18 +1606,41 @@ void module_reset_debug_info(struct module* module)
module->sources = NULL; module->sources = NULL;
} }
static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
{
HANDLE hProcess = user;
/* Note: this follows native behavior:
* If a PE module has been unloaded from debuggee, it's not immediately removed
* from module list in dbghelp.
* Removal may eventually happen when loading a another module with SymLoadModule:
* if the module to be loaded overlaps an existing one, SymLoadModule will
* automatically unload the eldest one.
*/
SymLoadModuleExW(hProcess, 0, name, NULL, base, size, NULL, 0);
return TRUE;
}
BOOL module_refresh_list(struct process *pcs)
{
BOOL ret;
ret = pcs->loader->synchronize_module_list(pcs);
ret = EnumerateLoadedModulesW64(pcs->handle, process_invade_cb, pcs->handle) && ret;
return ret;
}
/****************************************************************** /******************************************************************
* SymRefreshModuleList (DBGHELP.@) * SymRefreshModuleList (DBGHELP.@)
*/ */
BOOL WINAPI SymRefreshModuleList(HANDLE hProcess) BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
{ {
struct process* pcs; struct process *pcs;
TRACE("(%p)\n", hProcess); TRACE("(%p)\n", hProcess);
if (!(pcs = process_find_by_handle(hProcess))) return FALSE; if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
return module_refresh_list(pcs);
return pcs->loader->synchronize_module_list(pcs);
} }
/*********************************************************************** /***********************************************************************

View file

@ -4379,7 +4379,13 @@ static BOOL codeview_process_info(const struct process *pcs,
TRACE("Got RSDS type of PDB file: guid=%s age=%08x name=%s\n", TRACE("Got RSDS type of PDB file: guid=%s age=%08x name=%s\n",
wine_dbgstr_guid(&rsds->guid), rsds->age, debugstr_a(rsds->name)); wine_dbgstr_guid(&rsds->guid), rsds->age, debugstr_a(rsds->name));
/* gcc/mingw and clang can emit build-id information, but with an empty PDB filename.
* Don't search for the .pdb file in that case.
*/
if (rsds->name[0])
ret = pdb_process_file(pcs, msc_dbg, rsds->name, &rsds->guid, 0, rsds->age); ret = pdb_process_file(pcs, msc_dbg, rsds->name, &rsds->guid, 0, rsds->age);
else
ret = TRUE;
break; break;
} }
default: default:
@ -4487,7 +4493,7 @@ typedef struct _FPO_DATA
__ENDTRY __ENDTRY
/* we haven't found yet any debug information, fallback to unmatched pdb */ /* we haven't found yet any debug information, fallback to unmatched pdb */
if (module->module.SymType == SymDeferred) if (!ret && module->module.SymType == SymDeferred)
{ {
SYMSRV_INDEX_INFOW info = {.sizeofstruct = sizeof(info)}; SYMSRV_INDEX_INFOW info = {.sizeofstruct = sizeof(info)};
char buffer[MAX_PATH]; char buffer[MAX_PATH];
@ -4549,38 +4555,35 @@ DWORD msc_get_file_indexinfo(void* image, const IMAGE_DEBUG_DIRECTORY* debug_dir
num_misc_records++; num_misc_records++;
} }
} }
return info->stripped && !num_misc_records ? ERROR_BAD_EXE_FORMAT : ERROR_SUCCESS; return (!num_dir || (info->stripped && !num_misc_records)) ? ERROR_BAD_EXE_FORMAT : ERROR_SUCCESS;
} }
DWORD dbg_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info) DWORD dbg_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info)
{ {
const IMAGE_SEPARATE_DEBUG_HEADER *header; const IMAGE_SEPARATE_DEBUG_HEADER *header;
IMAGE_DEBUG_DIRECTORY *dbg;
DWORD num_directories; DWORD num_directories;
if (size < sizeof(*header)) return ERROR_BAD_EXE_FORMAT; if (size < sizeof(*header)) return ERROR_BAD_FORMAT;
header = image; header = image;
if (header->Signature != 0x4944 /* DI */ || if (header->Signature != 0x4944 /* DI */ ||
size < sizeof(*header) + header->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + header->ExportedNamesSize + header->DebugDirectorySize) size < sizeof(*header) + header->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + header->ExportedNamesSize + header->DebugDirectorySize)
return ERROR_BAD_EXE_FORMAT; return ERROR_BAD_FORMAT;
info->size = header->SizeOfImage;
/* seems to use header's timestamp, not debug_directory one */
info->timestamp = header->TimeDateStamp;
info->stripped = FALSE; /* FIXME */
/* header is followed by: /* header is followed by:
* - header->NumberOfSections of IMAGE_SECTION_HEADER * - header->NumberOfSections of IMAGE_SECTION_HEADER
* - header->ExportedNameSize * - header->ExportedNameSize
* - then num_directories of IMAGE_DEBUG_DIRECTORY * - then num_directories of IMAGE_DEBUG_DIRECTORY
*/ */
dbg = (IMAGE_DEBUG_DIRECTORY*)((char*)(header + 1) +
header->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
header->ExportedNamesSize);
num_directories = header->DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY); num_directories = header->DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
if (!num_directories) return ERROR_BAD_EXE_FORMAT; return msc_get_file_indexinfo(image, dbg, num_directories, info);
info->age = 0;
memset(&info->guid, 0, sizeof(info->guid));
info->sig = 0;
info->dbgfile[0] = L'\0';
info->pdbfile[0] = L'\0';
info->size = header->SizeOfImage;
/* seems to use header's timestamp, not debug_directory one */
info->timestamp = header->TimeDateStamp;
info->stripped = FALSE; /* FIXME */
return ERROR_SUCCESS;
} }

View file

@ -832,7 +832,7 @@ BOOL WINAPI SymSrvGetFileIndexInfoW(const WCHAR *file, SYMSRV_INDEX_INFOW* info,
if (hMap) CloseHandle(hMap); if (hMap) CloseHandle(hMap);
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
if (ret == ERROR_SUCCESS) wcscpy(info->file, file_name(file)); /* overflow? */ if (ret == ERROR_SUCCESS || ret == ERROR_BAD_EXE_FORMAT) wcscpy(info->file, file_name(file)); /* overflow? */
SetLastError(ret); SetLastError(ret);
return ret == ERROR_SUCCESS; return ret == ERROR_SUCCESS;
} }

View file

@ -656,7 +656,7 @@ static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* mod
if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC || if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC ||
misc->DataType != IMAGE_DEBUG_MISC_EXENAME) misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
{ {
ERR("-Debug info stripped, but no .DBG file in module %s\n", WARN("-Debug info stripped, but no .DBG file in module %s\n",
debugstr_w(module->modulename)); debugstr_w(module->modulename));
} }
else else
@ -1019,7 +1019,7 @@ DWORD pe_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info)
if (!(nthdr = RtlImageNtHeader(image))) return ERROR_BAD_FORMAT; if (!(nthdr = RtlImageNtHeader(image))) return ERROR_BAD_FORMAT;
dbg = RtlImageDirectoryEntryToData(image, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &dirsize); dbg = RtlImageDirectoryEntryToData(image, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &dirsize);
if (!dbg || dirsize < sizeof(dbg)) return ERROR_BAD_EXE_FORMAT; if (!dbg) dirsize = 0;
/* fill in information from NT header */ /* fill in information from NT header */
info->timestamp = nthdr->FileHeader.TimeDateStamp; info->timestamp = nthdr->FileHeader.TimeDateStamp;

View file

@ -372,6 +372,29 @@ static unsigned get_native_module_count(HANDLE proc)
return count; return count;
} }
struct module_present
{
const WCHAR* module_name;
BOOL found;
};
static BOOL CALLBACK is_module_present_cb(const WCHAR* name, DWORD64 base, void* usr)
{
struct module_present* present = usr;
if (!wcsicmp(name, present->module_name))
{
present->found = TRUE;
return FALSE;
}
return TRUE;
}
static BOOL is_module_present(HANDLE proc, const WCHAR* module_name)
{
struct module_present present = { .module_name = module_name };
return SymEnumerateModulesW64(proc, is_module_present_cb, &present) && present.found;
}
struct nth_module struct nth_module
{ {
HANDLE proc; HANDLE proc;
@ -424,6 +447,28 @@ static BOOL wrapper_EnumerateLoadedModulesW64(HANDLE proc, PENUMLOADED_MODULES_C
return ret; return ret;
} }
/* wrapper around SymRefreshModuleList which sometimes fails (it's very likely implemented on top
* of EnumerateLoadedModulesW64 on native too)
*/
static BOOL wrapper_SymRefreshModuleList(HANDLE proc)
{
BOOL ret;
int retry;
int retry_count = !strcmp(winetest_platform, "wine") ? 1 : 5;
for (retry = retry_count - 1; retry >= 0; retry--)
{
ret = SymRefreshModuleList(proc);
if (ret || (GetLastError() != STATUS_INFO_LENGTH_MISMATCH && GetLastError() == STATUS_PARTIAL_COPY))
break;
Sleep(10);
}
if (retry + 1 < retry_count)
trace("used wrapper retry: ret=%d retry=%d top=%d\n", ret, retry, retry_count);
return ret;
}
static BOOL test_modules(void) static BOOL test_modules(void)
{ {
BOOL ret; BOOL ret;
@ -492,6 +537,7 @@ static BOOL test_modules(void)
ret = SymRefreshModuleList(dummy); ret = SymRefreshModuleList(dummy);
ok(!ret, "SymRefreshModuleList should have failed\n"); ok(!ret, "SymRefreshModuleList should have failed\n");
ok(GetLastError() == STATUS_INVALID_CID, "Unexpected last error %lx\n", GetLastError());
count = get_module_count(dummy); count = get_module_count(dummy);
ok(count == 0, "Unexpected count (%u instead of 0)\n", count); ok(count == 0, "Unexpected count (%u instead of 0)\n", count);
@ -825,6 +871,11 @@ static void test_loaded_modules(void)
ok(ret, "got error %lu\n", GetLastError()); ok(ret, "got error %lu\n", GetLastError());
strcat(buffer, "\\msinfo32.exe"); strcat(buffer, "\\msinfo32.exe");
/* testing invalid process handle */
ret = wrapper_EnumerateLoadedModulesW64((HANDLE)(ULONG_PTR)0xffffffc0, NULL, FALSE);
ok(!ret, "EnumerateLoadedModulesW64 should have failed\n");
ok(GetLastError() == STATUS_INVALID_CID, "Unexpected last error %lx\n", GetLastError());
/* testing with child process of different machines */ /* testing with child process of different machines */
ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
ok(ret, "CreateProcess failed: %lu\n", GetLastError()); ok(ret, "CreateProcess failed: %lu\n", GetLastError());
@ -885,9 +936,10 @@ static void test_loaded_modules(void)
pcskind = get_process_kind(pi.hProcess); pcskind = get_process_kind(pi.hProcess);
ret = SymRefreshModuleList(pi.hProcess); ret = wrapper_SymRefreshModuleList(pi.hProcess);
todo_wine_if(pcskind == PCSKIND_WOW64) ok(ret || broken(GetLastError() == STATUS_PARTIAL_COPY /* Win11 in some cases */ ||
ok(ret || broken(GetLastError() == STATUS_PARTIAL_COPY /* Win11 in some cases */), "SymRefreshModuleList failed: %lu\n", GetLastError()); GetLastError() == STATUS_INFO_LENGTH_MISMATCH /* Win11 in some cases */),
"SymRefreshModuleList failed: %lx\n", GetLastError());
if (!strcmp(winetest_platform, "wine")) if (!strcmp(winetest_platform, "wine"))
{ {
@ -945,8 +997,8 @@ static void test_loaded_modules(void)
"Wrong directory aggregation count %u %u\n", "Wrong directory aggregation count %u %u\n",
aggregation.count_systemdir, aggregation.count_wowdir); aggregation.count_systemdir, aggregation.count_wowdir);
} }
ret = SymRefreshModuleList(pi.hProcess); ret = wrapper_SymRefreshModuleList(pi.hProcess);
ok(ret, "SymRefreshModuleList failed: %lu\n", GetLastError()); ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
if (!strcmp(winetest_platform, "wine")) if (!strcmp(winetest_platform, "wine"))
{ {
@ -1007,8 +1059,8 @@ static void test_loaded_modules(void)
break; break;
} }
ret = SymRefreshModuleList(pi.hProcess); ret = wrapper_SymRefreshModuleList(pi.hProcess);
ok(ret, "SymRefreshModuleList failed: %lu\n", GetLastError()); ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
if (!strcmp(winetest_platform, "wine")) if (!strcmp(winetest_platform, "wine"))
{ {
@ -1529,6 +1581,75 @@ static void test_function_tables(void)
SymCleanup(GetCurrentProcess()); SymCleanup(GetCurrentProcess());
} }
static void test_refresh_modules(void)
{
BOOL ret;
unsigned count, count_current;
HMODULE hmod;
IMAGEHLP_MODULEW64 module_info = { .SizeOfStruct = sizeof(module_info) };
/* pick a DLL: which isn't already loaded by test, and that will not load other DLLs for deps */
static const WCHAR* unused_dll = L"psapi";
ret = SymInitialize(GetCurrentProcess(), 0, TRUE);
ok(ret, "SymInitialize failed: %lu\n", GetLastError());
count = get_module_count(GetCurrentProcess());
ok(count, "Unexpected module count %u\n", count);
ret = SymCleanup(GetCurrentProcess());
ok(ret, "SymCleanup failed: %lu\n", GetLastError());
ret = SymInitialize(GetCurrentProcess(), 0, FALSE);
ok(ret, "SymInitialize failed: %lu\n", GetLastError());
count_current = get_module_count(GetCurrentProcess());
ok(!count_current, "Unexpected module count %u\n", count_current);
ret = wrapper_SymRefreshModuleList(GetCurrentProcess());
ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
count_current = get_module_count(GetCurrentProcess());
ok(count == count_current, "Unexpected module count %u, %u\n", count, count_current);
hmod = GetModuleHandleW(unused_dll);
ok(hmod == NULL, "Expecting DLL %ls not be loaded\n", unused_dll);
hmod = LoadLibraryW(unused_dll);
ok(hmod != NULL, "LoadLibraryW failed: %lu\n", GetLastError());
count_current = get_module_count(GetCurrentProcess());
ok(count == count_current, "Unexpected module count %u, %u\n", count, count_current);
ret = is_module_present(GetCurrentProcess(), unused_dll);
ok(!ret, "Couldn't find module %ls\n", unused_dll);
ret = wrapper_SymRefreshModuleList(GetCurrentProcess());
ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
count_current = get_module_count(GetCurrentProcess());
ok(count + 1 == count_current, "Unexpected module count %u, %u\n", count, count_current);
ret = is_module_present(GetCurrentProcess(), unused_dll);
ok(ret, "Couldn't find module %ls\n", unused_dll);
ret = FreeLibrary(hmod);
ok(ret, "LoadLibraryW failed: %lu\n", GetLastError());
count_current = get_module_count(GetCurrentProcess());
ok(count + 1 == count_current, "Unexpected module count %u, %u\n", count, count_current);
ret = wrapper_SymRefreshModuleList(GetCurrentProcess());
ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
/* SymRefreshModuleList() doesn't remove the unloaded modules... */
count_current = get_module_count(GetCurrentProcess());
ok(count + 1 == count_current, "Unexpected module count %u != %u\n", count, count_current);
ret = is_module_present(GetCurrentProcess(), unused_dll);
ok(ret, "Couldn't find module %ls\n", unused_dll);
ret = SymCleanup(GetCurrentProcess());
ok(ret, "SymCleanup failed: %lu\n", GetLastError());
}
START_TEST(dbghelp) START_TEST(dbghelp)
{ {
BOOL ret; BOOL ret;
@ -1559,6 +1680,7 @@ START_TEST(dbghelp)
test_modules_overlap(); test_modules_overlap();
test_loaded_modules(); test_loaded_modules();
test_live_modules(); test_live_modules();
test_refresh_modules();
} }
test_function_tables(); test_function_tables();
} }

View file

@ -671,20 +671,22 @@ static BOOL create_test_pdb_ds(const WCHAR* pdb_name, const GUID* guid, DWORD ag
return TRUE; return TRUE;
} }
static BOOL create_test_dbg(const WCHAR* dbg_name, WORD machine, DWORD timestamp, DWORD size) static BOOL create_test_dbg(const WCHAR* dbg_name, WORD machine, DWORD charac, DWORD timestamp, DWORD size, struct debug_directory_blob *blob)
{ {
HANDLE hfile; HANDLE hfile;
/* minimalistic .dbg made of a header and a DEBUG_DIRECTORY without any data */ /* minimalistic .dbg made of a header and a DEBUG_DIRECTORY without any data */
const IMAGE_SEPARATE_DEBUG_HEADER header = {.Signature = 0x4944 /* DI */, IMAGE_SEPARATE_DEBUG_HEADER header =
.Flags = 0, .Machine = machine, .Characteristics = 0x010E, .TimeDateStamp = timestamp, {
.Signature = 0x4944 /* DI */,
.Flags = 0, .Machine = machine, .Characteristics = charac, .TimeDateStamp = timestamp,
.CheckSum = 0, .ImageBase = 0x00040000, .SizeOfImage = size, .NumberOfSections = 0, .CheckSum = 0, .ImageBase = 0x00040000, .SizeOfImage = size, .NumberOfSections = 0,
.ExportedNamesSize = 0, .DebugDirectorySize = sizeof(IMAGE_DEBUG_DIRECTORY)}; .ExportedNamesSize = 0, .DebugDirectorySize = 0
const IMAGE_DEBUG_DIRECTORY debug_dir = {.Characteristics = 0, .TimeDateStamp = timestamp + 1, };
.MajorVersion = 0, .MinorVersion = 0, .Type = IMAGE_DEBUG_TYPE_CODEVIEW, DWORD where, expected_size;
.SizeOfData = 0, .AddressOfRawData = 0,
.PointerToRawData = sizeof(header) + header.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + if (blob)
header.DebugDirectorySize}; header.DebugDirectorySize = sizeof(IMAGE_DEBUG_DIRECTORY);
hfile = CreateFileW(dbg_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0); hfile = CreateFileW(dbg_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
ok(hfile != INVALID_HANDLE_VALUE, "failed to create %ls err %lu\n", dbg_name, GetLastError()); ok(hfile != INVALID_HANDLE_VALUE, "failed to create %ls err %lu\n", dbg_name, GetLastError());
@ -692,8 +694,18 @@ static BOOL create_test_dbg(const WCHAR* dbg_name, WORD machine, DWORD timestamp
check_write_file(hfile, &header, sizeof(header)); check_write_file(hfile, &header, sizeof(header));
/* FIXME: 0 sections... as header.NumberOfSections */ /* FIXME: 0 sections... as header.NumberOfSections */
check_write_file(hfile, &debug_dir, sizeof(debug_dir)); if (blob)
ok(SetFilePointer(hfile, 0, NULL, FILE_CURRENT) == debug_dir.PointerToRawData, "mismatch\n"); {
where = SetFilePointer(hfile, 0, NULL, FILE_CURRENT);
blob->debug_directory.PointerToRawData = (blob->debug_directory.SizeOfData) ?
where + sizeof(IMAGE_DEBUG_DIRECTORY) : 0;
check_write_file(hfile, &blob->debug_directory, sizeof(IMAGE_DEBUG_DIRECTORY));
check_write_file(hfile, blob->content, blob->debug_directory.SizeOfData);
}
expected_size = sizeof(header) + header.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (blob)
expected_size += sizeof(IMAGE_DEBUG_DIRECTORY) + blob->debug_directory.SizeOfData;
ok(SetFilePointer(hfile, 0, NULL, FILE_CURRENT) == expected_size, "Incorrect file length\n");
CloseHandle(hfile); CloseHandle(hfile);
return TRUE; return TRUE;
@ -725,16 +737,16 @@ static void test_srvgetindexes_pe(void)
DWORD sig; DWORD sig;
WCHAR pdb_name[16]; WCHAR pdb_name[16];
WCHAR dbg_name[16]; WCHAR dbg_name[16];
BOOL in_error; DWORD last_error;
} }
indexes[] = indexes[] =
{ {
/* error cases */ /* error cases */
/* 0 */{0, {-1, -1, -1}, .in_error = TRUE}, /* 0 */{0, {-1, -1, -1}, 0, &null_guid, 0, .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_DEBUG_STRIPPED, { 0, -1, -1}, .in_error = TRUE}, {IMAGE_FILE_DEBUG_STRIPPED, { 0, -1, -1}, 0, &null_guid, 0, .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_DEBUG_STRIPPED, { 1, -1, -1}, .in_error = TRUE}, {IMAGE_FILE_DEBUG_STRIPPED, { 1, -1, -1}, 123, &null_guid, 0xaaaabbbb, .pdb_name = L"pdbjg.pdb", .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_DEBUG_STRIPPED, { 2, -1, -1}, .in_error = TRUE}, {IMAGE_FILE_DEBUG_STRIPPED, { 2, -1, -1}, 124, &guid1, 0, .pdb_name = L"pdbds.pdb", .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_DEBUG_STRIPPED, {-1, -1, -1}, .in_error = TRUE}, /* not 100% logical ! */ {IMAGE_FILE_DEBUG_STRIPPED, {-1, -1, -1}, 0, &null_guid, 0, .last_error = ERROR_BAD_EXE_FORMAT}, /* not 100% logical ! */
/* success */ /* success */
/* 5 */{0, { 0, -1, -1}, 0, &null_guid, 0 }, /* 5 */{0, { 0, -1, -1}, 0, &null_guid, 0 },
{0, { 1, -1, -1}, 123, &null_guid, 0xaaaabbbb, .pdb_name = L"pdbjg.pdb"}, {0, { 1, -1, -1}, 123, &null_guid, 0xaaaabbbb, .pdb_name = L"pdbjg.pdb"},
@ -796,16 +808,16 @@ static void test_srvgetindexes_pe(void)
memset(&ssii, 0xa5, sizeof(ssii)); memset(&ssii, 0xa5, sizeof(ssii));
ssii.sizeofstruct = sizeof(ssii); ssii.sizeofstruct = sizeof(ssii);
ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0); ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0);
if (indexes[i].in_error) if (indexes[i].last_error)
{ {
ok(!ret, "SymSrvGetFileIndexInfo should have failed\n"); ok(!ret, "SymSrvGetFileIndexInfo should have failed\n");
ok(GetLastError() == ERROR_BAD_EXE_FORMAT, "Mismatch in GetLastError: %lu\n", GetLastError()); ok(GetLastError() == indexes[i].last_error, "Mismatch in GetLastError: %lu\n", GetLastError());
} }
else else
{
ok(ret, "SymSrvGetFileIndexInfo failed: %lu\n", GetLastError()); ok(ret, "SymSrvGetFileIndexInfo failed: %lu\n", GetLastError());
if (ret || indexes[i].last_error == ERROR_BAD_EXE_FORMAT)
ok(ssii.age == indexes[i].age, "Mismatch in age: %lx\n", ssii.age); {
ok(ssii.age == indexes[i].age, "Mismatch in age: %lu\n", ssii.age);
ok(IsEqualGUID(&ssii.guid, indexes[i].guid), ok(IsEqualGUID(&ssii.guid, indexes[i].guid),
"Mismatch in guid: guid=%s\n", wine_dbgstr_guid(&ssii.guid)); "Mismatch in guid: guid=%s\n", wine_dbgstr_guid(&ssii.guid));
@ -882,48 +894,69 @@ static void test_srvgetindexes_dbg(void)
WCHAR filename[128]; WCHAR filename[128];
SYMSRV_INDEX_INFOW ssii; SYMSRV_INDEX_INFOW ssii;
BOOL ret; BOOL ret;
struct debug_directory_blob *blob_refs[1];
static struct static struct
{ {
/* input parameters */ /* input parameters */
WORD machine; WORD machine;
DWORD characteristics;
DWORD timestamp; DWORD timestamp;
DWORD imagesize; DWORD imagesize;
int blob;
/* output parameters */
DWORD age;
const GUID *guid;
WCHAR pdbname[16];
WCHAR dbgname[16];
DWORD last_error;
} }
indexes[] = indexes[] =
{ {
{IMAGE_FILE_MACHINE_I386, 0x1234, 0x00560000}, {IMAGE_FILE_MACHINE_I386, 0, 0x1234, 0x00560000, -1, 0, &null_guid, .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_MACHINE_AMD64, 0x1235, 0x00570000}, {IMAGE_FILE_MACHINE_AMD64, 0, 0x1235, 0x00570000, -1, 0, &null_guid, .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_MACHINE_I386, 0, 0x1234, 0x00560000, 0, 123, &guid1, .pdbname=L"foo.pdb"},
{IMAGE_FILE_MACHINE_AMD64, 0, 0x1235, 0x00570000, 0, 123, &guid1, .pdbname=L"foo.pdb"},
}; };
blob_refs[0] = make_pdb_ds_blob(0x1226, &guid1, 123, "foo.pdb");
for (i = 0; i < ARRAY_SIZE(indexes); i++) for (i = 0; i < ARRAY_SIZE(indexes); i++)
{ {
winetest_push_context("dbg#%02u", i); winetest_push_context("dbg#%02u", i);
/* create dll */ /* create dll */
swprintf(filename, ARRAY_SIZE(filename), L"winetest%02u.dbg", i); swprintf(filename, ARRAY_SIZE(filename), L"winetest%02u.dbg", i);
ret = create_test_dbg(filename, indexes[i].machine, indexes[i].timestamp, indexes[i].imagesize); ret = create_test_dbg(filename, indexes[i].machine, indexes[i].characteristics,
indexes[i].timestamp, indexes[i].imagesize,
indexes[i].blob == -1 ? NULL : blob_refs[indexes[i].blob]);
ok(ret, "Couldn't create dbg file %ls\n", filename); ok(ret, "Couldn't create dbg file %ls\n", filename);
memset(&ssii, 0x45, sizeof(ssii)); memset(&ssii, 0x45, sizeof(ssii));
ssii.sizeofstruct = sizeof(ssii); ssii.sizeofstruct = sizeof(ssii);
ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0); ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0);
if (indexes[i].last_error)
{
ok(!ret, "SymSrvGetFileIndexInfo should have\n");
ok(GetLastError() == ERROR_BAD_EXE_FORMAT, "Unexpected last error: %lu\n", GetLastError());
}
else
ok(ret, "SymSrvGetFileIndexInfo failed: %lu\n", GetLastError()); ok(ret, "SymSrvGetFileIndexInfo failed: %lu\n", GetLastError());
ok(ssii.age == 0, "Mismatch in age: %lx\n", ssii.age); ok(ssii.age == indexes[i].age, "Mismatch in age: %lx\n", ssii.age);
ok(!memcmp(&ssii.guid, &null_guid, sizeof(GUID)), ok(IsEqualGUID(&ssii.guid, indexes[i].guid),
"Mismatch in guid: guid=%s\n", wine_dbgstr_guid(&ssii.guid)); "Mismatch in guid: guid=%s\n", wine_dbgstr_guid(&ssii.guid));
ok(ssii.sig == 0, "Mismatch in sig: %lx\n", ssii.sig); ok(ssii.sig == 0, "Mismatch in sig: %lx\n", ssii.sig);
ok(ssii.size == indexes[i].imagesize, "Mismatch in size: %lx\n", ssii.size); ok(ssii.size == indexes[i].imagesize, "Mismatch in size: %lx\n", ssii.size);
ok(!ssii.stripped, "Mismatch in stripped: %x\n", ssii.stripped); ok(!ssii.stripped, "Mismatch in stripped: %x\n", ssii.stripped);
ok(ssii.timestamp == indexes[i].timestamp, "Mismatch in timestamp: %lx\n", ssii.timestamp); ok(ssii.timestamp == indexes[i].timestamp, "Mismatch in timestamp: %lx\n", ssii.timestamp);
ok(!wcscmp(ssii.file, filename), "Mismatch in file: %ls\n", ssii.file); ok(!wcscmp(ssii.file, filename), "Mismatch in file: %ls\n", ssii.file);
ok(!ssii.pdbfile[0], "Mismatch in pdbfile: %ls\n", ssii.pdbfile); ok(!wcscmp(ssii.pdbfile, indexes[i].pdbname), "Mismatch in pdbfile: %ls\n", ssii.pdbfile);
ok(!ssii.dbgfile[0], "Mismatch in dbgfile: %ls\n", ssii.dbgfile); ok(!wcscmp(ssii.dbgfile, indexes[i].dbgname), "Mismatch in dbgfile: %ls\n", ssii.dbgfile);
DeleteFileW(filename); DeleteFileW(filename);
winetest_pop_context(); winetest_pop_context();
} }
for (i = 0; i < ARRAY_SIZE(blob_refs); i++) free(blob_refs[i]);
} }
static void make_path(WCHAR file[MAX_PATH], const WCHAR* topdir, const WCHAR* subdir, const WCHAR* base) static void make_path(WCHAR file[MAX_PATH], const WCHAR* topdir, const WCHAR* subdir, const WCHAR* base)
@ -1533,7 +1566,8 @@ static void test_load_modules_path(void)
if (test_files[val].guid) if (test_files[val].guid)
create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp); create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp);
else else
create_test_dbg(filename, IMAGE_FILE_MACHINE_AMD64 /* FIXME */, test_files[val].age_or_timestamp, 0x40000 * val * 0x20000); /*create_test_dbg(filename, IMAGE_FILE_MACHINE_AMD64, 0x10E, test_files[val].age_or_timestamp, 0x40000 * val * 0x20000, blob); */
ok(0, "not supported yet\n");
} }
else ok(0, "Unrecognized file reference %c\n", *ptr); else ok(0, "Unrecognized file reference %c\n", *ptr);
} }
@ -1754,7 +1788,7 @@ static void test_load_modules_details(void)
if (test_files[val].guid) if (test_files[val].guid)
create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp); create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp);
else else
create_test_dbg(filename, IMAGE_FILE_MACHINE_AMD64 /* FIXME */, test_files[val].age_or_timestamp, 0x40000 * val * 0x20000); create_test_dbg(filename, IMAGE_FILE_MACHINE_AMD64 /* FIXME */, 0x10E, test_files[val].age_or_timestamp, 0x40000 * val * 0x20000, NULL);
} }
else ok(0, "Unrecognized file reference %c\n", *ptr); else ok(0, "Unrecognized file reference %c\n", *ptr);
} }

View file

@ -306,20 +306,13 @@ static void warp_check( struct mouse *impl, BOOL force )
if (force || (impl->need_warp && (now - impl->last_warped > interval))) if (force || (impl->need_warp && (now - impl->last_warped > interval)))
{ {
RECT rect, new_rect;
POINT mapped_center; POINT mapped_center;
RECT rect;
impl->last_warped = now; impl->last_warped = now;
impl->need_warp = FALSE; impl->need_warp = FALSE;
if (!GetClientRect( impl->base.win, &rect )) return; if (!GetClientRect( impl->base.win, &rect )) return;
MapWindowPoints( impl->base.win, 0, (POINT *)&rect, 2 ); MapWindowPoints( impl->base.win, 0, (POINT *)&rect, 2 );
if (!impl->clipped)
{
mapped_center.x = (rect.left + rect.right) / 2;
mapped_center.y = (rect.top + rect.bottom) / 2;
TRACE( "Warping mouse to x %+ld, y %+ld.\n", mapped_center.x, mapped_center.y );
SetCursorPos( mapped_center.x, mapped_center.y );
}
if (impl->base.dwCoopLevel & DISCL_EXCLUSIVE) if (impl->base.dwCoopLevel & DISCL_EXCLUSIVE)
{ {
/* make sure we clip even if the window covers the whole screen */ /* make sure we clip even if the window covers the whole screen */
@ -328,8 +321,14 @@ static void warp_check( struct mouse *impl, BOOL force )
rect.right = min( rect.right, rect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN ) - 2 ); rect.right = min( rect.right, rect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN ) - 2 );
rect.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 ); rect.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 );
TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect )); TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect ));
ClipCursor( &rect ); impl->clipped = ClipCursor( &rect );
impl->clipped = GetClipCursor( &new_rect ) && EqualRect( &rect, &new_rect ); }
if (!impl->clipped)
{
mapped_center.x = (rect.left + rect.right) / 2;
mapped_center.y = (rect.top + rect.bottom) / 2;
TRACE( "Warping mouse to x %+ld, y %+ld.\n", mapped_center.x, mapped_center.y );
SetCursorPos( mapped_center.x, mapped_center.y );
} }
} }
} }

View file

@ -1281,17 +1281,28 @@ static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
return hr; return hr;
} }
static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName, HRESULT DP_CreateGroup( IDirectPlayImpl *This, void *msgHeader, const DPID *lpid,
DWORD dwFlags, DPID idParent, BOOL bAnsi ) const DPNAME *lpName, void *data, DWORD dataSize, DWORD dwFlags, DPID idParent,
BOOL bAnsi )
{ {
struct GroupList *groupList = NULL;
struct GroupData *parent = NULL;
lpGroupData lpGData; lpGroupData lpGData;
HRESULT hr;
if( DPID_SYSTEM_GROUP != *lpid )
{
parent = DP_FindAnyGroup( This, idParent );
if( !parent )
return DPERR_INVALIDGROUP;
}
/* Allocate the new space and add to end of high level group list */ /* Allocate the new space and add to end of high level group list */
lpGData = calloc( 1, sizeof( *lpGData ) ); lpGData = calloc( 1, sizeof( *lpGData ) );
if( lpGData == NULL ) if( lpGData == NULL )
{ {
return NULL; return DPERR_OUTOFMEMORY;
} }
DPQ_INIT(lpGData->groups); DPQ_INIT(lpGData->groups);
@ -1304,7 +1315,7 @@ static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, cons
if ( !lpGData->name ) if ( !lpGData->name )
{ {
free( lpGData ); free( lpGData );
return NULL; return DPERR_OUTOFMEMORY;
} }
lpGData->nameA = DP_DuplicateName( lpName, TRUE, bAnsi ); lpGData->nameA = DP_DuplicateName( lpName, TRUE, bAnsi );
@ -1312,10 +1323,9 @@ static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, cons
{ {
free( lpGData->name ); free( lpGData->name );
free( lpGData ); free( lpGData );
return NULL; return DPERR_OUTOFMEMORY;
} }
/* FIXME: Should we check that the parent exists? */
lpGData->parent = idParent; lpGData->parent = idParent;
/* FIXME: Should we validate the dwFlags? */ /* FIXME: Should we validate the dwFlags? */
@ -1328,12 +1338,83 @@ static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, cons
free( lpGData->nameA ); free( lpGData->nameA );
free( lpGData->name ); free( lpGData->name );
free( lpGData ); free( lpGData );
return NULL; return DPERR_OUTOFMEMORY;
}
if( DPID_SYSTEM_GROUP == *lpid )
{
This->dp2->lpSysGroup = lpGData;
TRACE( "Inserting system group\n" );
}
else
{
/* Insert into the parent group */
groupList = calloc( 1, sizeof( *groupList ) );
if( !groupList )
{
free( lpGData->nameA );
free( lpGData->name );
free( lpGData );
return DPERR_OUTOFMEMORY;
}
groupList->lpGData = lpGData;
DPQ_INSERT( parent->groups, groupList, groups );
}
/* Something is now referencing this data */
lpGData->uRef++;
DP_SetGroupData( lpGData, DPSET_REMOTE, data, dataSize );
/* FIXME: We should only create the system group if GetCaps returns
* DPCAPS_GROUPOPTIMIZED.
*/
/* Let the SP know that we've created this group */
if( This->dp2->spData.lpCB->CreateGroup )
{
DPSP_CREATEGROUPDATA data;
DWORD dwCreateFlags = 0;
TRACE( "Calling SP CreateGroup\n" );
if( !parent )
dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
if( !msgHeader )
dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
if( dwFlags & DPGROUP_HIDDEN )
dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
data.idGroup = *lpid;
data.dwFlags = dwCreateFlags;
data.lpSPMessageHeader = msgHeader;
data.lpISP = This->dp2->spData.lpISP;
hr = (*This->dp2->spData.lpCB->CreateGroup)( &data );
if( FAILED( hr ) )
{
if( groupList )
{
DPQ_REMOVE( parent->groups, groupList, groups );
free( groupList );
}
else
{
This->dp2->lpSysGroup = NULL;
}
free( lpGData->nameA );
free( lpGData->name );
free( lpGData );
return hr;
}
} }
TRACE( "Created group id 0x%08lx\n", *lpid ); TRACE( "Created group id 0x%08lx\n", *lpid );
return lpGData; return DP_OK;
} }
/* This method assumes that all links to it are already deleted */ /* This method assumes that all links to it are already deleted */
@ -1394,7 +1475,7 @@ static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid )
static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup, static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup,
DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi ) DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
{ {
lpGroupData lpGData; HRESULT hr;
TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
@ -1421,61 +1502,12 @@ static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *l
} }
} }
lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags, hr = DP_CreateGroup( This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
DPID_NOPARENT_GROUP, bAnsi ); DPID_NOPARENT_GROUP, bAnsi );
if( lpGData == NULL ) if( FAILED( hr ) )
{ {
return DPERR_CANTADDPLAYER; /* yes player not group */ return hr;
}
if( DPID_SYSTEM_GROUP == *lpidGroup )
{
This->dp2->lpSysGroup = lpGData;
TRACE( "Inserting system group\n" );
}
else
{
/* Insert into the system group */
lpGroupList lpGroup = calloc( 1, sizeof( *lpGroup ) );
lpGroup->lpGData = lpGData;
DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
}
/* Something is now referencing this data */
lpGData->uRef++;
/* Set all the important stuff for the group */
DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
/* FIXME: We should only create the system group if GetCaps returns
* DPCAPS_GROUPOPTIMIZED.
*/
/* Let the SP know that we've created this group */
if( This->dp2->spData.lpCB->CreateGroup )
{
DPSP_CREATEGROUPDATA data;
DWORD dwCreateFlags = 0;
TRACE( "Calling SP CreateGroup\n" );
if( *lpidGroup == DPID_NOPARENT_GROUP )
dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
if( lpMsgHdr == NULL )
dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
if( dwFlags & DPGROUP_HIDDEN )
dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
data.idGroup = *lpidGroup;
data.dwFlags = dwCreateFlags;
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
(*This->dp2->spData.lpCB->CreateGroup)( &data );
} }
/* Inform all other peers of the creation of a new group. If there are /* Inform all other peers of the creation of a new group. If there are
@ -4458,9 +4490,7 @@ static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr,
DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags,
BOOL bAnsi ) BOOL bAnsi )
{ {
lpGroupData lpGParentData; HRESULT hr;
lpGroupList lpGList;
lpGroupData lpGData;
TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n", TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
This, idParentGroup, lpidGroup, lpGroupName, lpData, This, idParentGroup, lpidGroup, lpGroupName, lpData,
@ -4471,48 +4501,12 @@ static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr,
return DPERR_UNINITIALIZED; return DPERR_UNINITIALIZED;
} }
/* Verify that the specified parent is valid */ hr = DP_CreateGroup(This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL ) idParentGroup, bAnsi );
return DPERR_INVALIDGROUP;
lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi ); if( FAILED( hr ) )
if( lpGData == NULL )
{ {
return DPERR_CANTADDPLAYER; /* yes player not group */ return hr;
}
/* Something else is referencing this data */
lpGData->uRef++;
DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
/* The list has now been inserted into the interface group list. We now
need to put a "shortcut" to this group in the parent group */
lpGList = calloc( 1, sizeof( *lpGList ) );
if( lpGList == NULL )
{
FIXME( "Memory leak\n" );
return DPERR_CANTADDPLAYER; /* yes player not group */
}
lpGList->lpGData = lpGData;
DPQ_INSERT( lpGParentData->groups, lpGList, groups );
/* Let the SP know that we've created this group */
if( This->dp2->spData.lpCB->CreateGroup )
{
DPSP_CREATEGROUPDATA data;
TRACE( "Calling SP CreateGroup\n" );
data.idGroup = *lpidGroup;
data.dwFlags = dwFlags;
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
(*This->dp2->spData.lpCB->CreateGroup)( &data );
} }
/* Inform all other peers of the creation of a new group. If there are /* Inform all other peers of the creation of a new group. If there are

View file

@ -218,6 +218,9 @@ HRESULT DP_HandleGameMessage( IDirectPlayImpl *This, void *messageBody, DWORD me
HRESULT DP_CreatePlayer( IDirectPlayImpl *This, void *msgHeader, DPID *lpid, DPNAME *lpName, HRESULT DP_CreatePlayer( IDirectPlayImpl *This, void *msgHeader, DPID *lpid, DPNAME *lpName,
void *data, DWORD dataSize, void *spData, DWORD spDataSize, DWORD dwFlags, void *data, DWORD dataSize, void *spData, DWORD spDataSize, DWORD dwFlags,
HANDLE hEvent, struct PlayerData **playerData, BOOL bAnsi ); HANDLE hEvent, struct PlayerData **playerData, BOOL bAnsi );
HRESULT DP_CreateGroup( IDirectPlayImpl *This, void *msgHeader, const DPID *lpid,
const DPNAME *lpName, void *data, DWORD dataSize, DWORD dwFlags,
DPID idParent, BOOL bAnsi );
/* DP SP external interfaces into DirectPlay */ /* DP SP external interfaces into DirectPlay */
extern HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData ); extern HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData );

View file

@ -676,6 +676,30 @@ HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlayImpl *This, DPID dpidServer, WC
return hr; return hr;
} }
} }
for( i = 0; i < enumPlayersReply->groupCount; ++i )
{
DPPLAYERINFO playerInfo;
hr = DP_MSG_ReadSuperPackedPlayer( (char *) enumPlayersReply, &offset, dwMsgSize,
&playerInfo );
if( FAILED( hr ) )
{
free( msgHeader );
free( lpMsg );
return hr;
}
hr = DP_CreateGroup( This, msgHeader, &playerInfo.id, &playerInfo.name,
playerInfo.playerData, playerInfo.playerDataLength,
playerInfo.flags & ~DPLAYI_PLAYER_PLAYERLOCAL, playerInfo.parentId,
FALSE );
if( FAILED( hr ) )
{
free( msgHeader );
free( lpMsg );
return hr;
}
}
} }
else if( envelope->wCommandId == DPMSGCMD_GETNAMETABLEREPLY ) else if( envelope->wCommandId == DPMSGCMD_GETNAMETABLEREPLY )
{ {

View file

@ -1224,12 +1224,14 @@ static void checkGameMessage_( int line, GameMessage *message, DPID expectedFrom
static unsigned short receiveEnumSessionsRequest_( int line, SOCKET sock, const GUID *expectedAppGuid, static unsigned short receiveEnumSessionsRequest_( int line, SOCKET sock, const GUID *expectedAppGuid,
const WCHAR *expectedPassword, DWORD expectedFlags ) const WCHAR *expectedPassword, DWORD expectedFlags )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
EnumSessionsRequest request; EnumSessionsRequest request;
WCHAR password[ 256 ]; WCHAR password[ 256 ];
} request; } request;
#include "poppack.h"
DWORD expectedPasswordSize; DWORD expectedPasswordSize;
unsigned short port; unsigned short port;
DWORD expectedSize; DWORD expectedSize;
@ -1267,6 +1269,7 @@ static unsigned short receiveEnumSessionsRequest_( int line, SOCKET sock, const
#define sendEnumSessionsReply( sock, port, dpsd ) sendEnumSessionsReply_( __LINE__, sock, port, dpsd ) #define sendEnumSessionsReply( sock, port, dpsd ) sendEnumSessionsReply_( __LINE__, sock, port, dpsd )
static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port, const DPSESSIONDESC2 *dpsd ) static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port, const DPSESSIONDESC2 *dpsd )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -1295,6 +1298,7 @@ static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port,
.nameOffset = sizeof( reply.reply ), .nameOffset = sizeof( reply.reply ),
}, },
}; };
#include "poppack.h"
DWORD passwordSize; DWORD passwordSize;
int wsResult; int wsResult;
DWORD size; DWORD size;
@ -1314,11 +1318,13 @@ static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port,
#define receiveRequestPlayerId( sock, expectedFlags, flagsTodo ) receiveRequestPlayerId_( __LINE__, sock, expectedFlags, flagsTodo ) #define receiveRequestPlayerId( sock, expectedFlags, flagsTodo ) receiveRequestPlayerId_( __LINE__, sock, expectedFlags, flagsTodo )
static unsigned short receiveRequestPlayerId_( int line, SOCKET sock, DWORD expectedFlags ) static unsigned short receiveRequestPlayerId_( int line, SOCKET sock, DWORD expectedFlags )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
RequestPlayerId request; RequestPlayerId request;
} request; } request;
#include "poppack.h"
unsigned short port; unsigned short port;
int wsResult; int wsResult;
@ -1335,6 +1341,7 @@ static unsigned short receiveRequestPlayerId_( int line, SOCKET sock, DWORD expe
#define sendRequestPlayerReply( sock, port, id, result ) sendRequestPlayerReply_( __LINE__, sock, port, id, result ) #define sendRequestPlayerReply( sock, port, id, result ) sendRequestPlayerReply_( __LINE__, sock, port, id, result )
static void sendRequestPlayerReply_( int line, SOCKET sock, unsigned short port, DPID id, HRESULT result ) static void sendRequestPlayerReply_( int line, SOCKET sock, unsigned short port, DPID id, HRESULT result )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -1362,6 +1369,7 @@ static void sendRequestPlayerReply_( int line, SOCKET sock, unsigned short port,
.result = result, .result = result,
}, },
}; };
#include "poppack.h"
int wsResult; int wsResult;
wsResult = send( sock, (char *) &reply, sizeof( reply ), 0 ); wsResult = send( sock, (char *) &reply, sizeof( reply ), 0 );
@ -1374,11 +1382,13 @@ static unsigned short receiveAddForwardRequest_( int line, SOCKET sock, DPID exp
const WCHAR *expectedPassword, DWORD expectedTickCount, const WCHAR *expectedPassword, DWORD expectedTickCount,
unsigned short *udpPort ) unsigned short *udpPort )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
AddForwardRequest request; AddForwardRequest request;
} request; } request;
#include "poppack.h"
DWORD expectedPasswordSize; DWORD expectedPasswordSize;
WCHAR password[ 256 ]; WCHAR password[ 256 ];
unsigned short port; unsigned short port;
@ -1427,25 +1437,53 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
{ {
#define SHORT_NAME L"short name" #define SHORT_NAME L"short name"
#define LONG_NAME L"long name" #define LONG_NAME L"long name"
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
SuperEnumPlayersReply reply; SuperEnumPlayersReply reply;
DPSESSIONDESC2 dpsd; DPSESSIONDESC2 dpsd;
WCHAR sessionName[ 256 ]; WCHAR sessionName[ 256 ];
SuperPackedPlayer superPackedPlayer0; struct
BYTE spDataLength0; {
SpData spData0; SuperPackedPlayer superPackedPlayer;
SuperPackedPlayer superPackedPlayer1; BYTE spDataLength;
BYTE spDataLength1; SpData spData;
SpData spData1; } player0;
SuperPackedPlayer superPackedPlayer2; struct
{
SuperPackedPlayer superPackedPlayer;
BYTE spDataLength;
SpData spData;
} player1;
struct
{
SuperPackedPlayer superPackedPlayer;
WCHAR shortName[ ARRAYSIZE( SHORT_NAME ) ]; WCHAR shortName[ ARRAYSIZE( SHORT_NAME ) ];
WCHAR longName[ ARRAYSIZE( LONG_NAME ) ]; WCHAR longName[ ARRAYSIZE( LONG_NAME ) ];
BYTE playerDataLength2; BYTE playerDataLength;
BYTE playerData[ 4 ]; BYTE playerData[ 4 ];
BYTE spDataLength2; BYTE spDataLength;
SpData spData2; SpData spData;
} player2;
struct
{
SuperPackedPlayer superPackedPlayer;
BYTE spDataLength;
SpData spData;
} player3;
struct
{
SuperPackedPlayer superPackedPlayer;
WCHAR shortName[ ARRAYSIZE( SHORT_NAME ) ];
WCHAR longName[ ARRAYSIZE( LONG_NAME ) ];
BYTE playerDataLength;
BYTE playerData[ 4 ];
BYTE spDataLength;
SpData spData;
BYTE playerCount;
DPID playerIds[ 1 ];
} group0;
} reply = } reply =
{ {
.spHeader = .spHeader =
@ -1465,8 +1503,8 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.command = 41, .command = 41,
.version = 14, .version = 14,
}, },
.playerCount = 3, .playerCount = 4,
.groupCount = 0, .groupCount = 1,
.packedOffset = sizeof( reply.reply ) + sizeof( reply.dpsd ) + sizeof( reply.sessionName ), .packedOffset = sizeof( reply.reply ) + sizeof( reply.dpsd ) + sizeof( reply.sessionName ),
.shortcutCount = 0, .shortcutCount = 0,
.descriptionOffset = sizeof( reply.reply ), .descriptionOffset = sizeof( reply.reply ),
@ -1474,7 +1512,9 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.passwordOffset = 0, .passwordOffset = 0,
}, },
.dpsd = *dpsd, .dpsd = *dpsd,
.superPackedPlayer0 = .player0 =
{
.superPackedPlayer =
{ {
.size = 16, .size = 16,
.flags = 0x5, .flags = 0x5,
@ -1482,8 +1522,8 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.infoMask = 0x4, .infoMask = 0x4,
.versionOrSystemPlayerId = 14, .versionOrSystemPlayerId = 14,
}, },
.spDataLength0 = sizeof( SpData ), .spDataLength = sizeof( SpData ),
.spData0 = .spData =
{ {
.tcpAddr = .tcpAddr =
{ {
@ -1496,7 +1536,10 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.sin_port = htons( udpPort ), .sin_port = htons( udpPort ),
}, },
}, },
.superPackedPlayer1 = },
.player1 =
{
.superPackedPlayer =
{ {
.size = 16, .size = 16,
.flags = 0xf, .flags = 0xf,
@ -1504,8 +1547,8 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.infoMask = 0x4, .infoMask = 0x4,
.versionOrSystemPlayerId = 14, .versionOrSystemPlayerId = 14,
}, },
.spDataLength1 = sizeof( SpData ), .spDataLength = sizeof( SpData ),
.spData1 = .spData =
{ {
.tcpAddr = .tcpAddr =
{ {
@ -1518,7 +1561,10 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.sin_port = htons( udpPort ), .sin_port = htons( udpPort ),
}, },
}, },
.superPackedPlayer2 = },
.player2 =
{
.superPackedPlayer =
{ {
.size = 16, .size = 16,
.flags = 0x8, .flags = 0x8,
@ -1528,10 +1574,10 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
}, },
.shortName = SHORT_NAME, .shortName = SHORT_NAME,
.longName = LONG_NAME, .longName = LONG_NAME,
.playerDataLength2 = 4, .playerDataLength = 4,
.playerData = { 1, 2, 3, 4, }, .playerData = { 1, 2, 3, 4, },
.spDataLength2 = sizeof( SpData ), .spDataLength = sizeof( SpData ),
.spData2 = .spData =
{ {
.tcpAddr = .tcpAddr =
{ {
@ -1544,7 +1590,65 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.sin_port = htons( udpPort ), .sin_port = htons( udpPort ),
}, },
}, },
},
.player3 =
{
.superPackedPlayer =
{
.size = 16,
.flags = 0x8,
.id = 0xd00de,
.infoMask = 0x4,
.versionOrSystemPlayerId = 0x51573,
},
.spDataLength = sizeof( SpData ),
.spData =
{
.tcpAddr =
{
.sin_family = AF_INET,
.sin_port = htons( tcpPort ),
},
.udpAddr =
{
.sin_family = AF_INET,
.sin_port = htons( udpPort ),
},
},
},
.group0 =
{
.superPackedPlayer =
{
.size = 16,
.flags = 0x48,
.id = 0x5e7,
.infoMask = 0x57,
.versionOrSystemPlayerId = 0x51573,
},
.shortName = SHORT_NAME,
.longName = LONG_NAME,
.playerDataLength = 4,
.playerData = { 1, 2, 3, 4, },
.spDataLength = sizeof( SpData ),
.spData =
{
.tcpAddr =
{
.sin_family = AF_INET,
.sin_port = htons( tcpPort ),
},
.udpAddr =
{
.sin_family = AF_INET,
.sin_port = htons( udpPort ),
},
},
.playerCount = 1,
.playerIds = { 0xd00de, },
},
}; };
#include "poppack.h"
#undef LONG_NAME #undef LONG_NAME
#undef SHORT_NAME #undef SHORT_NAME
int wsResult; int wsResult;
@ -1561,6 +1665,7 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
#define sendAddForwardReply( sock, port, result ) sendAddForwardReply_( __LINE__, sock, port, result ) #define sendAddForwardReply( sock, port, result ) sendAddForwardReply_( __LINE__, sock, port, result )
static void sendAddForwardReply_( int line, SOCKET sock, unsigned short port, HRESULT result ) static void sendAddForwardReply_( int line, SOCKET sock, unsigned short port, HRESULT result )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -1587,6 +1692,7 @@ static void sendAddForwardReply_( int line, SOCKET sock, unsigned short port, HR
.result = result, .result = result,
}, },
}; };
#include "poppack.h"
int wsResult; int wsResult;
wsResult = send( sock, (char *) &reply, sizeof( reply ), 0 ); wsResult = send( sock, (char *) &reply, sizeof( reply ), 0 );
@ -1596,6 +1702,7 @@ static void sendAddForwardReply_( int line, SOCKET sock, unsigned short port, HR
#define sendAddForward( sock, port, tcpPort, udpPort ) sendAddForward_( __LINE__, sock, port, tcpPort, udpPort ) #define sendAddForward( sock, port, tcpPort, udpPort ) sendAddForward_( __LINE__, sock, port, tcpPort, udpPort )
static void sendAddForward_( int line, SOCKET sock, unsigned short port, unsigned short tcpPort, unsigned short udpPort ) static void sendAddForward_( int line, SOCKET sock, unsigned short port, unsigned short tcpPort, unsigned short udpPort )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -1653,6 +1760,7 @@ static void sendAddForward_( int line, SOCKET sock, unsigned short port, unsigne
}, },
}, },
}; };
#include "poppack.h"
int wsResult; int wsResult;
@ -1663,11 +1771,13 @@ static void sendAddForward_( int line, SOCKET sock, unsigned short port, unsigne
#define receiveAddForwardAck( sock, expectedPlayerId ) receiveAddForwardAck_( __LINE__, sock, expectedPlayerId ) #define receiveAddForwardAck( sock, expectedPlayerId ) receiveAddForwardAck_( __LINE__, sock, expectedPlayerId )
static unsigned short receiveAddForwardAck_( int line, SOCKET sock, DPID expectedPlayerId ) static unsigned short receiveAddForwardAck_( int line, SOCKET sock, DPID expectedPlayerId )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
AddForwardAck request; AddForwardAck request;
} request; } request;
#include "poppack.h"
unsigned short port; unsigned short port;
int wsResult; int wsResult;
@ -1688,11 +1798,13 @@ static unsigned short receiveCreatePlayer_( int line, SOCKET sock, DPID expected
const WCHAR *expectedShortName, const WCHAR *expectedLongName, const WCHAR *expectedShortName, const WCHAR *expectedLongName,
void *expectedPlayerData, DWORD expectedPlayerDataSize ) void *expectedPlayerData, DWORD expectedPlayerDataSize )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
CreatePlayer request; CreatePlayer request;
} request; } request;
#include "poppack.h"
DWORD expectedShortNameSize; DWORD expectedShortNameSize;
DWORD expectedLongNameSize; DWORD expectedLongNameSize;
WCHAR shortName[ 256 ]; WCHAR shortName[ 256 ];
@ -1775,6 +1887,7 @@ static unsigned short receiveCreatePlayer_( int line, SOCKET sock, DPID expected
static void sendCreatePlayer_( int line, SOCKET sock, unsigned short tcpPort, unsigned short udpPort, static void sendCreatePlayer_( int line, SOCKET sock, unsigned short tcpPort, unsigned short udpPort,
const WCHAR *shortName, const WCHAR *longName, void *playerData, DWORD playerDataSize ) const WCHAR *shortName, const WCHAR *longName, void *playerData, DWORD playerDataSize )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -1820,6 +1933,7 @@ static void sendCreatePlayer_( int line, SOCKET sock, unsigned short tcpPort, un
}, },
}, },
}; };
#include "poppack.h"
SpData spData = { SpData spData = {
.tcpAddr.sin_family = AF_INET, .tcpAddr.sin_family = AF_INET,
.tcpAddr.sin_port = htons( tcpPort ), .tcpAddr.sin_port = htons( tcpPort ),
@ -1877,12 +1991,14 @@ static void sendCreatePlayer_( int line, SOCKET sock, unsigned short tcpPort, un
static unsigned short receiveGuaranteedGameMessage_( int line, SOCKET sock, DPID expectedFromId, DPID expectedToId, static unsigned short receiveGuaranteedGameMessage_( int line, SOCKET sock, DPID expectedFromId, DPID expectedToId,
void *expectedData, DWORD expectedDataSize ) void *expectedData, DWORD expectedDataSize )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
GameMessage request; GameMessage request;
BYTE data[ 256 ]; BYTE data[ 256 ];
} request; } request;
#include "poppack.h"
unsigned short port; unsigned short port;
int wsResult; int wsResult;
@ -1903,11 +2019,13 @@ static unsigned short receiveGuaranteedGameMessage_( int line, SOCKET sock, DPID
static void receiveGameMessage_( int line, SOCKET sock, DPID expectedFromId, DPID expectedToId, void *expectedData, static void receiveGameMessage_( int line, SOCKET sock, DPID expectedFromId, DPID expectedToId, void *expectedData,
DWORD expectedDataSize ) DWORD expectedDataSize )
{ {
#include "pshpack1.h"
struct struct
{ {
GameMessage request; GameMessage request;
BYTE data[ 256 ]; BYTE data[ 256 ];
} request; } request;
#include "poppack.h"
int wsResult; int wsResult;
DWORD expectedSize = sizeof( request.request ) + expectedDataSize; DWORD expectedSize = sizeof( request.request ) + expectedDataSize;
@ -1924,6 +2042,7 @@ static void receiveGameMessage_( int line, SOCKET sock, DPID expectedFromId, DPI
static void sendGuaranteedGameMessage_( int line, SOCKET sock, unsigned short port, DPID fromId, DPID toId, void *data, static void sendGuaranteedGameMessage_( int line, SOCKET sock, unsigned short port, DPID fromId, DPID toId, void *data,
DWORD dataSize ) DWORD dataSize )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -1945,6 +2064,7 @@ static void sendGuaranteedGameMessage_( int line, SOCKET sock, unsigned short po
.toId = toId, .toId = toId,
} }
}; };
#include "poppack.h"
int wsResult; int wsResult;
wsResult = send( sock, (char *) &request, sizeof( request ), 0 ); wsResult = send( sock, (char *) &request, sizeof( request ), 0 );
@ -1958,6 +2078,7 @@ static void sendGuaranteedGameMessage_( int line, SOCKET sock, unsigned short po
sendGameMessage_( __LINE__, sock, fromId, toId, data, dataSize ) sendGameMessage_( __LINE__, sock, fromId, toId, data, dataSize )
static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, void *data, DWORD dataSize ) static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, void *data, DWORD dataSize )
{ {
#include "pshpack1.h"
struct struct
{ {
GameMessage request; GameMessage request;
@ -1970,6 +2091,7 @@ static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, voi
.toId = toId, .toId = toId,
} }
}; };
#include "poppack.h"
int wsResult; int wsResult;
DWORD size; DWORD size;
@ -1985,6 +2107,7 @@ static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, voi
sendPing_( __LINE__, sock, port, fromId, tickCount ) sendPing_( __LINE__, sock, port, fromId, tickCount )
static void sendPing_( int line, SOCKET sock, unsigned short port, DPID fromId, DWORD tickCount ) static void sendPing_( int line, SOCKET sock, unsigned short port, DPID fromId, DWORD tickCount )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
@ -2012,6 +2135,7 @@ static void sendPing_( int line, SOCKET sock, unsigned short port, DPID fromId,
.tickCount = tickCount, .tickCount = tickCount,
} }
}; };
#include "poppack.h"
int wsResult; int wsResult;
wsResult = send( sock, (char *) &request, sizeof( request ), 0 ); wsResult = send( sock, (char *) &request, sizeof( request ), 0 );
@ -2022,11 +2146,13 @@ static void sendPing_( int line, SOCKET sock, unsigned short port, DPID fromId,
receivePingReply_( __LINE__, sock, expectedFromId, expectedTickCount ) receivePingReply_( __LINE__, sock, expectedFromId, expectedTickCount )
static unsigned short receivePingReply_( int line, SOCKET sock, DPID expectedFromId, DWORD expectedTickCount ) static unsigned short receivePingReply_( int line, SOCKET sock, DPID expectedFromId, DWORD expectedTickCount )
{ {
#include "pshpack1.h"
struct struct
{ {
SpHeader spHeader; SpHeader spHeader;
Ping request; Ping request;
} request; } request;
#include "poppack.h"
unsigned short port; unsigned short port;
int wsResult; int wsResult;
@ -2704,7 +2830,7 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const
HRESULT hr; HRESULT hr;
if ( player->actualCount ) if ( player->actualCount )
ok_( __FILE__, data->line )( 0, "duplicate player dpid %#lx.\n", dpid ); todo_wine ok_( __FILE__, data->line )( 0, "duplicate player dpid %#lx.\n", dpid );
ok_( __FILE__, data->line )( playerType == player->expectedPlayerType, "got player type %lu.\n", ok_( __FILE__, data->line )( playerType == player->expectedPlayerType, "got player type %lu.\n",
playerType ); playerType );
if ( player->expectedShortName ) if ( player->expectedShortName )
@ -2727,12 +2853,17 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const
ok_( __FILE__, data->line )( !name->lpszLongNameA, "got long name %s.\n", ok_( __FILE__, data->line )( !name->lpszLongNameA, "got long name %s.\n",
wine_dbgstr_a( name->lpszLongNameA ) ); wine_dbgstr_a( name->lpszLongNameA ) );
} }
todo_wine_if( playerType == DPPLAYERTYPE_GROUP && flags == DPENUMPLAYERS_LOCAL )
ok_( __FILE__, data->line )( flags == player->expectedFlags, "got flags %#lx.\n", flags ); ok_( __FILE__, data->line )( flags == player->expectedFlags, "got flags %#lx.\n", flags );
memset( &playerData, 0xcc, sizeof( playerData ) ); memset( &playerData, 0xcc, sizeof( playerData ) );
playerDataSize = sizeof( playerData ); playerDataSize = sizeof( playerData );
if ( playerType == DPPLAYERTYPE_PLAYER )
hr = IDirectPlayX_GetPlayerData( data->dp, dpid, playerData, &playerDataSize, DPGET_REMOTE ); hr = IDirectPlayX_GetPlayerData( data->dp, dpid, playerData, &playerDataSize, DPGET_REMOTE );
else
hr = IDirectPlayX_GetGroupData( data->dp, dpid, playerData, &playerDataSize, DPGET_REMOTE );
ok_( __FILE__, data->line )( hr == DP_OK, "GetPlayerData() returned %#lx.\n", hr ); ok_( __FILE__, data->line )( hr == DP_OK, "GetPlayerData() returned %#lx.\n", hr );
todo_wine_if( playerType == DPPLAYERTYPE_GROUP )
ok_( __FILE__, data->line )( playerDataSize == player->expectedPlayerDataSize, ok_( __FILE__, data->line )( playerDataSize == player->expectedPlayerDataSize,
"got player data size %lu.\n", playerDataSize ); "got player data size %lu.\n", playerDataSize );
ok_( __FILE__, data->line )( !memcmp( playerData, player->expectedPlayerData, player->expectedPlayerDataSize ), ok_( __FILE__, data->line )( !memcmp( playerData, player->expectedPlayerData, player->expectedPlayerDataSize ),
@ -2740,7 +2871,10 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const
memset( &nameData, 0xcc, sizeof( nameData ) ); memset( &nameData, 0xcc, sizeof( nameData ) );
nameDataSize = sizeof( nameData ); nameDataSize = sizeof( nameData );
if ( playerType == DPPLAYERTYPE_PLAYER )
hr = IDirectPlayX_GetPlayerName( data->dp, dpid, &nameData, &nameDataSize ); hr = IDirectPlayX_GetPlayerName( data->dp, dpid, &nameData, &nameDataSize );
else
hr = IDirectPlayX_GetGroupName( data->dp, dpid, &nameData, &nameDataSize );
ok_( __FILE__, data->line )( hr == DP_OK, "GetPlayerName() returned %#lx.\n", hr ); ok_( __FILE__, data->line )( hr == DP_OK, "GetPlayerName() returned %#lx.\n", hr );
ok_( __FILE__, data->line )( ((DPNAME *) nameData)->dwSize == sizeof( DPNAME ), ok_( __FILE__, data->line )( ((DPNAME *) nameData)->dwSize == sizeof( DPNAME ),
"got name size %lu.\n", ((DPNAME *) nameData)->dwSize ); "got name size %lu.\n", ((DPNAME *) nameData)->dwSize );
@ -2796,7 +2930,8 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const
return TRUE; return TRUE;
} }
#define checkPlayerList( dp, expectedPlayers, expectedPlayerCount ) checkPlayerList_( __LINE__, dp, expectedPlayers, expectedPlayerCount ) #define checkPlayerList( dp, expectedPlayers, expectedPlayerCount ) \
checkPlayerList_( __LINE__, dp, expectedPlayers, expectedPlayerCount )
static void checkPlayerList_( int line, IDirectPlay4 *dp, ExpectedPlayer *expectedPlayers, int expectedPlayerCount ) static void checkPlayerList_( int line, IDirectPlay4 *dp, ExpectedPlayer *expectedPlayers, int expectedPlayerCount )
{ {
CheckPlayerListCallbackData data = { CheckPlayerListCallbackData data = {
@ -2817,6 +2952,51 @@ static void checkPlayerList_( int line, IDirectPlay4 *dp, ExpectedPlayer *expect
data.actualPlayerCount ); data.actualPlayerCount );
} }
#define checkGroupPlayerList( dp, group, expectedPlayers, expectedPlayerCount ) \
checkGroupPlayerList_( __LINE__, dp, group, expectedPlayers, expectedPlayerCount )
static void checkGroupPlayerList_( int line, DPID group, IDirectPlay4 *dp, ExpectedPlayer *expectedPlayers,
int expectedPlayerCount )
{
CheckPlayerListCallbackData data = {
.line = line,
.dp = dp,
.expectedPlayers = expectedPlayers,
.expectedPlayerCount = expectedPlayerCount,
};
HRESULT hr;
hr = IDirectPlayX_EnumGroupPlayers( dp, group, NULL, checkPlayerListCallback, &data, DPENUMPLAYERS_LOCAL );
ok_( __FILE__, line )( hr == DP_OK, "EnumGroupPlayers() returned %#lx.\n", hr );
hr = IDirectPlayX_EnumGroupPlayers( dp, group, NULL, checkPlayerListCallback, &data, DPENUMPLAYERS_REMOTE );
ok_( __FILE__, line )( hr == DP_OK, "EnumGroupPlayers() returned %#lx.\n", hr );
todo_wine ok_( __FILE__, line )( data.actualPlayerCount == data.expectedPlayerCount, "got player count %d.\n",
data.actualPlayerCount );
}
#define checkGroupList( dp, expectedGroups, expectedGroupCount ) \
checkGroupList_( __LINE__, dp, expectedGroups, expectedGroupCount )
static void checkGroupList_( int line, IDirectPlay4 *dp, ExpectedPlayer *expectedGroups, int expectedGroupCount )
{
CheckPlayerListCallbackData data = {
.line = line,
.dp = dp,
.expectedPlayers = expectedGroups,
.expectedPlayerCount = expectedGroupCount,
};
HRESULT hr;
hr = IDirectPlayX_EnumGroups( dp, NULL, checkPlayerListCallback, &data, DPENUMGROUPS_LOCAL );
ok_( __FILE__, line )( hr == DP_OK, "EnumGroups() returned %#lx.\n", hr );
hr = IDirectPlayX_EnumGroups( dp, NULL, checkPlayerListCallback, &data, DPENUMGROUPS_REMOTE );
ok_( __FILE__, line )( hr == DP_OK, "EnumGroups() returned %#lx.\n", hr );
todo_wine ok_( __FILE__, line )( data.actualPlayerCount == data.expectedPlayerCount, "got group count %d.\n",
data.actualPlayerCount );
}
#define checkPlayerExists( dp, expectedDpid, expectedPlayerType, expectedShortName, expectedLongName, expectedFlags, \ #define checkPlayerExists( dp, expectedDpid, expectedPlayerType, expectedShortName, expectedLongName, expectedFlags, \
expectedPlayerData, expectedPlayerDataSize ) \ expectedPlayerData, expectedPlayerDataSize ) \
checkPlayerExists_( __LINE__, dp, expectedDpid, expectedPlayerType, expectedShortName, expectedLongName, \ checkPlayerExists_( __LINE__, dp, expectedDpid, expectedPlayerType, expectedShortName, expectedLongName, \
@ -2918,9 +3098,36 @@ static void check_Open_( int line, IDirectPlay4A *dp, DPSESSIONDESC2 *dpsd, cons
.expectedPlayerData = expectedPlayerData, .expectedPlayerData = expectedPlayerData,
.expectedPlayerDataSize = sizeof( expectedPlayerData ), .expectedPlayerDataSize = sizeof( expectedPlayerData ),
}, },
{
.expectedDpid = 0xd00de,
.expectedPlayerType = DPPLAYERTYPE_PLAYER,
.expectedFlags = DPENUMPLAYERS_REMOTE,
},
};
ExpectedPlayer expectedGroups[] =
{
{
.expectedDpid = 0x5e7,
.expectedPlayerType = DPPLAYERTYPE_GROUP,
.expectedShortName = "short name",
.expectedLongName = "long name",
.expectedFlags = DPENUMPLAYERS_REMOTE,
.expectedPlayerData = expectedPlayerData,
.expectedPlayerDataSize = sizeof( expectedPlayerData ),
},
};
ExpectedPlayer expectedGroupPlayers[] =
{
{
.expectedDpid = 0xd00de,
.expectedPlayerType = DPPLAYERTYPE_PLAYER,
.expectedFlags = DPENUMPLAYERS_REMOTE,
},
}; };
checkPlayerList_( line, dp, expectedPlayers, ARRAYSIZE( expectedPlayers ) ); checkPlayerList_( line, dp, expectedPlayers, ARRAYSIZE( expectedPlayers ) );
checkGroupList_( line, dp, expectedGroups, ARRAYSIZE( expectedGroups ) );
checkGroupPlayerList_( line, 0x5e7, dp, expectedGroupPlayers, ARRAYSIZE( expectedGroupPlayers ) );
hr = IDirectPlayX_Close( dp ); hr = IDirectPlayX_Close( dp );
checkHR( DP_OK, hr ); checkHR( DP_OK, hr );
@ -4648,20 +4855,20 @@ static void test_CreatePlayer(void)
/* Player name */ /* Player name */
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
check_CreatePlayer( dp, &dpid, NULL, 0, DP_OK, 2, recvSock, TRUE, 0x8, NULL, NULL, NULL, NULL, 1 ); check_CreatePlayer( dp, &dpid, NULL, 0, DP_OK, 2, recvSock, TRUE, 0x8, NULL, NULL, NULL, NULL, 2 );
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
check_CreatePlayer( dp, &dpid, &fullName, 0, DP_OK, 3, recvSock, TRUE, 0x8, L"short player name", check_CreatePlayer( dp, &dpid, &fullName, 0, DP_OK, 3, recvSock, TRUE, 0x8, L"short player name",
"short player name", L"long player name", "long player name", 2 ); "short player name", L"long player name", "long player name", 3 );
name = fullName; name = fullName;
name.dwSize = 1; name.dwSize = 1;
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
check_CreatePlayer( dp, &dpid, &name, 0, DP_OK, 4, recvSock, TRUE, 0x8, L"short player name", "short player name", check_CreatePlayer( dp, &dpid, &name, 0, DP_OK, 4, recvSock, TRUE, 0x8, L"short player name", "short player name",
L"long player name", "long player name", 3 ); L"long player name", "long player name", 4 );
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
check_CreatePlayer( dp, &dpid, &nullName, 0, DP_OK, 5, recvSock, TRUE, 0x8, NULL, NULL, NULL, NULL, 4 ); check_CreatePlayer( dp, &dpid, &nullName, 0, DP_OK, 5, recvSock, TRUE, 0x8, NULL, NULL, NULL, NULL, 5 );
/* Null dpid */ /* Null dpid */
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
@ -4669,11 +4876,11 @@ static void test_CreatePlayer(void)
/* Flags */ /* Flags */
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
check_CreatePlayer( dp, &dpid, NULL, 0, DP_OK, 6, recvSock, TRUE, 0x8, NULL, NULL, NULL, NULL, 5 ); check_CreatePlayer( dp, &dpid, NULL, 0, DP_OK, 6, recvSock, TRUE, 0x8, NULL, NULL, NULL, NULL, 6 );
dpid = 0xdeadbeef; dpid = 0xdeadbeef;
check_CreatePlayer( dp, &dpid, NULL, DPPLAYER_SPECTATOR, DP_OK, 7, recvSock, TRUE, 0x208, NULL, NULL, NULL, NULL, check_CreatePlayer( dp, &dpid, NULL, DPPLAYER_SPECTATOR, DP_OK, 7, recvSock, TRUE, 0x208, NULL, NULL, NULL, NULL,
6 ); 7 );
closesocket( recvSock ); closesocket( recvSock );
closesocket( sendSock ); closesocket( sendSock );
@ -4920,7 +5127,7 @@ static void test_CREATEPLAYER(void)
checkPlayerExists( dp, 0x07734, DPPLAYERTYPE_PLAYER, "new player short name", "new player long name", checkPlayerExists( dp, 0x07734, DPPLAYERTYPE_PLAYER, "new player short name", "new player long name",
DPENUMPLAYERS_REMOTE, playerData, sizeof( playerData ) ); DPENUMPLAYERS_REMOTE, playerData, sizeof( playerData ) );
dpid = checkCreatePlayerOrGroupMessage( dp, DPPLAYERTYPE_PLAYER, 0x07734, 3, playerData, sizeof( playerData ), dpid = checkCreatePlayerOrGroupMessage( dp, DPPLAYERTYPE_PLAYER, 0x07734, 4, playerData, sizeof( playerData ),
"new player short name", "new player long name", 0, 0 ); "new player short name", "new player long name", 0, 0 );
ok( dpid == 0x11223344, "got destination id %#lx.\n", dpid ); ok( dpid == 0x11223344, "got destination id %#lx.\n", dpid );
@ -7852,7 +8059,7 @@ static void test_Send(void)
createPlayer( dp, 0x07734, NULL, NULL, 0, 0, sendSock, recvSock ); createPlayer( dp, 0x07734, NULL, NULL, 0, 0, sendSock, recvSock );
createPlayer( dp, 0x14, NULL, NULL, 0, 0, sendSock, recvSock ); createPlayer( dp, 0x14, NULL, NULL, 0, 0, sendSock, recvSock );
checkCreatePlayerOrGroupMessage( dp, DPPLAYERTYPE_PLAYER, 0x14, 2, NULL, 0, NULL, NULL, 0, DPPLAYER_LOCAL ); checkCreatePlayerOrGroupMessage( dp, DPPLAYERTYPE_PLAYER, 0x14, 3, NULL, 0, NULL, NULL, 0, DPPLAYER_LOCAL );
hr = IDirectPlayX_Send( dp, 0x07734, 0xdeadbeef, DPSEND_GUARANTEED, data, sizeof( data ) ); hr = IDirectPlayX_Send( dp, 0x07734, 0xdeadbeef, DPSEND_GUARANTEED, data, sizeof( data ) );
todo_wine ok( hr == DPERR_INVALIDPARAM, "got hr %#lx.\n", hr ); todo_wine ok( hr == DPERR_INVALIDPARAM, "got hr %#lx.\n", hr );
@ -8289,7 +8496,7 @@ static void test_Receive(void)
waitResult = WaitForSingleObject( event0, 2000 ); waitResult = WaitForSingleObject( event0, 2000 );
ok( waitResult == WAIT_OBJECT_0, "message wait returned %lu\n", waitResult ); ok( waitResult == WAIT_OBJECT_0, "message wait returned %lu\n", waitResult );
checkCreatePlayerOrGroupMessage( dp, DPPLAYERTYPE_PLAYER, 0x14, 2, NULL, 0, NULL, NULL, 0, DPPLAYER_LOCAL ); checkCreatePlayerOrGroupMessage( dp, DPPLAYERTYPE_PLAYER, 0x14, 3, NULL, 0, NULL, NULL, 0, DPPLAYER_LOCAL );
sendGuaranteedGameMessage( sendSock, 2349, 0x1337, 0x07734, data0, sizeof( data0 ) ); sendGuaranteedGameMessage( sendSock, 2349, 0x1337, 0x07734, data0, sizeof( data0 ) );
sendGuaranteedGameMessage( sendSock, 2349, 0x1337, 0x14, data1, sizeof( data1 ) ); sendGuaranteedGameMessage( sendSock, 2349, 0x1337, 0x14, data1, sizeof( data1 ) );

View file

@ -354,7 +354,7 @@ static int wait_select_reply( void *cookie )
/*********************************************************************** /***********************************************************************
* invoke_user_apc * invoke_user_apc
*/ */
static NTSTATUS invoke_user_apc( CONTEXT *context, const user_apc_t *apc, NTSTATUS status ) static NTSTATUS invoke_user_apc( CONTEXT *context, const struct user_apc *apc, NTSTATUS status )
{ {
return call_user_apc_dispatcher( context, apc->args[0], apc->args[1], apc->args[2], return call_user_apc_dispatcher( context, apc->args[0], apc->args[1], apc->args[2],
wine_server_get_ptr( apc->func ), status ); wine_server_get_ptr( apc->func ), status );
@ -364,7 +364,7 @@ static NTSTATUS invoke_user_apc( CONTEXT *context, const user_apc_t *apc, NTSTAT
/*********************************************************************** /***********************************************************************
* invoke_system_apc * invoke_system_apc
*/ */
static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOOL self ) static void invoke_system_apc( const union apc_call *call, union apc_result *result, BOOL self )
{ {
SIZE_T size, bits; SIZE_T size, bits;
void *addr; void *addr;
@ -687,20 +687,20 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO
/*********************************************************************** /***********************************************************************
* server_select * server_select
*/ */
unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags, unsigned int server_select( const union select_op *select_op, data_size_t size, UINT flags,
timeout_t abs_timeout, context_t *context, user_apc_t *user_apc ) timeout_t abs_timeout, context_t *context, struct user_apc *user_apc )
{ {
unsigned int ret; unsigned int ret;
int cookie; int cookie;
obj_handle_t apc_handle = 0; obj_handle_t apc_handle = 0;
BOOL suspend_context = !!context; BOOL suspend_context = !!context;
apc_result_t result; union apc_result result;
sigset_t old_set; sigset_t old_set;
int signaled; int signaled;
data_size_t reply_size; data_size_t reply_size;
struct struct
{ {
apc_call_t call; union apc_call call;
context_t context[2]; context_t context[2];
} reply_data; } reply_data;
@ -740,7 +740,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
/* don't signal multiple times */ /* don't signal multiple times */
if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT)
size = offsetof( select_op_t, signal_and_wait.signal ); size = offsetof( union select_op, signal_and_wait.signal );
} }
pthread_sigmask( SIG_SETMASK, &old_set, NULL ); pthread_sigmask( SIG_SETMASK, &old_set, NULL );
if (signaled) break; if (signaled) break;
@ -763,12 +763,12 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
/*********************************************************************** /***********************************************************************
* server_wait * server_wait
*/ */
unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, unsigned int server_wait( const union select_op *select_op, data_size_t size, UINT flags,
const LARGE_INTEGER *timeout ) const LARGE_INTEGER *timeout )
{ {
timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
unsigned int ret; unsigned int ret;
user_apc_t apc; struct user_apc apc;
if (abs_timeout < 0) if (abs_timeout < 0)
{ {
@ -794,7 +794,7 @@ unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT f
*/ */
NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable ) NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable )
{ {
user_apc_t apc; struct user_apc apc;
NTSTATUS status; NTSTATUS status;
if (alertable) if (alertable)
@ -811,7 +811,7 @@ NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable )
*/ */
NTSTATUS WINAPI NtTestAlert(void) NTSTATUS WINAPI NtTestAlert(void)
{ {
user_apc_t apc; struct user_apc apc;
NTSTATUS status; NTSTATUS status;
status = server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, 0, NULL, &apc ); status = server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, 0, NULL, &apc );
@ -823,7 +823,7 @@ NTSTATUS WINAPI NtTestAlert(void)
/*********************************************************************** /***********************************************************************
* server_queue_process_apc * server_queue_process_apc
*/ */
unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) unsigned int server_queue_process_apc( HANDLE process, const union apc_call *call, union apc_result *result )
{ {
for (;;) for (;;)
{ {
@ -1759,8 +1759,8 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
if ((options & DUPLICATE_CLOSE_SOURCE) && source_process != NtCurrentProcess()) if ((options & DUPLICATE_CLOSE_SOURCE) && source_process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );

View file

@ -993,7 +993,7 @@ NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS
/* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */ /* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */
static NTSTATUS event_data_to_state_change( const debug_event_t *data, DBGUI_WAIT_STATE_CHANGE *state ) static NTSTATUS event_data_to_state_change( const union debug_event_data *data, DBGUI_WAIT_STATE_CHANGE *state )
{ {
int i; int i;
@ -1098,7 +1098,7 @@ static NTSTATUS get_image_machine( HANDLE handle, USHORT *machine )
NTSTATUS WINAPI NtWaitForDebugEvent( HANDLE handle, BOOLEAN alertable, LARGE_INTEGER *timeout, NTSTATUS WINAPI NtWaitForDebugEvent( HANDLE handle, BOOLEAN alertable, LARGE_INTEGER *timeout,
DBGUI_WAIT_STATE_CHANGE *state ) DBGUI_WAIT_STATE_CHANGE *state )
{ {
debug_event_t data; union debug_event_data data;
unsigned int ret; unsigned int ret;
BOOL wait = TRUE; BOOL wait = TRUE;
@ -1572,7 +1572,7 @@ NTSTATUS WINAPI NtQueryTimer( HANDLE handle, TIMER_INFORMATION_CLASS class,
NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
select_op_t select_op; union select_op select_op;
UINT i, flags = SELECT_INTERRUPTIBLE; UINT i, flags = SELECT_INTERRUPTIBLE;
if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
@ -1580,7 +1580,7 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO
if (alertable) flags |= SELECT_ALERTABLE; if (alertable) flags |= SELECT_ALERTABLE;
select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL; select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] ); for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
return server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout ); return server_wait( &select_op, offsetof( union select_op, wait.handles[count] ), flags, timeout );
} }
@ -1599,7 +1599,7 @@ NTSTATUS WINAPI NtWaitForSingleObject( HANDLE handle, BOOLEAN alertable, const L
NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
select_op_t select_op; union select_op select_op;
UINT flags = SELECT_INTERRUPTIBLE; UINT flags = SELECT_INTERRUPTIBLE;
if (!signal) return STATUS_INVALID_HANDLE; if (!signal) return STATUS_INVALID_HANDLE;
@ -1883,7 +1883,7 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE
NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
select_op_t select_op; union select_op select_op;
UINT flags = SELECT_INTERRUPTIBLE; UINT flags = SELECT_INTERRUPTIBLE;
if (!handle) handle = keyed_event; if (!handle) handle = keyed_event;
@ -1902,7 +1902,7 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key, NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
select_op_t select_op; union select_op select_op;
UINT flags = SELECT_INTERRUPTIBLE; UINT flags = SELECT_INTERRUPTIBLE;
if (!handle) handle = keyed_event; if (!handle) handle = keyed_event;

View file

@ -1323,8 +1323,8 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -1512,7 +1512,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
DWORD i; DWORD i;
obj_handle_t handle = 0; obj_handle_t handle = 0;
client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS]; client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
select_op_t select_op; union select_op select_op;
sigset_t old_set; sigset_t old_set;
if (!peb->BeingDebugged) return 0; /* no debugger present */ if (!peb->BeingDebugged) return 0; /* no debugger present */
@ -1545,7 +1545,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
contexts_to_server( server_contexts, context ); contexts_to_server( server_contexts, context );
server_contexts[0].flags |= SERVER_CTX_EXEC_SPACE; server_contexts[0].flags |= SERVER_CTX_EXEC_SPACE;
server_contexts[0].exec_space.space.space = exception ? EXEC_SPACE_EXCEPTION : EXEC_SPACE_SYSCALL; server_contexts[0].exec_space.space.space = exception ? EXEC_SPACE_EXCEPTION : EXEC_SPACE_SYSCALL;
server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, server_select( &select_op, offsetof( union select_op, wait.handles[1] ), SELECT_INTERRUPTIBLE,
TIMEOUT_INFINITE, server_contexts, NULL ); TIMEOUT_INFINITE, server_contexts, NULL );
SERVER_START_REQ( get_exception_status ) SERVER_START_REQ( get_exception_status )
@ -1712,7 +1712,7 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1
ULONG_PTR arg2, ULONG_PTR arg3 ) ULONG_PTR arg2, ULONG_PTR arg3 )
{ {
unsigned int ret; unsigned int ret;
apc_call_t call; union apc_call call;
SERVER_START_REQ( queue_apc ) SERVER_START_REQ( queue_apc )
{ {

View file

@ -208,12 +208,12 @@ extern void start_server( BOOL debug );
extern unsigned int server_call_unlocked( void *req_ptr ); extern unsigned int server_call_unlocked( void *req_ptr );
extern void server_enter_uninterrupted_section( pthread_mutex_t *mutex, sigset_t *sigset ); extern void server_enter_uninterrupted_section( pthread_mutex_t *mutex, sigset_t *sigset );
extern void server_leave_uninterrupted_section( pthread_mutex_t *mutex, sigset_t *sigset ); extern void server_leave_uninterrupted_section( pthread_mutex_t *mutex, sigset_t *sigset );
extern unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags, extern unsigned int server_select( const union select_op *select_op, data_size_t size, UINT flags,
timeout_t abs_timeout, context_t *context, user_apc_t *user_apc ); timeout_t abs_timeout, context_t *context, struct user_apc *user_apc );
extern unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, extern unsigned int server_wait( const union select_op *select_op, data_size_t size, UINT flags,
const LARGE_INTEGER *timeout ); const LARGE_INTEGER *timeout );
extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, extern unsigned int server_queue_process_apc( HANDLE process, const union apc_call *call,
apc_result_t *result ); union apc_result *result );
extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd,
int *needs_close, enum server_fd_type *type, unsigned int *options ); int *needs_close, enum server_fd_type *type, unsigned int *options );
extern void wine_server_send_fd( int fd ); extern void wine_server_send_fd( int fd );
@ -436,10 +436,10 @@ static inline void mutex_unlock( pthread_mutex_t *mutex )
if (!process_exiting) pthread_mutex_unlock( mutex ); if (!process_exiting) pthread_mutex_unlock( mutex );
} }
static inline async_data_t server_async( HANDLE handle, struct async_fileio *user, HANDLE event, static inline struct async_data server_async( HANDLE handle, struct async_fileio *user, HANDLE event,
PIO_APC_ROUTINE apc, void *apc_context, client_ptr_t iosb ) PIO_APC_ROUTINE apc, void *apc_context, client_ptr_t iosb )
{ {
async_data_t async; struct async_data async;
async.handle = wine_server_obj_handle( handle ); async.handle = wine_server_obj_handle( handle );
async.user = wine_server_client_ptr( user ); async.user = wine_server_client_ptr( user );
async.iosb = iosb; async.iosb = iosb;

View file

@ -4671,8 +4671,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
unsigned int status; unsigned int status;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -4817,8 +4817,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -4864,8 +4864,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -4962,8 +4962,8 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5146,8 +5146,8 @@ static unsigned int get_basic_memory_info( HANDLE process, LPCVOID addr,
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5559,8 +5559,8 @@ NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size,
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5596,8 +5596,8 @@ NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5672,8 +5672,8 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5744,8 +5744,8 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5788,8 +5788,8 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags )
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -5973,8 +5973,8 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );
@ -6359,8 +6359,8 @@ NTSTATUS WINAPI NtWow64AllocateVirtualMemory64( HANDLE process, ULONG64 *ret, UL
if (process != NtCurrentProcess()) if (process != NtCurrentProcess())
{ {
apc_call_t call; union apc_call call;
apc_result_t result; union apc_result result;
memset( &call, 0, sizeof(call) ); memset( &call, 0, sizeof(call) );

View file

@ -506,7 +506,7 @@ static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp,
struct dispatch_context struct dispatch_context
{ {
irp_params_t params; union irp_params params;
HANDLE handle; HANDLE handle;
struct irp_data *irp_data; struct irp_data *irp_data;
ULONG in_size; ULONG in_size;

View file

@ -4067,11 +4067,8 @@ static void test_SetForegroundWindow(HWND hwnd)
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0); if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0);
/* FIXME: these tests are failing because of a race condition ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow());
* between internal focus state applied immediately and X11 focus ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus());
* message coming late */
todo_wine ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow());
todo_wine ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus());
SetForegroundWindow(hwnd); SetForegroundWindow(hwnd);
check_wnd_state(hwnd, hwnd, hwnd, 0); check_wnd_state(hwnd, hwnd, hwnd, 0);

View file

@ -2729,7 +2729,7 @@ int peek_message( MSG *msg, const struct peek_message_filter *filter )
{ {
NTSTATUS res; NTSTATUS res;
size_t size = 0; size_t size = 0;
const message_data_t *msg_data = buffer; const union message_data *msg_data = buffer;
UINT wake_mask, signal_bits, wake_bits, changed_bits, clear_bits = 0; UINT wake_mask, signal_bits, wake_bits, changed_bits, clear_bits = 0;
/* use the same logic as in server/queue.c get_message */ /* use the same logic as in server/queue.c get_message */
@ -3320,7 +3320,7 @@ BOOL WINAPI NtUserGetMessage( MSG *msg, HWND hwnd, UINT first, UINT last )
static BOOL put_message_in_queue( const struct send_message_info *info, size_t *reply_size ) static BOOL put_message_in_queue( const struct send_message_info *info, size_t *reply_size )
{ {
struct packed_message data; struct packed_message data;
message_data_t msg_data; union message_data msg_data;
unsigned int res; unsigned int res;
int i; int i;
timeout_t timeout = TIMEOUT_INFINITE; timeout_t timeout = TIMEOUT_INFINITE;

View file

@ -275,10 +275,11 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void *
.serialnumber = {'0','0','0','0',0}, .serialnumber = {'0','0','0','0',0},
}; };
struct iohid_device *impl; struct iohid_device *impl;
USAGE_AND_PAGE usages;
CFStringRef str; CFStringRef str;
desc.usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey))); usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey)));
desc.usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey))); usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey)));
desc.vid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDVendorIDKey))); desc.vid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDVendorIDKey)));
desc.pid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDProductIDKey))); desc.pid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDProductIDKey)));
@ -289,8 +290,8 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void *
desc.is_bluetooth = !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothValue), 0) || desc.is_bluetooth = !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothValue), 0) ||
!CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0); !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0);
if (desc.usages.UsagePage != HID_USAGE_PAGE_GENERIC || if (usages.UsagePage != HID_USAGE_PAGE_GENERIC ||
!(desc.usages.Usage == HID_USAGE_GENERIC_JOYSTICK || desc.usages.Usage == HID_USAGE_GENERIC_GAMEPAD)) !(usages.Usage == HID_USAGE_GENERIC_JOYSTICK || usages.Usage == HID_USAGE_GENERIC_GAMEPAD))
{ {
/* winebus isn't currently meant to handle anything but these, and /* winebus isn't currently meant to handle anything but these, and
* opening keyboards, mice, or the Touch Bar on older MacBooks triggers * 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); hid_device_set_hatswitch_y(iface, index, y);
} }
static BOOL descriptor_add_haptic(struct sdl_device *impl) static BOOL descriptor_add_haptic(struct sdl_device *impl, BOOL force)
{ {
USHORT i, count = 0; USHORT i, count = 0;
USAGE usages[16]; USAGE usages[16];
@ -227,16 +227,16 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl)
if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL)) if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL))
{ {
/* SDL_HAPTIC_SQUARE doesn't exist */ /* SDL_HAPTIC_SQUARE doesn't exist */
if (impl->effect_support & SDL_HAPTIC_SINE) usages[count++] = PID_USAGE_ET_SINE; if (force || (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 (force || (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 (force || (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 (force || (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 (force || (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 (force || (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 (force || (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 (force || (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 (force || (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 (force || (impl->effect_support & SDL_HAPTIC_RAMP)) usages[count++] = PID_USAGE_ET_RAMP;
if (!hid_device_add_physical(&impl->unix_device, usages, count)) if (!hid_device_add_physical(&impl->unix_device, usages, count))
return FALSE; return FALSE;
@ -360,7 +360,7 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface)
if (!hid_device_end_input_report(iface)) if (!hid_device_end_input_report(iface))
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
if (!descriptor_add_haptic(impl)) if (!descriptor_add_haptic(impl, physical_usage.Usage == HID_USAGE_SIMULATION_AUTOMOBILE_SIMULATION_DEVICE))
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface)) 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)) if (!hid_device_end_input_report(iface))
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
if (!descriptor_add_haptic(impl)) if (!descriptor_add_haptic(impl, FALSE))
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
if (!hid_device_end_report_descriptor(iface)) if (!hid_device_end_report_descriptor(iface))
@ -443,17 +443,12 @@ static void sdl_device_destroy(struct unix_device *iface)
static NTSTATUS sdl_device_start(struct unix_device *iface) static NTSTATUS sdl_device_start(struct unix_device *iface)
{ {
struct sdl_device *impl = impl_from_unix_device(iface); struct sdl_device *impl = impl_from_unix_device(iface);
NTSTATUS status;
pthread_mutex_lock(&sdl_cs); 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); pthread_mutex_unlock(&sdl_cs);
return status; return STATUS_SUCCESS;
} }
static void sdl_device_stop(struct unix_device *iface) static void sdl_device_stop(struct unix_device *iface)
@ -595,7 +590,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); TRACE("iface %p, index %u, control %04x, iterations %u.\n", iface, index, control, iterations);
if (impl->effect_ids[index] < 0) return STATUS_UNSUCCESSFUL; if (id < 0) return STATUS_SUCCESS;
switch (control) switch (control)
{ {
@ -991,8 +986,6 @@ static void sdl_add_device(unsigned int index)
if (controller) if (controller)
{ {
desc.is_gamepad = TRUE; desc.is_gamepad = TRUE;
desc.usages.UsagePage = HID_USAGE_PAGE_GENERIC;
desc.usages.Usage = HID_USAGE_GENERIC_GAMEPAD;
axis_count = 6; axis_count = 6;
} }
else else
@ -1000,12 +993,12 @@ static void sdl_add_device(unsigned int index)
int button_count = pSDL_JoystickNumButtons(joystick); int button_count = pSDL_JoystickNumButtons(joystick);
axis_count = pSDL_JoystickNumAxes(joystick); axis_count = pSDL_JoystickNumAxes(joystick);
desc.is_gamepad = (axis_count == 6 && button_count >= 14); 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)) for (axis_offset = 0; axis_offset < axis_count; axis_offset += (options.split_controllers ? 6 : axis_count))
{ {
NTSTATUS status;
if (!axis_offset) strcpy(buffer, product); if (!axis_offset) strcpy(buffer, product);
else snprintf(buffer, ARRAY_SIZE(buffer), "%s %d", product, axis_offset / 6); else snprintf(buffer, ARRAY_SIZE(buffer), "%s %d", product, axis_offset / 6);
ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.product, ARRAY_SIZE(desc.product)); ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.product, ARRAY_SIZE(desc.product));
@ -1019,6 +1012,15 @@ static void sdl_add_device(unsigned int index)
impl->id = id; impl->id = id;
impl->axis_offset = axis_offset; 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); bus_event_queue_device_created(&event_queue, &impl->unix_device, &desc);
} }
} }

View file

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

View file

@ -417,7 +417,7 @@ static DWORD check_bus_option(const WCHAR *option, DWORD default_value)
return default_value; return default_value;
} }
static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages) static BOOL is_hidraw_enabled(WORD vid, WORD pid, const USAGE_AND_PAGE *usages, UINT buttons)
{ {
char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024])]; char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[1024])];
KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
@ -436,6 +436,48 @@ 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_dualshock4_gamepad(vid, pid)) prefer_hidraw = TRUE;
if (is_dualsense_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"); RtlInitUnicodeString(&str, L"EnableHidraw");
if (!NtQueryValueKey(driver_key, &str, KeyValuePartialInformation, info, if (!NtQueryValueKey(driver_key, &str, KeyValuePartialInformation, info,
sizeof(buffer) - sizeof(WCHAR), &size)) sizeof(buffer) - sizeof(WCHAR), &size))
@ -684,22 +726,41 @@ static NTSTATUS get_device_descriptors(UINT64 unix_device, BYTE **report_desc, U
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static USAGE_AND_PAGE get_hidraw_device_usages(UINT64 unix_device) static USAGE_AND_PAGE get_device_usages(UINT64 unix_device, UINT *buttons)
{ {
HIDP_DEVICE_DESC device_desc; HIDP_DEVICE_DESC device_desc;
USAGE_AND_PAGE usages = {0}; USAGE_AND_PAGE usages = {0};
UINT report_desc_length; UINT i, count = 0, report_desc_length;
HIDP_BUTTON_CAPS *button_caps;
BYTE *report_desc; BYTE *report_desc;
NTSTATUS status; NTSTATUS status;
HIDP_CAPS caps;
if (!(status = get_device_descriptors(unix_device, &report_desc, &report_desc_length, &device_desc))) 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.UsagePage = device_desc.CollectionDesc[0].UsagePage;
usages.Usage = device_desc.CollectionDesc[0].Usage; 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); HidP_FreeCollectionDescription(&device_desc);
RtlFreeHeap(GetProcessHeap(), 0, report_desc); RtlFreeHeap(GetProcessHeap(), 0, report_desc);
} }
*buttons = count;
return usages; return usages;
} }
@ -749,18 +810,21 @@ static DWORD CALLBACK bus_main_thread(void *args)
case BUS_EVENT_TYPE_DEVICE_CREATED: case BUS_EVENT_TYPE_DEVICE_CREATED:
{ {
struct device_desc desc = event->device_created.desc; struct device_desc desc = event->device_created.desc;
if (desc.is_hidraw && !desc.usages.UsagePage) desc.usages = get_hidraw_device_usages(event->device); USAGE_AND_PAGE usages;
if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &desc.usages)) UINT buttons;
usages = get_device_usages(event->device, &buttons);
if (!desc.is_hidraw != !is_hidraw_enabled(desc.vid, desc.pid, &usages, buttons))
{ {
struct device_remove_params params = {.device = event->device}; struct device_remove_params params = {.device = event->device};
WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-", WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-",
desc.vid, desc.pid, desc.usages.UsagePage, desc.usages.Usage); desc.vid, desc.pid, usages.UsagePage, usages.Usage);
winebus_call(device_remove, &params); winebus_call(device_remove, &params);
break; break;
} }
TRACE("creating %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-", TRACE("creating %shidraw device %04x:%04x with usages %04x:%04x\n", desc.is_hidraw ? "" : "non-",
desc.vid, desc.pid, desc.usages.UsagePage, desc.usages.Usage); desc.vid, desc.pid, usages.UsagePage, usages.Usage);
device = bus_create_hid_device(&event->device_created.desc, event->device); device = bus_create_hid_device(&event->device_created.desc, event->device);
if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations);

View file

@ -49,14 +49,6 @@ static void mouse_destroy(struct unix_device *iface)
static NTSTATUS mouse_start(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; return STATUS_SUCCESS;
} }
@ -123,9 +115,21 @@ static const struct device_desc mouse_device_desc =
static NTSTATUS mouse_device_create(void *args) 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 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->desc = mouse_device_desc;
params->device = (UINT_PTR)hid_device_create(&mouse_vtbl, sizeof(struct mouse_device)); params->device = (UINT_PTR)iface;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -140,14 +144,6 @@ static void keyboard_destroy(struct unix_device *iface)
static NTSTATUS keyboard_start(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; return STATUS_SUCCESS;
} }
@ -214,9 +210,21 @@ static const struct device_desc keyboard_device_desc =
static NTSTATUS keyboard_device_create(void *args) 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 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->desc = keyboard_device_desc;
params->device = (UINT_PTR)hid_device_create(&keyboard_vtbl, sizeof(struct keyboard_device)); params->device = (UINT_PTR)iface;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -38,7 +38,6 @@ struct device_desc
UINT version; UINT version;
UINT input; UINT input;
UINT uid; UINT uid;
USAGE_AND_PAGE usages;
BOOL is_gamepad; BOOL is_gamepad;
BOOL is_hidraw; BOOL is_hidraw;
BOOL is_bluetooth; BOOL is_bluetooth;
@ -151,8 +150,8 @@ enum unix_funcs
static inline const char *debugstr_device_desc(struct device_desc *desc) static inline const char *debugstr_device_desc(struct device_desc *desc)
{ {
if (!desc) return "(null)"; if (!desc) return "(null)";
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}", 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, desc->usages.UsagePage, desc->usages.Usage, desc->vid, desc->pid, desc->version, desc->input, desc->uid,
desc->is_gamepad, desc->is_hidraw, desc->is_bluetooth); desc->is_gamepad, desc->is_hidraw, desc->is_bluetooth);
} }

View file

@ -73,7 +73,8 @@ BOOL X11DRV_CreateDesktop( const WCHAR *name, UINT width, UINT height )
/* Create window */ /* Create window */
win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | EnterWindowMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask; PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
PropertyChangeMask;
win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow ); win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow );
if (default_visual.visual != DefaultVisual( display, DefaultScreen(display) )) if (default_visual.visual != DefaultVisual( display, DefaultScreen(display) ))

View file

@ -761,12 +761,20 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
} }
else if (protocol == x11drv_atom(WM_TAKE_FOCUS)) else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
{ {
HWND last_focus = x11drv_thread_data()->last_focus; HWND last_focus = x11drv_thread_data()->last_focus, foreground = NtUserGetForegroundWindow();
TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n", if (window_has_pending_wm_state( hwnd, -1 ))
hwnd, NtUserIsWindowEnabled(hwnd), NtUserIsWindowVisible(hwnd), {
(int)NtUserGetWindowLongW(hwnd, GWL_STYLE), WARN( "Ignoring window %p/%lx WM_TAKE_FOCUS serial %lu, event_time %ld, foreground %p during WM_STATE change\n",
get_focus(), get_active_window(), NtUserGetForegroundWindow(), last_focus ); hwnd, event->window, event->serial, event_time, foreground );
return;
}
TRACE( "window %p/%lx WM_TAKE_FOCUS serial %lu, event_time %ld, foreground %p\n", hwnd, event->window,
event->serial, event_time, foreground );
TRACE( " enabled %u, visible %u, style %#x, focus %p, active %p, last %p\n",
NtUserIsWindowEnabled( hwnd ), NtUserIsWindowVisible( hwnd ), (int)NtUserGetWindowLongW( hwnd, GWL_STYLE ),
get_focus(), get_active_window(), last_focus );
if (can_activate_window(hwnd)) if (can_activate_window(hwnd))
{ {
@ -783,7 +791,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
} }
else if (hwnd == NtUserGetDesktopWindow()) else if (hwnd == NtUserGetDesktopWindow())
{ {
hwnd = NtUserGetForegroundWindow(); hwnd = foreground;
if (!hwnd) hwnd = last_focus; if (!hwnd) hwnd = last_focus;
if (!hwnd) hwnd = NtUserGetDesktopWindow(); if (!hwnd) hwnd = NtUserGetDesktopWindow();
set_focus( event->display, hwnd, event_time ); set_focus( event->display, hwnd, event_time );
@ -845,14 +853,23 @@ BOOL is_current_process_focused(void)
*/ */
static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
{ {
HWND foreground = NtUserGetForegroundWindow();
XFocusChangeEvent *event = &xev->xfocus; XFocusChangeEvent *event = &xev->xfocus;
BOOL was_grabbed; BOOL was_grabbed;
if (event->detail == NotifyPointer) return FALSE;
if (!hwnd) return FALSE; if (!hwnd) return FALSE;
TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] ); if (window_has_pending_wm_state( hwnd, -1 ))
{
WARN( "Ignoring window %p/%lx FocusIn serial %lu, detail %s, mode %s, foreground %p during WM_STATE change\n",
hwnd, event->window, event->serial, focus_details[event->detail], focus_modes[event->mode], foreground );
return FALSE;
}
TRACE( "window %p/%lx FocusIn serial %lu, detail %s, mode %s, foreground %p\n", hwnd, event->window,
event->serial, focus_details[event->detail], focus_modes[event->mode], foreground );
if (event->detail == NotifyPointer) return FALSE;
/* when focusing in the virtual desktop window, re-apply the cursor clipping rect */ /* when focusing in the virtual desktop window, re-apply the cursor clipping rect */
if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) reapply_cursor_clipping(); if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) reapply_cursor_clipping();
if (hwnd == NtUserGetDesktopWindow()) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE;
@ -921,10 +938,9 @@ static void focus_out( Display *display , HWND hwnd )
*/ */
static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
{ {
HWND foreground = NtUserGetForegroundWindow();
XFocusChangeEvent *event = &xev->xfocus; XFocusChangeEvent *event = &xev->xfocus;
TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] );
if (event->detail == NotifyPointer) if (event->detail == NotifyPointer)
{ {
if (!hwnd && event->window == x11drv_thread_data()->clip_window) if (!hwnd && event->window == x11drv_thread_data()->clip_window)
@ -938,6 +954,16 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
} }
if (!hwnd) return FALSE; if (!hwnd) return FALSE;
if (window_has_pending_wm_state( hwnd, NormalState )) /* ignore FocusOut only if the window is being shown */
{
WARN( "Ignoring window %p/%lx FocusOut serial %lu, detail %s, mode %s, foreground %p during WM_STATE change\n",
hwnd, event->window, event->serial, focus_details[event->detail], focus_modes[event->mode], foreground );
return FALSE;
}
TRACE( "window %p/%lx FocusOut serial %lu, detail %s, mode %s, foreground %p\n", hwnd, event->window,
event->serial, focus_details[event->detail], focus_modes[event->mode], foreground );
/* in virtual desktop mode or when keyboard is grabbed, release any cursor grab but keep the clipping rect */ /* in virtual desktop mode or when keyboard is grabbed, release any cursor grab but keep the clipping rect */
keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed; keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed;
if (is_virtual_desktop() || keyboard_grabbed) ungrab_clipping_window(); if (is_virtual_desktop() || keyboard_grabbed) ungrab_clipping_window();
@ -1078,8 +1104,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
struct x11drv_win_data *data; struct x11drv_win_data *data;
RECT rect; RECT rect;
POINT pos = {event->x, event->y}; POINT pos = {event->x, event->y};
UINT style, flags = 0, config_cmd = 0; UINT config_cmd, state_cmd;
int cx, cy, x, y;
if (!hwnd) return FALSE; if (!hwnd) return FALSE;
if (!(data = get_win_data( hwnd ))) return FALSE; if (!(data = get_win_data( hwnd ))) return FALSE;
@ -1098,78 +1123,24 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
SetRect( &rect, pos.x, pos.y, pos.x + event->width, pos.y + event->height ); SetRect( &rect, pos.x, pos.y, pos.x + event->width, pos.y + event->height );
window_configure_notify( data, event->serial, &rect ); window_configure_notify( data, event->serial, &rect );
if (!data->mapped || data->iconic) goto done; state_cmd = window_update_client_state( data );
if (!data->whole_window || !data->managed) goto done; config_cmd = window_update_client_config( data );
if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0) rect = window_rect_from_visible( &data->rects, data->current_state.rect );
{
TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
hwnd, data->whole_window, event->x, event->y, event->width, event->height,
event->serial, data->configure_serial );
goto done;
}
rect = window_rect_from_visible( &data->rects, rect );
TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
hwnd, data->whole_window, (int)rect.left, (int)rect.top,
(int)(rect.right-rect.left), (int)(rect.bottom-rect.top),
event->x, event->y, event->width, event->height );
/* Compare what has changed */
x = rect.left;
y = rect.top;
cx = rect.right - rect.left;
cy = rect.bottom - rect.top;
flags = SWP_NOACTIVATE | SWP_NOZORDER;
if (!data->whole_window) flags |= SWP_NOCOPYBITS; /* we can't copy bits of foreign windows */
if (data->rects.window.left == x && data->rects.window.top == y) flags |= SWP_NOMOVE;
else
TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
hwnd, (int)data->rects.window.left, (int)data->rects.window.top, x, y );
if ((data->rects.window.right - data->rects.window.left == cx &&
data->rects.window.bottom - data->rects.window.top == cy) ||
IsRectEmpty( &data->rects.window ))
flags |= SWP_NOSIZE;
else
TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
hwnd, (int)(data->rects.window.right - data->rects.window.left),
(int)(data->rects.window.bottom - data->rects.window.top), cx, cy );
style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
if ((style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen)
{
data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window );
if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && !(style & WS_MAXIMIZE))
{
TRACE( "window %p/%lx is maximized\n", data->hwnd, data->whole_window );
config_cmd = SC_MAXIMIZE;
}
else if (!(data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && (style & WS_MAXIMIZE))
{
TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
config_cmd = SC_RESTORE;
}
}
if (!config_cmd && (flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
{
TRACE( "window %p/%lx config changed %s -> %s, flags %#x\n", data->hwnd, data->whole_window,
wine_dbgstr_rect(&data->rects.window), wine_dbgstr_rect(&rect), flags );
config_cmd = MAKELONG(SC_MOVE, flags);
}
done:
release_win_data( data ); release_win_data( data );
if (state_cmd)
{
if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd );
send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 );
}
if (config_cmd) if (config_cmd)
{ {
if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE ); if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE );
else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 ); else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 );
} }
return !!config_cmd; return config_cmd || state_cmd;
} }
@ -1229,74 +1200,20 @@ static int get_window_xembed_info( Display *display, Window window )
* *
* Handle a PropertyNotify for WM_STATE. * Handle a PropertyNotify for WM_STATE.
*/ */
static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window ) static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event )
{ {
struct x11drv_win_data *data; struct x11drv_win_data *data;
UINT style, value = 0, state_cmd = 0; UINT value = 0, state_cmd = 0, config_cmd = 0;
RECT rect;
if (!(data = get_win_data( hwnd ))) return; if (!(data = get_win_data( hwnd ))) return;
if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window ); if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window );
if (update_window) window_wm_state_notify( data, event->serial, value ); window_wm_state_notify( data, event->serial, value );
switch(event->state) state_cmd = window_update_client_state( data );
{ config_cmd = window_update_client_config( data );
case PropertyDelete: rect = window_rect_from_visible( &data->rects, data->current_state.rect );
TRACE( "%p/%lx: WM_STATE deleted from %d\n", data->hwnd, data->whole_window, data->wm_state );
data->wm_state = WithdrawnState;
break;
case PropertyNewValue:
{
int old_state = data->wm_state;
int new_state = get_window_wm_state( event->display, data->whole_window );
if (new_state != -1 && new_state != data->wm_state)
{
TRACE( "%p/%lx: new WM_STATE %d from %d\n",
data->hwnd, data->whole_window, new_state, old_state );
data->wm_state = new_state;
/* ignore the initial state transition out of withdrawn state */
/* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
if (!old_state) goto done;
}
}
break;
}
if (!update_window || !data->managed || !data->mapped) goto done;
style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
if (data->iconic && data->wm_state == NormalState) /* restore window */
{
data->iconic = FALSE;
data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window );
if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
{
if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED))
{
TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
state_cmd = SC_MAXIMIZE;
}
}
else
{
if (style & (WS_MINIMIZE | WS_MAXIMIZE))
{
BOOL activate = (style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE);
TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
state_cmd = MAKELONG(SC_RESTORE, activate);
}
}
}
else if (!data->iconic && data->wm_state == IconicState)
{
data->iconic = TRUE;
if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
{
TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
state_cmd = SC_MINIMIZE;
}
}
done:
release_win_data( data ); release_win_data( data );
if (state_cmd) if (state_cmd)
@ -1304,6 +1221,12 @@ done:
if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd );
send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 );
} }
if (config_cmd)
{
if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE );
else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 );
}
} }
static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event ) static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event )
@ -1320,12 +1243,30 @@ static void handle_xembed_info_notify( HWND hwnd, XPropertyEvent *event )
static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) static void handle_net_wm_state_notify( HWND hwnd, XPropertyEvent *event )
{ {
struct x11drv_win_data *data; struct x11drv_win_data *data;
UINT value = 0; UINT value = 0, state_cmd = 0, config_cmd = 0;
RECT rect;
if (!(data = get_win_data( hwnd ))) return; if (!(data = get_win_data( hwnd ))) return;
if (event->state == PropertyNewValue) value = get_window_net_wm_state( event->display, event->window ); if (event->state == PropertyNewValue) value = get_window_net_wm_state( event->display, event->window );
window_net_wm_state_notify( data, event->serial, value ); window_net_wm_state_notify( data, event->serial, value );
state_cmd = window_update_client_state( data );
config_cmd = window_update_client_config( data );
rect = window_rect_from_visible( &data->rects, data->current_state.rect );
release_win_data( data ); release_win_data( data );
if (state_cmd)
{
if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd );
send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 );
}
if (config_cmd)
{
if (LOWORD(config_cmd) == SC_MOVE) NtUserSetRawWindowPos( hwnd, rect, HIWORD(config_cmd), FALSE );
else send_message( hwnd, WM_SYSCOMMAND, LOWORD(config_cmd), 0 );
}
} }
/*********************************************************************** /***********************************************************************
@ -1336,79 +1277,13 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev )
XPropertyEvent *event = &xev->xproperty; XPropertyEvent *event = &xev->xproperty;
if (!hwnd) return FALSE; if (!hwnd) return FALSE;
if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE ); if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event );
if (event->atom == x11drv_atom(_XEMBED_INFO)) handle_xembed_info_notify( hwnd, event ); if (event->atom == x11drv_atom(_XEMBED_INFO)) handle_xembed_info_notify( hwnd, event );
if (event->atom == x11drv_atom(_NET_WM_STATE)) handle_net_wm_state_notify( hwnd, event ); if (event->atom == x11drv_atom(_NET_WM_STATE)) handle_net_wm_state_notify( hwnd, event );
return TRUE; return TRUE;
} }
/* event filter to wait for a WM_STATE change notification on a window */
static Bool is_wm_state_notify( Display *display, XEvent *event, XPointer arg )
{
if (event->xany.window != (Window)arg) return 0;
return (event->type == DestroyNotify ||
(event->type == PropertyNotify && event->xproperty.atom == x11drv_atom(WM_STATE)));
}
/***********************************************************************
* wait_for_withdrawn_state
*/
void wait_for_withdrawn_state( HWND hwnd, BOOL set )
{
Display *display = thread_display();
struct x11drv_win_data *data;
DWORD end = NtGetTickCount() + 2000;
TRACE( "waiting for window %p to become %swithdrawn\n", hwnd, set ? "" : "not " );
for (;;)
{
XEvent event;
Window window;
int count = 0;
if (!(data = get_win_data( hwnd ))) break;
if (!data->managed || data->embedded || data->display != display) break;
if (!(window = data->whole_window)) break;
if (!data->mapped == !set)
{
TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" );
break;
}
if ((data->wm_state == WithdrawnState) != !set)
{
TRACE( "window %p/%lx state now %d\n", hwnd, window, data->wm_state );
break;
}
release_win_data( data );
while (XCheckIfEvent( display, &event, is_wm_state_notify, (char *)window ))
{
count++;
if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
if (event.type == DestroyNotify) call_event_handler( display, &event );
else handle_wm_state_notify( hwnd, &event.xproperty, FALSE );
}
if (!count)
{
struct pollfd pfd;
int timeout = end - NtGetTickCount();
pfd.fd = ConnectionNumber(display);
pfd.events = POLLIN;
if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1)
{
FIXME( "window %p/%lx wait timed out\n", hwnd, window );
return;
}
}
}
release_win_data( data );
}
/***************************************************************** /*****************************************************************
* SetFocus (X11DRV.@) * SetFocus (X11DRV.@)
* *

View file

@ -46,7 +46,7 @@
#include "winuser.h" #include "winuser.h"
#include "winreg.h" #include "winreg.h"
#include "winnls.h" #include "winnls.h"
#include "ime.h" #include "kbd.h"
#include "wine/server.h" #include "wine/server.h"
#include "wine/debug.h" #include "wine/debug.h"

View file

@ -1160,7 +1160,7 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data )
long monitors[4]; long monitors[4];
XEvent xev; XEvent xev;
if (!(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop() if (!(data->pending_state.net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop()
|| NtUserGetWindowLongW( data->hwnd, GWL_STYLE ) & WS_MINIMIZE) || NtUserGetWindowLongW( data->hwnd, GWL_STYLE ) & WS_MINIMIZE)
return; return;
@ -1213,7 +1213,10 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat
{ {
UINT i, count, old_state = data->pending_state.net_wm_state; UINT i, count, old_state = data->pending_state.net_wm_state;
data->desired_state.net_wm_state = new_state;
if (!data->whole_window) return; /* no window, nothing to update */ if (!data->whole_window) return; /* no window, nothing to update */
if (data->wm_state_serial) return; /* another WM_STATE update is pending, wait for it to complete */
/* we ignore and override previous _NET_WM_STATE update requests */
if (old_state == new_state) return; /* states are the same, nothing to update */ if (old_state == new_state) return; /* states are the same, nothing to update */
if (data->pending_state.wm_state == IconicState) return; /* window is iconic, don't update its state now */ if (data->pending_state.wm_state == IconicState) return; /* window is iconic, don't update its state now */
@ -1267,6 +1270,8 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat
SubstructureRedirectMask | SubstructureNotifyMask, &xev ); SubstructureRedirectMask | SubstructureNotifyMask, &xev );
} }
} }
XFlush( data->display );
} }
static void window_set_config( struct x11drv_win_data *data, const RECT *new_rect, BOOL above ) static void window_set_config( struct x11drv_win_data *data, const RECT *new_rect, BOOL above )
@ -1275,6 +1280,7 @@ static void window_set_config( struct x11drv_win_data *data, const RECT *new_rec
const RECT *old_rect = &data->pending_state.rect; const RECT *old_rect = &data->pending_state.rect;
XWindowChanges changes; XWindowChanges changes;
data->desired_state.rect = *new_rect;
if (!data->whole_window) return; /* no window, nothing to update */ if (!data->whole_window) return; /* no window, nothing to update */
if (EqualRect( old_rect, new_rect )) return; /* rects are the same, nothing to update */ if (EqualRect( old_rect, new_rect )) return; /* rects are the same, nothing to update */
@ -1328,7 +1334,7 @@ static void update_net_wm_states( struct x11drv_win_data *data )
style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
if (style & WS_MINIMIZE) if (style & WS_MINIMIZE)
new_state |= data->net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED)); new_state |= data->desired_state.net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED));
if (data->is_fullscreen) if (data->is_fullscreen)
{ {
if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION)
@ -1352,7 +1358,6 @@ static void update_net_wm_states( struct x11drv_win_data *data )
} }
window_set_net_wm_state( data, new_state ); window_set_net_wm_state( data, new_state );
data->net_wm_state = new_state;
update_net_wm_fullscreen_monitors( data ); update_net_wm_fullscreen_monitors( data );
} }
@ -1413,13 +1418,15 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state )
{ {
UINT old_state = data->pending_state.wm_state; UINT old_state = data->pending_state.wm_state;
data->desired_state.wm_state = new_state;
if (!data->whole_window) return; /* no window, nothing to update */ if (!data->whole_window) return; /* no window, nothing to update */
if (data->wm_state_serial) return; /* another WM_STATE update is pending, wait for it to complete */
if (old_state == new_state) return; /* states are the same, nothing to update */ if (old_state == new_state) return; /* states are the same, nothing to update */
data->pending_state.wm_state = new_state; data->pending_state.wm_state = new_state;
data->wm_state_serial = NextRequest( data->display ); data->wm_state_serial = NextRequest( data->display );
TRACE( "window %p/%lx, requesting WM_STATE %#x -> %#x serial %lu\n", data->hwnd, data->whole_window, TRACE( "window %p/%lx, requesting WM_STATE %#x -> %#x serial %lu, foreground %p\n", data->hwnd, data->whole_window,
old_state, new_state, data->wm_state_serial ); old_state, new_state, data->wm_state_serial, NtUserGetForegroundWindow() );
switch (MAKELONG(old_state, new_state)) switch (MAKELONG(old_state, new_state))
{ {
@ -1439,6 +1446,11 @@ static void window_set_wm_state( struct x11drv_win_data *data, UINT new_state )
if (!data->embedded) XIconifyWindow( data->display, data->whole_window, data->vis.screen ); if (!data->embedded) XIconifyWindow( data->display, data->whole_window, data->vis.screen );
break; break;
} }
/* override redirect windows won't receive WM_STATE property changes */
if (!data->managed) data->wm_state_serial = 0;
XFlush( data->display );
} }
@ -1450,7 +1462,6 @@ static void map_window( HWND hwnd, DWORD new_style )
struct x11drv_win_data *data; struct x11drv_win_data *data;
make_owner_managed( hwnd ); make_owner_managed( hwnd );
wait_for_withdrawn_state( hwnd, TRUE );
if (!(data = get_win_data( hwnd ))) return; if (!(data = get_win_data( hwnd ))) return;
@ -1464,7 +1475,6 @@ static void map_window( HWND hwnd, DWORD new_style )
sync_window_style( data ); sync_window_style( data );
window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState ); window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState );
XFlush( data->display );
data->mapped = TRUE; data->mapped = TRUE;
data->iconic = (new_style & WS_MINIMIZE) != 0; data->iconic = (new_style & WS_MINIMIZE) != 0;
@ -1481,8 +1491,6 @@ static void unmap_window( HWND hwnd )
{ {
struct x11drv_win_data *data; struct x11drv_win_data *data;
wait_for_withdrawn_state( hwnd, FALSE );
if (!(data = get_win_data( hwnd ))) return; if (!(data = get_win_data( hwnd ))) return;
if (data->mapped) if (data->mapped)
@ -1490,14 +1498,96 @@ static void unmap_window( HWND hwnd )
TRACE( "win %p/%lx\n", data->hwnd, data->whole_window ); TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
window_set_wm_state( data, WithdrawnState ); window_set_wm_state( data, WithdrawnState );
data->mapped = FALSE; data->mapped = FALSE;
data->net_wm_state = 0;
} }
release_win_data( data ); release_win_data( data );
} }
UINT window_update_client_state( struct x11drv_win_data *data )
{
UINT old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE );
if (!data->managed) return 0; /* unmanaged windows are managed by the Win32 side */
if (!data->mapped) return 0; /* ignore state changes on invisible windows */
if (data->wm_state_serial) return 0; /* another WM_STATE update is pending, wait for it to complete */
if (data->net_wm_state_serial) return 0; /* another _NET_WM_STATE update is pending, wait for it to complete */
if (data->configure_serial) return 0; /* another config update is pending, wait for it to complete */
if (data->iconic && data->current_state.wm_state == NormalState) /* restore window */
{
data->iconic = FALSE;
if ((old_style & WS_CAPTION) == WS_CAPTION && (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)))
{
if ((old_style & WS_MAXIMIZEBOX) && !(old_style & WS_DISABLED))
{
TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window );
return SC_MAXIMIZE;
}
}
else if (old_style & (WS_MINIMIZE | WS_MAXIMIZE))
{
BOOL activate = (old_style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE);
TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window );
return MAKELONG(SC_RESTORE, activate);
}
}
else if (!data->iconic && data->current_state.wm_state == IconicState)
{
data->iconic = TRUE;
if ((old_style & WS_MINIMIZEBOX) && !(old_style & WS_DISABLED))
{
TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window );
return SC_MINIMIZE;
}
}
return 0;
}
UINT window_update_client_config( struct x11drv_win_data *data )
{
UINT old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ), flags;
RECT rect, old_rect = data->rects.window, new_rect;
if (!data->managed) return 0; /* unmanaged windows are managed by the Win32 side */
if (!data->mapped) return 0; /* ignore config changes on invisible windows */
if (data->iconic) return 0; /* ignore config changes on minimized windows */
if (data->wm_state_serial) return 0; /* another WM_STATE update is pending, wait for it to complete */
if (data->net_wm_state_serial) return 0; /* another _NET_WM_STATE update is pending, wait for it to complete */
if (data->configure_serial) return 0; /* another config update is pending, wait for it to complete */
if ((old_style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen)
{
if ((data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && !(old_style & WS_MAXIMIZE))
{
TRACE( "window %p/%lx is maximized\n", data->hwnd, data->whole_window );
return SC_MAXIMIZE;
}
if (!(data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) && (old_style & WS_MAXIMIZE))
{
TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window );
return SC_RESTORE;
}
}
flags = SWP_NOACTIVATE | SWP_NOZORDER;
rect = new_rect = window_rect_from_visible( &data->rects, data->current_state.rect );
if (new_rect.left == old_rect.left && new_rect.top == old_rect.top) flags |= SWP_NOMOVE;
else OffsetRect( &rect, old_rect.left - new_rect.left, old_rect.top - new_rect.top );
if (rect.right == old_rect.right && rect.bottom == old_rect.bottom) flags |= SWP_NOSIZE;
else if (IsRectEmpty( &rect )) flags |= SWP_NOSIZE;
if ((flags & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE)) return 0;
TRACE( "window %p/%lx config changed %s -> %s, flags %#x\n", data->hwnd, data->whole_window,
wine_dbgstr_rect(&old_rect), wine_dbgstr_rect(&new_rect), flags );
return MAKELONG(SC_MOVE, flags);
}
void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value )
{ {
UINT *pending = &data->pending_state.wm_state, *current = &data->current_state.wm_state; UINT *desired = &data->desired_state.wm_state, *pending = &data->pending_state.wm_state, *current = &data->current_state.wm_state;
unsigned long *expect_serial = &data->wm_state_serial; unsigned long *expect_serial = &data->wm_state_serial;
const char *reason = NULL, *expected, *received; const char *reason = NULL, *expected, *received;
@ -1522,16 +1612,20 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial,
else else
{ {
WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected );
*pending = value; /* avoid requesting the same state again */ *desired = *pending = value; /* avoid requesting the same state again */
} }
*current = value; *current = value;
*expect_serial = 0; *expect_serial = 0;
/* send any pending changes from the desired state */
window_set_wm_state( data, data->desired_state.wm_state );
window_set_net_wm_state( data, data->desired_state.net_wm_state );
} }
void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ) void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value )
{ {
UINT *pending = &data->pending_state.net_wm_state, *current = &data->current_state.net_wm_state; UINT *desired = &data->desired_state.net_wm_state, *pending = &data->pending_state.net_wm_state, *current = &data->current_state.net_wm_state;
unsigned long *expect_serial = &data->net_wm_state_serial; unsigned long *expect_serial = &data->net_wm_state_serial;
const char *reason = NULL, *expected, *received; const char *reason = NULL, *expected, *received;
@ -1554,16 +1648,20 @@ void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long ser
else else
{ {
WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected );
*pending = value; /* avoid requesting the same state again */ *desired = *pending = value; /* avoid requesting the same state again */
} }
*current = value; *current = value;
*expect_serial = 0; *expect_serial = 0;
/* send any pending changes from the desired state */
window_set_wm_state( data, data->desired_state.wm_state );
window_set_net_wm_state( data, data->desired_state.net_wm_state );
} }
void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *value ) void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *value )
{ {
RECT *pending = &data->pending_state.rect, *current = &data->current_state.rect; RECT *desired = &data->desired_state.rect, *pending = &data->pending_state.rect, *current = &data->current_state.rect;
unsigned long *expect_serial = &data->configure_serial; unsigned long *expect_serial = &data->configure_serial;
const char *reason = NULL, *expected, *received; const char *reason = NULL, *expected, *received;
@ -1586,13 +1684,26 @@ void window_configure_notify( struct x11drv_win_data *data, unsigned long serial
else else
{ {
WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected ); WARN( "window %p/%lx, %s%s%s\n", data->hwnd, data->whole_window, reason, received, expected );
*pending = *value; /* avoid requesting the same state again */ *desired = *pending = *value; /* avoid requesting the same state again */
} }
*current = *value; *current = *value;
*expect_serial = 0; *expect_serial = 0;
} }
BOOL window_has_pending_wm_state( HWND hwnd, UINT state )
{
struct x11drv_win_data *data;
BOOL pending;
if (!(data = get_win_data( hwnd ))) return FALSE;
if (state != -1 && data->desired_state.wm_state != state) pending = FALSE;
else pending = !!data->wm_state_serial;
release_win_data( data );
return pending;
}
/*********************************************************************** /***********************************************************************
* make_window_embedded * make_window_embedded
*/ */
@ -1600,7 +1711,6 @@ void make_window_embedded( struct x11drv_win_data *data )
{ {
/* the window cannot be mapped before being embedded */ /* the window cannot be mapped before being embedded */
window_set_wm_state( data, WithdrawnState ); window_set_wm_state( data, WithdrawnState );
data->net_wm_state = 0;
data->embedded = TRUE; data->embedded = TRUE;
data->managed = TRUE; data->managed = TRUE;
sync_window_style( data ); sync_window_style( data );
@ -1957,6 +2067,7 @@ static void create_whole_window( struct x11drv_win_data *data )
if (!data->whole_window) goto done; if (!data->whole_window) goto done;
SetRect( &data->current_state.rect, pos.x, pos.y, pos.x + cx, pos.y + cy ); SetRect( &data->current_state.rect, pos.x, pos.y, pos.x + cx, pos.y + cy );
data->pending_state.rect = data->current_state.rect; data->pending_state.rect = data->current_state.rect;
data->desired_state.rect = data->current_state.rect;
x11drv_xinput2_enable( data->display, data->whole_window ); x11drv_xinput2_enable( data->display, data->whole_window );
set_initial_wm_hints( data->display, data->whole_window ); set_initial_wm_hints( data->display, data->whole_window );
@ -2011,10 +2122,9 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des
if (data->whole_colormap) XFreeColormap( data->display, data->whole_colormap ); if (data->whole_colormap) XFreeColormap( data->display, data->whole_colormap );
data->whole_window = data->client_window = 0; data->whole_window = data->client_window = 0;
data->whole_colormap = 0; data->whole_colormap = 0;
data->wm_state = WithdrawnState;
data->net_wm_state = 0;
data->mapped = FALSE; data->mapped = FALSE;
memset( &data->desired_state, 0, sizeof(data->desired_state) );
memset( &data->pending_state, 0, sizeof(data->pending_state) ); memset( &data->pending_state, 0, sizeof(data->pending_state) );
memset( &data->current_state, 0, sizeof(data->current_state) ); memset( &data->current_state, 0, sizeof(data->current_state) );
data->wm_state_serial = 0; data->wm_state_serial = 0;

View file

@ -633,14 +633,13 @@ struct x11drv_win_data
UINT net_wm_fullscreen_monitors_set : 1; /* is _NET_WM_FULLSCREEN_MONITORS set */ UINT net_wm_fullscreen_monitors_set : 1; /* is _NET_WM_FULLSCREEN_MONITORS set */
UINT is_fullscreen : 1; /* is the window visible rect fullscreen */ UINT is_fullscreen : 1; /* is the window visible rect fullscreen */
UINT parent_invalid : 1; /* is the parent host window possibly invalid */ UINT parent_invalid : 1; /* is the parent host window possibly invalid */
int wm_state; /* current value of the WM_STATE property */
DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */
Window embedder; /* window id of embedder */ Window embedder; /* window id of embedder */
Pixmap icon_pixmap; Pixmap icon_pixmap;
Pixmap icon_mask; Pixmap icon_mask;
unsigned long *icon_bits; unsigned long *icon_bits;
unsigned int icon_size; unsigned int icon_size;
struct window_state desired_state; /* window state tracking the desired / win32 state */
struct window_state pending_state; /* window state tracking the pending / requested state */ struct window_state pending_state; /* window state tracking the pending / requested state */
struct window_state current_state; /* window state tracking the current X11 state */ struct window_state current_state; /* window state tracking the current X11 state */
unsigned long wm_state_serial; /* serial of last pending WM_STATE request */ unsigned long wm_state_serial; /* serial of last pending WM_STATE request */
@ -659,10 +658,13 @@ extern void set_gl_drawable_parent( HWND hwnd, HWND parent );
extern void destroy_gl_drawable( HWND hwnd ); extern void destroy_gl_drawable( HWND hwnd );
extern void destroy_vk_surface( HWND hwnd ); extern void destroy_vk_surface( HWND hwnd );
extern BOOL window_has_pending_wm_state( HWND hwnd, UINT state );
extern void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ); extern void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value );
extern void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value ); extern void window_net_wm_state_notify( struct x11drv_win_data *data, unsigned long serial, UINT value );
extern void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *rect ); extern void window_configure_notify( struct x11drv_win_data *data, unsigned long serial, const RECT *rect );
extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ); extern UINT window_update_client_state( struct x11drv_win_data *data );
extern UINT window_update_client_config( struct x11drv_win_data *data );
extern Window init_clip_window(void); extern Window init_clip_window(void);
extern void update_user_time( Time time ); extern void update_user_time( Time time );
extern UINT get_window_net_wm_state( Display *display, Window window ); extern UINT get_window_net_wm_state( Display *display, Window window );

View file

@ -3886,26 +3886,23 @@ static DWORD HTTP_HttpQueryInfoW(http_request_t *request, DWORD dwInfoLevel,
} }
else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer) else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
{ {
time_t tmpTime; SYSTEMTIME st;
struct tm tmpTM;
SYSTEMTIME *STHook;
tmpTime = ConvertTimeString(lphttpHdr->lpszValue); if (!InternetTimeToSystemTimeW(lphttpHdr->lpszValue, &st, 0))
{
tmpTM = *gmtime(&tmpTime); LeaveCriticalSection( &request->headers_section );
STHook = (SYSTEMTIME *)lpBuffer; return ERROR_HTTP_INVALID_HEADER;
STHook->wDay = tmpTM.tm_mday; }
STHook->wHour = tmpTM.tm_hour; if (*lpdwBufferLength < sizeof(st))
STHook->wMilliseconds = 0; {
STHook->wMinute = tmpTM.tm_min; *lpdwBufferLength = sizeof(st);
STHook->wDayOfWeek = tmpTM.tm_wday; LeaveCriticalSection( &request->headers_section );
STHook->wMonth = tmpTM.tm_mon + 1; return ERROR_INSUFFICIENT_BUFFER;
STHook->wSecond = tmpTM.tm_sec; }
STHook->wYear = 1900+tmpTM.tm_year; TRACE(" returning time: %04u/%02u/%02u - %u - %02u:%02u:%02u.%02u\n",
st.wYear, st.wMonth, st.wDay, st.wDayOfWeek, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", memcpy(lpBuffer, &st, sizeof(st));
STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek, *lpdwBufferLength = sizeof(st);
STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
} }
else if (lphttpHdr->lpszValue) else if (lphttpHdr->lpszValue)
{ {
@ -4521,7 +4518,7 @@ static BOOL HTTP_ParseDateAsAsctime(LPCWSTR value, FILETIME *ft)
/* asctime() doesn't report a timezone, but some web servers do, so accept /* asctime() doesn't report a timezone, but some web servers do, so accept
* with or without GMT. * with or without GMT.
*/ */
if (*ptr && wcscmp(ptr, L"GMT")) if (*ptr && (wcscmp(ptr, L"GMT") && wcscmp(ptr, L"UTC")))
{ {
ERR("unexpected timezone %s\n", debugstr_w(ptr)); ERR("unexpected timezone %s\n", debugstr_w(ptr));
return FALSE; return FALSE;
@ -4598,7 +4595,7 @@ static BOOL HTTP_ParseRfc1123Date(LPCWSTR value, FILETIME *ft)
while (iswspace(*ptr)) while (iswspace(*ptr))
ptr++; ptr++;
if (wcscmp(ptr, L"GMT")) if (wcscmp(ptr, L"GMT") && wcscmp(ptr, L"UTC"))
{ {
ERR("unexpected time zone %s\n", debugstr_w(ptr)); ERR("unexpected time zone %s\n", debugstr_w(ptr));
return FALSE; return FALSE;
@ -4715,7 +4712,7 @@ static BOOL HTTP_ParseRfc850Date(LPCWSTR value, FILETIME *ft)
while (iswspace(*ptr)) while (iswspace(*ptr))
ptr++; ptr++;
if (wcscmp(ptr, L"GMT")) if (wcscmp(ptr, L"GMT") && wcscmp(ptr, L"UTC"))
{ {
ERR("unexpected time zone %s\n", debugstr_w(ptr)); ERR("unexpected time zone %s\n", debugstr_w(ptr));
return FALSE; return FALSE;

View file

@ -2412,6 +2412,7 @@ static const char okmsg2[] =
"Content-Length: 0\r\n" "Content-Length: 0\r\n"
"Set-Cookie: one\r\n" "Set-Cookie: one\r\n"
"Set-Cookie: two\r\n" "Set-Cookie: two\r\n"
"Last-Modified: Mon, 01 Dec 2008 13:44:34 UTC\r\n"
"\r\n"; "\r\n";
static DWORD64 content_length; static DWORD64 content_length;
@ -4566,9 +4567,11 @@ static void test_head_request(int port)
static void test_HttpQueryInfo(int port) static void test_HttpQueryInfo(int port)
{ {
static const SYSTEMTIME expect = {2008, 12, 1, 1, 13, 44, 34};
test_request_t req; test_request_t req;
DWORD size, index, error; DWORD size, index, error;
char buffer[1024]; char buffer[1024];
SYSTEMTIME st;
BOOL ret; BOOL ret;
open_simple_request(&req, "localhost", port, NULL, "/testD"); open_simple_request(&req, "localhost", port, NULL, "/testD");
@ -4589,9 +4592,27 @@ static void test_HttpQueryInfo(int port)
ok(index == 1, "expected 1 got %lu\n", index); ok(index == 1, "expected 1 got %lu\n", index);
index = 0; index = 0;
size = sizeof(buffer); size = 0;
ret = HttpQueryInfoA(req.request, HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME, buffer, &size, &index); ret = HttpQueryInfoA(req.request, HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME, &st, &size, &index);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %lu\n", GetLastError());
ok(size == sizeof(st), "got %lu\n", size);
index = 0;
size = sizeof(st) + 1;
memset(&st, 0, sizeof(st));
ret = HttpQueryInfoA(req.request, HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME, &st, &size, &index);
ok(ret, "HttpQueryInfo failed %lu\n", GetLastError()); ok(ret, "HttpQueryInfo failed %lu\n", GetLastError());
ok(!memcmp(&st, &expect, sizeof(st)), "wrong time\n");
ok(size == sizeof(st), "got %lu\n", size);
ok(index == 1, "expected 1 got %lu\n", index);
index = 0;
size = sizeof(st);
memset(&st, 0, sizeof(st));
ret = HttpQueryInfoA(req.request, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, &st, &size, &index);
ok(ret, "HttpQueryInfo failed %lu\n", GetLastError());
ok(!memcmp(&st, &expect, sizeof(st)), "wrong time\n");
ok(size == sizeof(st), "got %lu\n", size);
ok(index == 1, "expected 1 got %lu\n", index); ok(index == 1, "expected 1 got %lu\n", index);
index = 0; index = 0;

View file

@ -1116,9 +1116,11 @@ static void test_InternetTimeToSystemTime(void)
test_data[] = test_data[] =
{ {
{ "Fri, 07 Jan 2005 12:06:35 GMT", &expect1, TRUE }, { "Fri, 07 Jan 2005 12:06:35 GMT", &expect1, TRUE },
{ "Fri, 07 Jan 2005 12:06:35 UTC", &expect1, TRUE },
{ " fri, 7 jan 2005 12 06 35", &expect1, TRUE }, { " fri, 7 jan 2005 12 06 35", &expect1, TRUE },
{ "Fri, 07-01-2005 12:06:35", &expect1, TRUE }, { "Fri, 07-01-2005 12:06:35", &expect1, TRUE },
{ "5, 07-01-2005 12:06:35 GMT", &expect1, TRUE }, { "5, 07-01-2005 12:06:35 GMT", &expect1, TRUE },
{ "5, 07-01-2005 12:06:35 UTC", &expect1, TRUE },
{ "5, 07-01-2005 12:06:35 GMT;", &expect1, TRUE }, { "5, 07-01-2005 12:06:35 GMT;", &expect1, TRUE },
{ "5, 07-01-2005 12:06:35 GMT123", &expect1, TRUE }, { "5, 07-01-2005 12:06:35 GMT123", &expect1, TRUE },
{ "2, 11 01 2022 11 13 05", &expect2, TRUE }, { "2, 11 01 2022 11 13 05", &expect2, TRUE },
@ -1126,6 +1128,9 @@ static void test_InternetTimeToSystemTime(void)
{ "2, 11*01/2022 11+13=05", &expect2, TRUE }, { "2, 11*01/2022 11+13=05", &expect2, TRUE },
{ "2, 11-Jan-2022 11:13:05", &expect2, TRUE }, { "2, 11-Jan-2022 11:13:05", &expect2, TRUE },
{ "Fr", NULL, FALSE }, { "Fr", NULL, FALSE },
{ "Fri Jan 7 12:06:35 2005", &expect1, TRUE, TRUE },
{ "Fri Jan 7 12:06:35 2005 GMT", &expect1, TRUE, TRUE },
{ "Fri Jan 7 12:06:35 2005 UTC", &expect1, TRUE, TRUE },
}; };
ret = pInternetTimeToSystemTimeA(NULL, NULL, 0); ret = pInternetTimeToSystemTimeA(NULL, NULL, 0);

View file

@ -39,92 +39,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(wininet); WINE_DEFAULT_DEBUG_CHANNEL(wininet);
#define TIME_STRING_LEN 30
time_t ConvertTimeString(LPCWSTR asctime)
{
WCHAR tmpChar[TIME_STRING_LEN];
WCHAR *tmpChar2;
struct tm t;
int timelen = lstrlenW(asctime);
if(!timelen)
return 0;
/* FIXME: the atoiWs below rely on that tmpChar is \0 padded */
memset( tmpChar, 0, sizeof(tmpChar) );
lstrcpynW(tmpChar, asctime, TIME_STRING_LEN);
/* Assert that the string is the expected length */
if (lstrlenW(asctime) >= TIME_STRING_LEN) FIXME("\n");
/* Convert a time such as 'Mon, 15 Nov 1999 16:09:35 GMT' into a SYSTEMTIME structure
* We assume the time is in this format
* and divide it into easy to swallow chunks
*/
tmpChar[3]='\0';
tmpChar[7]='\0';
tmpChar[11]='\0';
tmpChar[16]='\0';
tmpChar[19]='\0';
tmpChar[22]='\0';
tmpChar[25]='\0';
memset( &t, 0, sizeof(t) );
t.tm_year = wcstol(tmpChar+12, NULL, 10) - 1900;
t.tm_mday = wcstol(tmpChar+5, NULL, 10);
t.tm_hour = wcstol(tmpChar+17, NULL, 10);
t.tm_min = wcstol(tmpChar+20, NULL, 10);
t.tm_sec = wcstol(tmpChar+23, NULL, 10);
/* and month */
tmpChar2 = tmpChar + 8;
switch(tmpChar2[2])
{
case 'n':
if(tmpChar2[1]=='a')
t.tm_mon = 0;
else
t.tm_mon = 5;
break;
case 'b':
t.tm_mon = 1;
break;
case 'r':
if(tmpChar2[1]=='a')
t.tm_mon = 2;
else
t.tm_mon = 3;
break;
case 'y':
t.tm_mon = 4;
break;
case 'l':
t.tm_mon = 6;
break;
case 'g':
t.tm_mon = 7;
break;
case 'p':
t.tm_mon = 8;
break;
case 't':
t.tm_mon = 9;
break;
case 'v':
t.tm_mon = 10;
break;
case 'c':
t.tm_mon = 11;
break;
default:
FIXME("\n");
}
return mktime(&t);
}
BOOL GetAddress(const WCHAR *name, INTERNET_PORT port, struct sockaddr *psa, int *sa_len, char *addr_str) BOOL GetAddress(const WCHAR *name, INTERNET_PORT port, struct sockaddr *psa, int *sa_len, char *addr_str)
{ {
ADDRINFOW *res, hints; ADDRINFOW *res, hints;

View file

@ -1240,3 +1240,211 @@ HRESULT WINAPI RoResolveNamespace(HSTRING name, HSTRING windowsMetaDataDir,
return RO_E_METADATA_NAME_NOT_FOUND; 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,11 +814,159 @@ static void test_RoResolveNamespace(void)
RoUninitialize(); 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) START_TEST(wintypes)
{ {
IsWow64Process(GetCurrentProcess(), &is_wow64); IsWow64Process(GetCurrentProcess(), &is_wow64);
test_IApiInformationStatics(); test_IApiInformationStatics();
test_IPropertyValueStatics(); test_IPropertyValueStatics();
test_RoParseTypeName();
test_RoResolveNamespace(); test_RoResolveNamespace();
} }

View file

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

View file

@ -343,4 +343,19 @@ typedef struct tagKbdLayer
#error "Unsupported KBD_TYPE" #error "Unsupported KBD_TYPE"
#endif #endif
#define VK_DBE_ALPHANUMERIC 0x0f0
#define VK_DBE_KATAKANA 0x0f1
#define VK_DBE_HIRAGANA 0x0f2
#define VK_DBE_SBCSCHAR 0x0f3
#define VK_DBE_DBCSCHAR 0x0f4
#define VK_DBE_ROMAN 0x0f5
#define VK_DBE_NOROMAN 0x0f6
#define VK_DBE_ENTERWORDREGISTERMODE 0x0f7
#define VK_DBE_ENTERIMECONFIGMODE 0x0f8
#define VK_DBE_FLUSHSTRING 0x0f9
#define VK_DBE_CODEINPUT 0x0fa
#define VK_DBE_NOCODEINPUT 0x0fb
#define VK_DBE_DETERMINESTRING 0x0fc
#define VK_DBE_ENTERDLGCONVERSIONMODE 0x0fd
#endif /* __WINE_KBD_H */ #endif /* __WINE_KBD_H */

View file

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

View file

@ -430,6 +430,36 @@ library UIAutomationClient {
const long UIA_AppBarControlTypeId = 50040; const long UIA_AppBarControlTypeId = 50040;
} }
[dllname("<no entry points>")]
module UIA_AnnotationTypes
{
const long AnnotationType_Unknown = 60000;
const long AnnotationType_SpellingError = 60001;
const long AnnotationType_GrammarError = 60002;
const long AnnotationType_Comment = 60003;
const long AnnotationType_FormulaError = 60004;
const long AnnotationType_TrackChanges = 60005;
const long AnnotationType_Header = 60006;
const long AnnotationType_Footer = 60007;
const long AnnotationType_Highlighted = 60008;
const long AnnotationType_Endnote = 60009;
const long AnnotationType_Footnote = 60010;
const long AnnotationType_InsertionChange = 60011;
const long AnnotationType_DeletionChange = 60012;
const long AnnotationType_MoveChange = 60013;
const long AnnotationType_FormatChange = 60014;
const long AnnotationType_UnsyncedChange = 60015;
const long AnnotationType_EditingLockedChange = 60016;
const long AnnotationType_ExternalChange = 60017;
const long AnnotationType_ConflictingChange = 60018;
const long AnnotationType_Author = 60019;
const long AnnotationType_AdvancedProofingIssue = 60020;
const long AnnotationType_DataValidationError = 60021;
const long AnnotationType_CircularReferenceError = 60022;
const long AnnotationType_Mathematics = 60023;
const long AnnotationType_Sensitive = 60024;
}
[dllname("<no entry points>")] [dllname("<no entry points>")]
module UIA_LandmarkTypeIds module UIA_LandmarkTypeIds
{ {

View file

@ -57,7 +57,7 @@ struct request_max_size
typedef union union debug_event_data
{ {
int code; int code;
struct struct
@ -109,7 +109,7 @@ typedef union
int __pad; int __pad;
mod_handle_t base; mod_handle_t base;
} unload_dll; } unload_dll;
} debug_event_t; };
enum context_exec_space enum context_exec_space
@ -260,7 +260,7 @@ typedef struct
} rectangle_t; } rectangle_t;
typedef struct struct async_data
{ {
obj_handle_t handle; obj_handle_t handle;
obj_handle_t event; obj_handle_t event;
@ -268,7 +268,7 @@ typedef struct
client_ptr_t user; client_ptr_t user;
client_ptr_t apc; client_ptr_t apc;
apc_param_t apc_context; apc_param_t apc_context;
} async_data_t; };
@ -312,7 +312,7 @@ struct winevent_msg_data
}; };
typedef union union hw_input
{ {
int type; int type;
struct struct
@ -342,15 +342,15 @@ typedef union
lparam_t lparam; lparam_t lparam;
struct hid_input hid; struct hid_input hid;
} hw; } hw;
} hw_input_t; };
typedef union union message_data
{ {
unsigned char bytes[1]; unsigned char bytes[1];
struct hardware_msg_data hardware; struct hardware_msg_data hardware;
struct callback_msg_data callback; struct callback_msg_data callback;
struct winevent_msg_data winevent; struct winevent_msg_data winevent;
} message_data_t; };
struct filesystem_event struct filesystem_event
@ -435,7 +435,7 @@ struct object_type_info
}; };
enum select_op enum select_opcode
{ {
SELECT_NONE, SELECT_NONE,
SELECT_WAIT, SELECT_WAIT,
@ -445,28 +445,28 @@ enum select_op
SELECT_KEYED_EVENT_RELEASE SELECT_KEYED_EVENT_RELEASE
}; };
typedef union union select_op
{ {
enum select_op op; enum select_opcode op;
struct struct
{ {
enum select_op op; enum select_opcode op;
obj_handle_t handles[MAXIMUM_WAIT_OBJECTS]; obj_handle_t handles[MAXIMUM_WAIT_OBJECTS];
int __pad; int __pad;
} wait; } wait;
struct struct
{ {
enum select_op op; enum select_opcode op;
obj_handle_t wait; obj_handle_t wait;
obj_handle_t signal; obj_handle_t signal;
} signal_and_wait; } signal_and_wait;
struct struct
{ {
enum select_op op; enum select_opcode op;
obj_handle_t handle; obj_handle_t handle;
client_ptr_t key; client_ptr_t key;
} keyed_event; } keyed_event;
} select_op_t; };
enum apc_type enum apc_type
{ {
@ -488,18 +488,18 @@ enum apc_type
APC_DUP_HANDLE APC_DUP_HANDLE
}; };
typedef struct struct user_apc
{ {
enum apc_type type; enum apc_type type;
int __pad; int __pad;
client_ptr_t func; client_ptr_t func;
apc_param_t args[3]; apc_param_t args[3];
} user_apc_t; };
typedef union union apc_call
{ {
enum apc_type type; enum apc_type type;
user_apc_t user; struct user_apc user;
struct struct
{ {
enum apc_type type; enum apc_type type;
@ -620,9 +620,9 @@ typedef union
unsigned int attributes; unsigned int attributes;
unsigned int options; unsigned int options;
} dup_handle; } dup_handle;
} apc_call_t; };
typedef union union apc_result
{ {
enum apc_type type; enum apc_type type;
struct struct
@ -732,7 +732,7 @@ typedef union
enum apc_type type; enum apc_type type;
unsigned int status; unsigned int status;
} break_process; } break_process;
} apc_result_t; };
enum irp_type enum irp_type
{ {
@ -748,7 +748,7 @@ enum irp_type
IRP_CALL_CANCEL IRP_CALL_CANCEL
}; };
typedef union union irp_params
{ {
enum irp_type type; enum irp_type type;
struct struct
@ -816,7 +816,7 @@ typedef union
int __pad; int __pad;
client_ptr_t irp; client_ptr_t irp;
} cancel; } cancel;
} irp_params_t; };
typedef struct typedef struct
@ -1343,7 +1343,7 @@ struct get_apc_result_request
struct get_apc_result_reply struct get_apc_result_reply
{ {
struct reply_header __header; struct reply_header __header;
apc_result_t result; union apc_result result;
}; };
@ -1829,7 +1829,7 @@ struct flush_request
{ {
struct request_header __header; struct request_header __header;
char __pad_12[4]; char __pad_12[4];
async_data_t async; struct async_data async;
}; };
struct flush_reply struct flush_reply
{ {
@ -1857,7 +1857,7 @@ struct get_volume_info_request
{ {
struct request_header __header; struct request_header __header;
obj_handle_t handle; obj_handle_t handle;
async_data_t async; struct async_data async;
unsigned int info_class; unsigned int info_class;
char __pad_60[4]; char __pad_60[4];
}; };
@ -1906,7 +1906,7 @@ struct recv_socket_request
{ {
struct request_header __header; struct request_header __header;
int oob; int oob;
async_data_t async; struct async_data async;
int force_async; int force_async;
char __pad_60[4]; char __pad_60[4];
}; };
@ -1925,7 +1925,7 @@ struct send_socket_request
{ {
struct request_header __header; struct request_header __header;
unsigned int flags; unsigned int flags;
async_data_t async; struct async_data async;
}; };
struct send_socket_reply struct send_socket_reply
{ {
@ -2016,7 +2016,7 @@ struct read_directory_changes_request
unsigned int filter; unsigned int filter;
int subtree; int subtree;
int want_data; int want_data;
async_data_t async; struct async_data async;
}; };
struct read_directory_changes_reply struct read_directory_changes_reply
{ {
@ -2970,7 +2970,7 @@ struct send_hardware_message_request
{ {
struct request_header __header; struct request_header __header;
user_handle_t win; user_handle_t win;
hw_input_t input; union hw_input input;
unsigned int flags; unsigned int flags;
/* VARARG(report,bytes); */ /* VARARG(report,bytes); */
char __pad_60[4]; char __pad_60[4];
@ -3152,7 +3152,7 @@ struct register_async_request
{ {
struct request_header __header; struct request_header __header;
int type; int type;
async_data_t async; struct async_data async;
int count; int count;
char __pad_60[4]; char __pad_60[4];
}; };
@ -3216,7 +3216,7 @@ struct read_request
{ {
struct request_header __header; struct request_header __header;
char __pad_12[4]; char __pad_12[4];
async_data_t async; struct async_data async;
file_pos_t pos; file_pos_t pos;
}; };
struct read_reply struct read_reply
@ -3233,7 +3233,7 @@ struct write_request
{ {
struct request_header __header; struct request_header __header;
char __pad_12[4]; char __pad_12[4];
async_data_t async; struct async_data async;
file_pos_t pos; file_pos_t pos;
/* VARARG(data,bytes); */ /* VARARG(data,bytes); */
}; };
@ -3252,7 +3252,7 @@ struct ioctl_request
{ {
struct request_header __header; struct request_header __header;
ioctl_code_t code; ioctl_code_t code;
async_data_t async; struct async_data async;
/* VARARG(in_data,bytes); */ /* VARARG(in_data,bytes); */
}; };
struct ioctl_reply struct ioctl_reply
@ -5239,7 +5239,7 @@ struct get_next_device_request_request
struct get_next_device_request_reply struct get_next_device_request_reply
{ {
struct reply_header __header; struct reply_header __header;
irp_params_t params; union irp_params params;
obj_handle_t next; obj_handle_t next;
thread_id_t client_tid; thread_id_t client_tid;
client_ptr_t client_thread; client_ptr_t client_thread;
@ -6758,10 +6758,6 @@ union generic_reply
struct set_keyboard_repeat_reply set_keyboard_repeat_reply; struct set_keyboard_repeat_reply set_keyboard_repeat_reply;
}; };
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 848 #define SERVER_PROTOCOL_VERSION 848
/* ### protocol_version end ### */
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View file

@ -365,7 +365,7 @@ int __cdecl wmain(int argc, const WCHAR* argv[])
if(arg_is(argv[2], L"/help")) if(arg_is(argv[2], L"/help"))
output_string(STRING_STOP_USAGE); output_string(STRING_STOP_USAGE);
else if(!net_service(NET_STOP, argv[2])) else if(!net_service(NET_STOP, argv[2]))
return 1; return 2;
} }
else if(arg_is(argv[1], L"use")) else if(arg_is(argv[1], L"use"))
{ {

View file

@ -0,0 +1,4 @@
TESTDLL = net.exe
SOURCES = \
net.c

78
programs/net/tests/net.c Normal file
View file

@ -0,0 +1,78 @@
/*
* Copyright 2024 Fabian Maurer
*
* 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
*/
#include <windows.h>
#include <stdio.h>
#include "wine/test.h"
static HANDLE nul_file;
#define check_exit_code(x) ok(r == (x), "got exit code %ld, expected %d\n", r, (x))
/* Copied and modified from the reg.exe tests */
#define run_net_exe(c,r) run_net_exe_(__FILE__,__LINE__,c,r)
static BOOL run_net_exe_(const char *file, unsigned line, const char *cmd, DWORD *rc)
{
STARTUPINFOA si = {sizeof(STARTUPINFOA)};
PROCESS_INFORMATION pi;
BOOL bret;
DWORD ret;
char cmdline[256];
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = nul_file;
si.hStdOutput = nul_file;
si.hStdError = nul_file;
strcpy(cmdline, cmd);
if (!CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
return FALSE;
ret = WaitForSingleObject(pi.hProcess, 10000);
if (ret == WAIT_TIMEOUT)
TerminateProcess(pi.hProcess, 1);
bret = GetExitCodeProcess(pi.hProcess, rc);
ok_(__FILE__, line)(bret, "GetExitCodeProcess failed: %ld\n", GetLastError());
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return bret;
}
static void test_stop(void)
{
DWORD r;
/* Stop non existing service */
run_net_exe("net stop non-existing-service", &r);
check_exit_code(2);
}
START_TEST(net)
{
SECURITY_ATTRIBUTES secattr = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
nul_file = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE, 0, &secattr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
test_stop();
CloseHandle(nul_file);
}

View file

@ -45,7 +45,7 @@ struct async
struct timeout_user *timeout; struct timeout_user *timeout;
unsigned int timeout_status; /* status to report upon timeout */ unsigned int timeout_status; /* status to report upon timeout */
struct event *event; struct event *event;
async_data_t data; /* data for async I/O call */ struct async_data data; /* data for async I/O call */
struct iosb *iosb; /* I/O status block */ struct iosb *iosb; /* I/O status block */
obj_handle_t wait_handle; /* pre-allocated wait handle */ obj_handle_t wait_handle; /* pre-allocated wait handle */
unsigned int initial_status; /* status returned from initial request */ unsigned int initial_status; /* status returned from initial request */
@ -180,7 +180,7 @@ void async_terminate( struct async *async, unsigned int status )
if (!async->direct_result) if (!async->direct_result)
{ {
apc_call_t data; union apc_call data;
memset( &data, 0, sizeof(data) ); memset( &data, 0, sizeof(data) );
data.type = APC_ASYNC_IO; data.type = APC_ASYNC_IO;
@ -248,7 +248,7 @@ void queue_async( struct async_queue *queue, struct async *async )
} }
/* create an async on a given queue of a fd */ /* create an async on a given queue of a fd */
struct async *create_async( struct fd *fd, struct thread *thread, const async_data_t *data, struct iosb *iosb ) struct async *create_async( struct fd *fd, struct thread *thread, const struct async_data *data, struct iosb *iosb )
{ {
struct event *event = NULL; struct event *event = NULL;
struct async *async; struct async *async;
@ -515,7 +515,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
{ {
if (async->data.apc) if (async->data.apc)
{ {
apc_call_t data; union apc_call data;
memset( &data, 0, sizeof(data) ); memset( &data, 0, sizeof(data) );
data.type = APC_USER; data.type = APC_USER;
data.user.func = async->data.apc; data.user.func = async->data.apc;
@ -753,7 +753,7 @@ static struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_
/* create an async associated with iosb for async-based requests /* create an async associated with iosb for async-based requests
* returned async must be passed to async_handoff */ * returned async must be passed to async_handoff */
struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data, int is_system ) struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const struct async_data *data, int is_system )
{ {
struct async *async; struct async *async;
struct iosb *iosb; struct iosb *iosb;

View file

@ -48,7 +48,7 @@ struct debug_event
struct file *file; /* file object for events that need one */ struct file *file; /* file object for events that need one */
enum debug_event_state state; /* event state */ enum debug_event_state state; /* event state */
int status; /* continuation status */ int status; /* continuation status */
debug_event_t data; /* event data */ union debug_event_data data; /* event data */
}; };
static const WCHAR debug_obj_name[] = {'D','e','b','u','g','O','b','j','e','c','t'}; static const WCHAR debug_obj_name[] = {'D','e','b','u','g','O','b','j','e','c','t'};
@ -142,7 +142,7 @@ static client_ptr_t get_teb_user_ptr( struct thread *thread )
static void fill_exception_event( struct debug_event *event, const void *arg ) static void fill_exception_event( struct debug_event *event, const void *arg )
{ {
const debug_event_t *data = arg; const union debug_event_data *data = arg;
event->data.exception = data->exception; event->data.exception = data->exception;
event->data.exception.nb_params = min( event->data.exception.nb_params, EXCEPTION_MAXIMUM_PARAMETERS ); event->data.exception.nb_params = min( event->data.exception.nb_params, EXCEPTION_MAXIMUM_PARAMETERS );
} }
@ -641,7 +641,7 @@ DECL_HANDLER(queue_exception_event)
reply->handle = 0; reply->handle = 0;
if (debug_obj) if (debug_obj)
{ {
debug_event_t data; union debug_event_data data;
struct debug_event *event; struct debug_event *event;
struct thread *thread = current; struct thread *thread = current;

View file

@ -49,7 +49,7 @@ struct irp_call
struct device_file *file; /* file containing this irp */ struct device_file *file; /* file containing this irp */
struct thread *thread; /* thread that queued the irp */ struct thread *thread; /* thread that queued the irp */
struct async *async; /* pending async op */ struct async *async; /* pending async op */
irp_params_t params; /* irp parameters */ union irp_params params; /* irp parameters */
struct iosb *iosb; /* I/O status block */ struct iosb *iosb; /* I/O status block */
int canceled; /* the call was canceled */ int canceled; /* the call was canceled */
client_ptr_t user_ptr; /* client side pointer */ client_ptr_t user_ptr; /* client side pointer */
@ -348,7 +348,8 @@ static void irp_call_destroy( struct object *obj )
if (irp->thread) release_object( irp->thread ); if (irp->thread) release_object( irp->thread );
} }
static struct irp_call *create_irp( struct device_file *file, const irp_params_t *params, struct async *async ) static struct irp_call *create_irp( struct device_file *file, const union irp_params *params,
struct async *async )
{ {
struct irp_call *irp; struct irp_call *irp;
@ -455,7 +456,7 @@ static struct object *device_open_file( struct object *obj, unsigned int access,
if (device->manager) if (device->manager)
{ {
struct irp_call *irp; struct irp_call *irp;
irp_params_t params; union irp_params params;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
params.create.type = IRP_CALL_CREATE; params.create.type = IRP_CALL_CREATE;
@ -512,7 +513,7 @@ static int device_file_close_handle( struct object *obj, struct process *process
if (!file->closed && file->device->manager && obj->handle_count == 1) /* last handle */ if (!file->closed && file->device->manager && obj->handle_count == 1) /* last handle */
{ {
struct irp_call *irp; struct irp_call *irp;
irp_params_t params; union irp_params params;
file->closed = 1; file->closed = 1;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
@ -542,7 +543,7 @@ static void device_file_destroy( struct object *obj )
release_object( file->device ); release_object( file->device );
} }
static int fill_irp_params( struct device_manager *manager, struct irp_call *irp, irp_params_t *params ) static int fill_irp_params( struct device_manager *manager, struct irp_call *irp, union irp_params *params )
{ {
switch (irp->params.type) switch (irp->params.type)
{ {
@ -595,7 +596,7 @@ static void free_irp_params( struct irp_call *irp )
} }
/* queue an irp to the device */ /* queue an irp to the device */
static void queue_irp( struct device_file *file, const irp_params_t *params, struct async *async ) static void queue_irp( struct device_file *file, const union irp_params *params, struct async *async )
{ {
struct irp_call *irp = create_irp( file, params, async ); struct irp_call *irp = create_irp( file, params, async );
if (!irp) return; if (!irp) return;
@ -615,7 +616,7 @@ static enum server_fd_type device_file_get_fd_type( struct fd *fd )
static void device_file_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class ) static void device_file_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class )
{ {
struct device_file *file = get_fd_user( fd ); struct device_file *file = get_fd_user( fd );
irp_params_t params; union irp_params params;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
params.volume.type = IRP_CALL_VOLUME; params.volume.type = IRP_CALL_VOLUME;
@ -626,7 +627,7 @@ static void device_file_get_volume_info( struct fd *fd, struct async *async, uns
static void device_file_read( struct fd *fd, struct async *async, file_pos_t pos ) static void device_file_read( struct fd *fd, struct async *async, file_pos_t pos )
{ {
struct device_file *file = get_fd_user( fd ); struct device_file *file = get_fd_user( fd );
irp_params_t params; union irp_params params;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
params.read.type = IRP_CALL_READ; params.read.type = IRP_CALL_READ;
@ -638,7 +639,7 @@ static void device_file_read( struct fd *fd, struct async *async, file_pos_t pos
static void device_file_write( struct fd *fd, struct async *async, file_pos_t pos ) static void device_file_write( struct fd *fd, struct async *async, file_pos_t pos )
{ {
struct device_file *file = get_fd_user( fd ); struct device_file *file = get_fd_user( fd );
irp_params_t params; union irp_params params;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
params.write.type = IRP_CALL_WRITE; params.write.type = IRP_CALL_WRITE;
@ -650,7 +651,7 @@ static void device_file_write( struct fd *fd, struct async *async, file_pos_t po
static void device_file_flush( struct fd *fd, struct async *async ) static void device_file_flush( struct fd *fd, struct async *async )
{ {
struct device_file *file = get_fd_user( fd ); struct device_file *file = get_fd_user( fd );
irp_params_t params; union irp_params params;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
params.flush.type = IRP_CALL_FLUSH; params.flush.type = IRP_CALL_FLUSH;
@ -660,7 +661,7 @@ static void device_file_flush( struct fd *fd, struct async *async )
static void device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) static void device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
{ {
struct device_file *file = get_fd_user( fd ); struct device_file *file = get_fd_user( fd );
irp_params_t params; union irp_params params;
memset( &params, 0, sizeof(params) ); memset( &params, 0, sizeof(params) );
params.ioctl.type = IRP_CALL_IOCTL; params.ioctl.type = IRP_CALL_IOCTL;
@ -671,7 +672,7 @@ static void device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *a
static void cancel_irp_call( struct irp_call *irp ) static void cancel_irp_call( struct irp_call *irp )
{ {
struct irp_call *cancel_irp; struct irp_call *cancel_irp;
irp_params_t params; union irp_params params;
irp->canceled = 1; irp->canceled = 1;
if (!irp->user_ptr || !irp->file || !irp->file->device->manager) return; if (!irp->user_ptr || !irp->file || !irp->file->device->manager) return;
@ -842,7 +843,7 @@ void free_kernel_objects( struct object *obj )
{ {
struct kernel_object *kernel_object = LIST_ENTRY( ptr, struct kernel_object, list_entry ); struct kernel_object *kernel_object = LIST_ENTRY( ptr, struct kernel_object, list_entry );
struct irp_call *irp; struct irp_call *irp;
irp_params_t params; union irp_params params;
assert( !kernel_object->owned ); assert( !kernel_object->owned );

View file

@ -248,7 +248,7 @@ static void keyed_event_dump( struct object *obj, int verbose )
fputs( "Keyed event\n", stderr ); fputs( "Keyed event\n", stderr );
} }
static enum select_op matching_op( enum select_op op ) static enum select_opcode matching_op( enum select_opcode op )
{ {
return op ^ (SELECT_KEYED_EVENT_WAIT ^ SELECT_KEYED_EVENT_RELEASE); return op ^ (SELECT_KEYED_EVENT_WAIT ^ SELECT_KEYED_EVENT_RELEASE);
} }
@ -257,7 +257,7 @@ static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *en
{ {
struct wait_queue_entry *ptr; struct wait_queue_entry *ptr;
struct process *process; struct process *process;
enum select_op select_op; enum select_opcode select_op;
assert( obj->ops == &keyed_event_ops ); assert( obj->ops == &keyed_event_ops );

View file

@ -252,8 +252,8 @@ extern struct object *create_serial( struct fd *fd );
typedef void (*async_completion_callback)( void *private ); typedef void (*async_completion_callback)( void *private );
extern void free_async_queue( struct async_queue *queue ); extern void free_async_queue( struct async_queue *queue );
extern struct async *create_async( struct fd *fd, struct thread *thread, const async_data_t *data, struct iosb *iosb ); extern struct async *create_async( struct fd *fd, struct thread *thread, const struct async_data *data, struct iosb *iosb );
extern struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data, extern struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const struct async_data *data,
int is_system ); int is_system );
extern obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_blocking ); extern obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_blocking );
extern void queue_async( struct async_queue *queue, struct async *async ); extern void queue_async( struct async_queue *queue, struct async *async );

View file

@ -262,6 +262,9 @@ void init_memory(void)
page_mask = sysconf( _SC_PAGESIZE ) - 1; page_mask = sysconf( _SC_PAGESIZE ) - 1;
free_map_addr( 0x60000000, 0x1c000000 ); free_map_addr( 0x60000000, 0x1c000000 );
free_map_addr( 0x600000000000, 0x100000000000 ); free_map_addr( 0x600000000000, 0x100000000000 );
if (page_mask != 0xfff)
fprintf( stderr, "wineserver: page size is %uk but Wine requires 4k pages, expect problems\n",
(int)(page_mask + 1) / 1024 );
} }
static void ranges_dump( struct object *obj, int verbose ) static void ranges_dump( struct object *obj, int verbose )

View file

@ -73,7 +73,7 @@ struct request_max_size
/* debug event data */ /* debug event data */
typedef union union debug_event_data
{ {
int code; /* event code */ int code; /* event code */
struct struct
@ -125,7 +125,7 @@ typedef union
int __pad; int __pad;
mod_handle_t base; /* base address of the dll */ mod_handle_t base; /* base address of the dll */
} unload_dll; } unload_dll;
} debug_event_t; };
enum context_exec_space enum context_exec_space
@ -276,7 +276,7 @@ typedef struct
} rectangle_t; } rectangle_t;
/* structure for parameters of async I/O calls */ /* structure for parameters of async I/O calls */
typedef struct struct async_data
{ {
obj_handle_t handle; /* object to perform I/O on */ obj_handle_t handle; /* object to perform I/O on */
obj_handle_t event; /* event to signal when done */ obj_handle_t event; /* event to signal when done */
@ -284,7 +284,7 @@ typedef struct
client_ptr_t user; /* opaque user data containing callback pointer and async-specific data */ client_ptr_t user; /* opaque user data containing callback pointer and async-specific data */
client_ptr_t apc; /* user APC to call */ client_ptr_t apc; /* user APC to call */
apc_param_t apc_context; /* user APC context or completion value */ apc_param_t apc_context; /* user APC context or completion value */
} async_data_t; };
/* structures for extra message data */ /* structures for extra message data */
@ -328,7 +328,7 @@ struct winevent_msg_data
/* followed by module name if any */ /* followed by module name if any */
}; };
typedef union union hw_input
{ {
int type; int type;
struct struct
@ -358,15 +358,15 @@ typedef union
lparam_t lparam; /* parameters */ lparam_t lparam; /* parameters */
struct hid_input hid; /* defined in ntuser.h */ struct hid_input hid; /* defined in ntuser.h */
} hw; } hw;
} hw_input_t; };
typedef union union message_data
{ {
unsigned char bytes[1]; /* raw data for sent messages */ unsigned char bytes[1]; /* raw data for sent messages */
struct hardware_msg_data hardware; struct hardware_msg_data hardware;
struct callback_msg_data callback; struct callback_msg_data callback;
struct winevent_msg_data winevent; struct winevent_msg_data winevent;
} message_data_t; };
/* structure returned in filesystem events */ /* structure returned in filesystem events */
struct filesystem_event struct filesystem_event
@ -451,7 +451,7 @@ struct object_type_info
/* VARARG(name,unicode_str); */ /* VARARG(name,unicode_str); */
}; };
enum select_op enum select_opcode
{ {
SELECT_NONE, SELECT_NONE,
SELECT_WAIT, SELECT_WAIT,
@ -461,28 +461,28 @@ enum select_op
SELECT_KEYED_EVENT_RELEASE SELECT_KEYED_EVENT_RELEASE
}; };
typedef union union select_op
{ {
enum select_op op; enum select_opcode op;
struct struct
{ {
enum select_op op; /* SELECT_WAIT or SELECT_WAIT_ALL */ enum select_opcode op; /* SELECT_WAIT or SELECT_WAIT_ALL */
obj_handle_t handles[MAXIMUM_WAIT_OBJECTS]; obj_handle_t handles[MAXIMUM_WAIT_OBJECTS];
int __pad; int __pad;
} wait; } wait;
struct struct
{ {
enum select_op op; /* SELECT_SIGNAL_AND_WAIT */ enum select_opcode op; /* SELECT_SIGNAL_AND_WAIT */
obj_handle_t wait; obj_handle_t wait;
obj_handle_t signal; /* must be last in the structure so we can remove it on retries */ obj_handle_t signal; /* must be last in the structure so we can remove it on retries */
} signal_and_wait; } signal_and_wait;
struct struct
{ {
enum select_op op; /* SELECT_KEYED_EVENT_WAIT or SELECT_KEYED_EVENT_RELEASE */ enum select_opcode op; /* SELECT_KEYED_EVENT_WAIT or SELECT_KEYED_EVENT_RELEASE */
obj_handle_t handle; obj_handle_t handle;
client_ptr_t key; client_ptr_t key;
} keyed_event; } keyed_event;
} select_op_t; };
enum apc_type enum apc_type
{ {
@ -504,18 +504,18 @@ enum apc_type
APC_DUP_HANDLE APC_DUP_HANDLE
}; };
typedef struct struct user_apc
{ {
enum apc_type type; /* APC_USER */ enum apc_type type; /* APC_USER */
int __pad; int __pad;
client_ptr_t func; /* void (__stdcall *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR); */ client_ptr_t func; /* void (__stdcall *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR); */
apc_param_t args[3]; /* arguments for user function */ apc_param_t args[3]; /* arguments for user function */
} user_apc_t; };
typedef union union apc_call
{ {
enum apc_type type; enum apc_type type;
user_apc_t user; struct user_apc user;
struct struct
{ {
enum apc_type type; /* APC_ASYNC_IO */ enum apc_type type; /* APC_ASYNC_IO */
@ -636,9 +636,9 @@ typedef union
unsigned int attributes; /* object attributes */ unsigned int attributes; /* object attributes */
unsigned int options; /* duplicate options */ unsigned int options; /* duplicate options */
} dup_handle; } dup_handle;
} apc_call_t; };
typedef union union apc_result
{ {
enum apc_type type; enum apc_type type;
struct struct
@ -748,7 +748,7 @@ typedef union
enum apc_type type; /* APC_BREAK_PROCESS */ enum apc_type type; /* APC_BREAK_PROCESS */
unsigned int status; /* status returned by call */ unsigned int status; /* status returned by call */
} break_process; } break_process;
} apc_result_t; };
enum irp_type enum irp_type
{ {
@ -764,7 +764,7 @@ enum irp_type
IRP_CALL_CANCEL IRP_CALL_CANCEL
}; };
typedef union union irp_params
{ {
enum irp_type type; /* irp call type */ enum irp_type type; /* irp call type */
struct struct
@ -832,7 +832,7 @@ typedef union
int __pad; int __pad;
client_ptr_t irp; /* opaque ptr for canceled irp */ client_ptr_t irp; /* opaque ptr for canceled irp */
} cancel; } cancel;
} irp_params_t; };
/* information about a PE image mapping, roughly equivalent to SECTION_IMAGE_INFORMATION */ /* information about a PE image mapping, roughly equivalent to SECTION_IMAGE_INFORMATION */
typedef struct typedef struct
@ -1232,7 +1232,7 @@ typedef struct
@REQ(get_apc_result) @REQ(get_apc_result)
obj_handle_t handle; /* handle to the APC */ obj_handle_t handle; /* handle to the APC */
@REPLY @REPLY
apc_result_t result; /* result of the APC */ union apc_result result; /* result of the APC */
@END @END
@ -1539,7 +1539,7 @@ enum server_fd_type
/* Flush a file buffers */ /* Flush a file buffers */
@REQ(flush) @REQ(flush)
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
@REPLY @REPLY
obj_handle_t event; /* event set when finished */ obj_handle_t event; /* event set when finished */
@END @END
@ -1555,7 +1555,7 @@ enum server_fd_type
/* Query volume information */ /* Query volume information */
@REQ(get_volume_info) @REQ(get_volume_info)
obj_handle_t handle; /* handle to the file */ obj_handle_t handle; /* handle to the file */
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
unsigned int info_class; /* queried information class */ unsigned int info_class; /* queried information class */
@REPLY @REPLY
obj_handle_t wait; /* handle to wait on for blocking read */ obj_handle_t wait; /* handle to wait on for blocking read */
@ -1586,7 +1586,7 @@ enum server_fd_type
/* Perform a recv on a socket */ /* Perform a recv on a socket */
@REQ(recv_socket) @REQ(recv_socket)
int oob; /* are we receiving OOB data? */ int oob; /* are we receiving OOB data? */
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
int force_async; /* Force asynchronous mode? */ int force_async; /* Force asynchronous mode? */
@REPLY @REPLY
obj_handle_t wait; /* handle to wait on for blocking recv */ obj_handle_t wait; /* handle to wait on for blocking recv */
@ -1598,7 +1598,7 @@ enum server_fd_type
/* Perform a send on a socket */ /* Perform a send on a socket */
@REQ(send_socket) @REQ(send_socket)
unsigned int flags; /* SERVER_SOCKET_IO_* flags */ unsigned int flags; /* SERVER_SOCKET_IO_* flags */
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
@REPLY @REPLY
obj_handle_t wait; /* handle to wait on for blocking send */ obj_handle_t wait; /* handle to wait on for blocking send */
unsigned int options; /* device open options */ unsigned int options; /* device open options */
@ -1656,7 +1656,7 @@ enum server_fd_type
unsigned int filter; /* notification filter */ unsigned int filter; /* notification filter */
int subtree; /* watch the subtree? */ int subtree; /* watch the subtree? */
int want_data; /* flag indicating whether change data should be collected */ int want_data; /* flag indicating whether change data should be collected */
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
@END @END
@ -2241,7 +2241,7 @@ enum message_type
/* Send a hardware message to a thread queue */ /* Send a hardware message to a thread queue */
@REQ(send_hardware_message) @REQ(send_hardware_message)
user_handle_t win; /* window handle */ user_handle_t win; /* window handle */
hw_input_t input; /* input data */ union hw_input input; /* input data */
unsigned int flags; /* flags (see below) */ unsigned int flags; /* flags (see below) */
VARARG(report,bytes); /* HID report data */ VARARG(report,bytes); /* HID report data */
@REPLY @REPLY
@ -2355,7 +2355,7 @@ enum message_type
/* Create an async I/O */ /* Create an async I/O */
@REQ(register_async) @REQ(register_async)
int type; /* type of queue to look after */ int type; /* type of queue to look after */
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
int count; /* count - usually # of bytes to be read/written */ int count; /* count - usually # of bytes to be read/written */
@END @END
#define ASYNC_TYPE_READ 0x01 #define ASYNC_TYPE_READ 0x01
@ -2392,7 +2392,7 @@ enum message_type
/* Perform a read on a file object */ /* Perform a read on a file object */
@REQ(read) @REQ(read)
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
file_pos_t pos; /* read position */ file_pos_t pos; /* read position */
@REPLY @REPLY
obj_handle_t wait; /* handle to wait on for blocking read */ obj_handle_t wait; /* handle to wait on for blocking read */
@ -2403,7 +2403,7 @@ enum message_type
/* Perform a write on a file object */ /* Perform a write on a file object */
@REQ(write) @REQ(write)
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
file_pos_t pos; /* write position */ file_pos_t pos; /* write position */
VARARG(data,bytes); /* write data */ VARARG(data,bytes); /* write data */
@REPLY @REPLY
@ -2416,7 +2416,7 @@ enum message_type
/* Perform an ioctl on a file */ /* Perform an ioctl on a file */
@REQ(ioctl) @REQ(ioctl)
ioctl_code_t code; /* ioctl code */ ioctl_code_t code; /* ioctl code */
async_data_t async; /* async I/O parameters */ struct async_data async; /* async I/O parameters */
VARARG(in_data,bytes); /* ioctl input data */ VARARG(in_data,bytes); /* ioctl input data */
@REPLY @REPLY
obj_handle_t wait; /* handle to wait on for blocking ioctl */ obj_handle_t wait; /* handle to wait on for blocking ioctl */
@ -3695,7 +3695,7 @@ typedef union
data_size_t result; /* IOSB result of the previous irp */ data_size_t result; /* IOSB result of the previous irp */
VARARG(data,bytes); /* output data of the previous irp */ VARARG(data,bytes); /* output data of the previous irp */
@REPLY @REPLY
irp_params_t params; /* irp parameters */ union irp_params params; /* irp parameters */
obj_handle_t next; /* handle to the next irp */ obj_handle_t next; /* handle to the next irp */
thread_id_t client_tid; /* tid of thread calling irp */ thread_id_t client_tid; /* tid of thread calling irp */
client_ptr_t client_thread; /* pointer to thread object of calling irp */ client_ptr_t client_thread; /* pointer to thread object of calling irp */

View file

@ -2106,7 +2106,7 @@ static void rawkeyboard_init( struct rawinput *rawinput, RAWKEYBOARD *keyboard,
keyboard->ExtraInformation = info; keyboard->ExtraInformation = info;
} }
static void rawhid_init( struct rawinput *rawinput, RAWHID *hid, const hw_input_t *input ) static void rawhid_init( struct rawinput *rawinput, RAWHID *hid, const union hw_input *input )
{ {
rawinput->type = RIM_TYPEHID; rawinput->type = RIM_TYPEHID;
rawinput->device = input->hw.hid.device; rawinput->device = input->hw.hid.device;
@ -2203,7 +2203,7 @@ static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_
} }
/* queue a hardware message for a mouse event */ /* queue a hardware message for a mouse event */
static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const union hw_input *input,
unsigned int origin, struct msg_queue *sender ) unsigned int origin, struct msg_queue *sender )
{ {
const desktop_shm_t *desktop_shm = desktop->shared; const desktop_shm_t *desktop_shm = desktop->shared;
@ -2309,7 +2309,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
return wait; return wait;
} }
static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const union hw_input *input,
unsigned int origin, struct msg_queue *sender, int repeat ); unsigned int origin, struct msg_queue *sender, int repeat );
static void key_repeat_timeout( void *private ) static void key_repeat_timeout( void *private )
@ -2329,7 +2329,7 @@ static void stop_key_repeat( struct desktop *desktop )
} }
/* queue a hardware message for a keyboard event */ /* queue a hardware message for a keyboard event */
static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const union hw_input *input,
unsigned int origin, struct msg_queue *sender, int repeat ) unsigned int origin, struct msg_queue *sender, int repeat )
{ {
const desktop_shm_t *desktop_shm = desktop->shared; const desktop_shm_t *desktop_shm = desktop->shared;
@ -2502,7 +2502,7 @@ struct pointer
struct desktop *desktop; struct desktop *desktop;
user_handle_t win; user_handle_t win;
int primary; int primary;
hw_input_t input; union hw_input input;
}; };
static void queue_pointer_message( struct pointer *pointer, int repeated ); static void queue_pointer_message( struct pointer *pointer, int repeated );
@ -2524,7 +2524,7 @@ static void queue_pointer_message( struct pointer *pointer, int repeated )
struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH }; struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH };
struct desktop *desktop = pointer->desktop; struct desktop *desktop = pointer->desktop;
const desktop_shm_t *desktop_shm = desktop->shared; const desktop_shm_t *desktop_shm = desktop->shared;
const hw_input_t *input = &pointer->input; const union hw_input *input = &pointer->input;
unsigned int i, wparam = input->hw.wparam; unsigned int i, wparam = input->hw.wparam;
timeout_t time = get_tick_count(); timeout_t time = get_tick_count();
user_handle_t win = pointer->win; user_handle_t win = pointer->win;
@ -2600,7 +2600,7 @@ static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned i
/* queue a hardware message for a custom type of event */ /* queue a hardware message for a custom type of event */
static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win, static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win,
unsigned int origin, const hw_input_t *input ) unsigned int origin, const union hw_input *input )
{ {
const desktop_shm_t *desktop_shm = desktop->shared; const desktop_shm_t *desktop_shm = desktop->shared;
struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };

View file

@ -60,8 +60,7 @@
#include "thread.h" #include "thread.h"
#include "security.h" #include "security.h"
#include "handle.h" #include "handle.h"
#define WANT_REQUEST_HANDLERS #include "request_handlers.h"
#include "request.h"
/* Some versions of glibc don't define this */ /* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS #ifndef SCM_RIGHTS

File diff suppressed because it is too large Load diff

2264
server/request_handlers.h generated Normal file

File diff suppressed because it is too large Load diff

4399
server/request_trace.h generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -61,7 +61,7 @@ struct thread_wait
int count; /* count of objects */ int count; /* count of objects */
int flags; int flags;
int abandoned; int abandoned;
enum select_op select; enum select_opcode select;
client_ptr_t key; /* wait key for keyed events */ client_ptr_t key; /* wait key for keyed events */
client_ptr_t cookie; /* magic cookie to return to client */ client_ptr_t cookie; /* magic cookie to return to client */
abstime_t when; abstime_t when;
@ -79,8 +79,8 @@ struct thread_apc
struct thread *caller; /* thread that queued this apc */ struct thread *caller; /* thread that queued this apc */
struct object *owner; /* object that queued this apc */ struct object *owner; /* object that queued this apc */
int executed; /* has it been executed by the client? */ int executed; /* has it been executed by the client? */
apc_call_t call; /* call arguments */ union apc_call call; /* call arguments */
apc_result_t result; /* call results once executed */ union apc_result result; /* call results once executed */
}; };
static void dump_thread_apc( struct object *obj, int verbose ); static void dump_thread_apc( struct object *obj, int verbose );
@ -508,7 +508,7 @@ static void thread_apc_destroy( struct object *obj )
} }
/* queue an async procedure call */ /* queue an async procedure call */
static struct thread_apc *create_apc( struct object *owner, const apc_call_t *call_data ) static struct thread_apc *create_apc( struct object *owner, const union apc_call *call_data )
{ {
struct thread_apc *apc; struct thread_apc *apc;
@ -721,7 +721,7 @@ struct thread *get_wait_queue_thread( struct wait_queue_entry *entry )
return entry->wait->thread; return entry->wait->thread;
} }
enum select_op get_wait_queue_select_op( struct wait_queue_entry *entry ) enum select_opcode get_wait_queue_select_op( struct wait_queue_entry *entry )
{ {
return entry->wait->select; return entry->wait->select;
} }
@ -775,7 +775,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status )
} }
/* build the thread wait structure */ /* build the thread wait structure */
static int wait_on( const select_op_t *select_op, unsigned int count, struct object *objects[], static int wait_on( const union select_op *select_op, unsigned int count, struct object *objects[],
int flags, abstime_t when ) int flags, abstime_t when )
{ {
struct thread_wait *wait; struct thread_wait *wait;
@ -812,7 +812,7 @@ static int wait_on( const select_op_t *select_op, unsigned int count, struct obj
return current->wait ? 1 : 0; return current->wait ? 1 : 0;
} }
static int wait_on_handles( const select_op_t *select_op, unsigned int count, const obj_handle_t *handles, static int wait_on_handles( const union select_op *select_op, unsigned int count, const obj_handle_t *handles,
int flags, abstime_t when ) int flags, abstime_t when )
{ {
struct object *objects[MAXIMUM_WAIT_OBJECTS]; struct object *objects[MAXIMUM_WAIT_OBJECTS];
@ -981,7 +981,7 @@ static int signal_object( obj_handle_t handle )
} }
/* select on a list of handles */ /* select on a list of handles */
static int select_on( const select_op_t *select_op, data_size_t op_size, client_ptr_t cookie, static int select_on( const union select_op *select_op, data_size_t op_size, client_ptr_t cookie,
int flags, abstime_t when ) int flags, abstime_t when )
{ {
int ret; int ret;
@ -996,8 +996,8 @@ static int select_on( const select_op_t *select_op, data_size_t op_size, client_
case SELECT_WAIT: case SELECT_WAIT:
case SELECT_WAIT_ALL: case SELECT_WAIT_ALL:
count = (op_size - offsetof( select_op_t, wait.handles )) / sizeof(select_op->wait.handles[0]); count = (op_size - offsetof( union select_op, wait.handles )) / sizeof(select_op->wait.handles[0]);
if (op_size < offsetof( select_op_t, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS) if (op_size < offsetof( union select_op, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS)
{ {
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return 1; return 1;
@ -1155,7 +1155,7 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr
} }
/* queue an async procedure call */ /* queue an async procedure call */
int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const apc_call_t *call_data ) int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const union apc_call *call_data )
{ {
struct thread_apc *apc; struct thread_apc *apc;
int ret = 0; int ret = 0;
@ -1580,11 +1580,11 @@ DECL_HANDLER(resume_thread)
/* select on a handle list */ /* select on a handle list */
DECL_HANDLER(select) DECL_HANDLER(select)
{ {
select_op_t select_op; union select_op select_op;
data_size_t op_size, ctx_size; data_size_t op_size, ctx_size;
struct context *ctx; struct context *ctx;
struct thread_apc *apc; struct thread_apc *apc;
const apc_result_t *result = get_req_data(); const union apc_result *result = get_req_data();
unsigned int ctx_count; unsigned int ctx_count;
if (get_req_data_size() < sizeof(*result)) goto invalid_param; if (get_req_data_size() < sizeof(*result)) goto invalid_param;
@ -1665,13 +1665,13 @@ DECL_HANDLER(select)
reply->signaled = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout ); reply->signaled = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout );
if (get_error() == STATUS_USER_APC && get_reply_max_size() >= sizeof(apc_call_t)) if (get_error() == STATUS_USER_APC && get_reply_max_size() >= sizeof(union apc_call))
{ {
apc = thread_dequeue_apc( current, 0 ); apc = thread_dequeue_apc( current, 0 );
set_reply_data( &apc->call, sizeof(apc->call) ); set_reply_data( &apc->call, sizeof(apc->call) );
release_object( apc ); release_object( apc );
} }
else if (get_error() == STATUS_KERNEL_APC && get_reply_max_size() >= sizeof(apc_call_t)) else if (get_error() == STATUS_KERNEL_APC && get_reply_max_size() >= sizeof(union apc_call))
{ {
apc = thread_dequeue_apc( current, 1 ); apc = thread_dequeue_apc( current, 1 );
if ((reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 ))) if ((reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 )))
@ -1685,13 +1685,13 @@ DECL_HANDLER(select)
} }
release_object( apc ); release_object( apc );
} }
else if (reply->signaled && get_reply_max_size() >= sizeof(apc_call_t) + sizeof(context_t) && else if (reply->signaled && get_reply_max_size() >= sizeof(union apc_call) + sizeof(context_t) &&
current->context && current->suspend_cookie == req->cookie) current->context && current->suspend_cookie == req->cookie)
{ {
ctx = current->context; ctx = current->context;
if (ctx->regs[CTX_NATIVE].flags || ctx->regs[CTX_WOW].flags) if (ctx->regs[CTX_NATIVE].flags || ctx->regs[CTX_WOW].flags)
{ {
apc_call_t *data; union apc_call *data;
data_size_t size = sizeof(*data) + (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t); data_size_t size = sizeof(*data) + (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t);
unsigned int flags = system_flags & ctx->regs[CTX_NATIVE].flags; unsigned int flags = system_flags & ctx->regs[CTX_NATIVE].flags;
@ -1718,7 +1718,7 @@ DECL_HANDLER(queue_apc)
struct thread *thread = NULL; struct thread *thread = NULL;
struct process *process = NULL; struct process *process = NULL;
struct thread_apc *apc; struct thread_apc *apc;
const apc_call_t *call = get_req_data(); const union apc_call *call = get_req_data();
if (get_req_data_size() < sizeof(*call)) call = NULL; if (get_req_data_size() < sizeof(*call)) call = NULL;

View file

@ -106,7 +106,7 @@ extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int
extern struct thread *get_thread_from_tid( int tid ); extern struct thread *get_thread_from_tid( int tid );
extern struct thread *get_thread_from_pid( int pid ); extern struct thread *get_thread_from_pid( int pid );
extern struct thread *get_wait_queue_thread( struct wait_queue_entry *entry ); extern struct thread *get_wait_queue_thread( struct wait_queue_entry *entry );
extern enum select_op get_wait_queue_select_op( struct wait_queue_entry *entry ); extern enum select_opcode get_wait_queue_select_op( struct wait_queue_entry *entry );
extern client_ptr_t get_wait_queue_key( struct wait_queue_entry *entry ); extern client_ptr_t get_wait_queue_key( struct wait_queue_entry *entry );
extern void make_wait_abandoned( struct wait_queue_entry *entry ); extern void make_wait_abandoned( struct wait_queue_entry *entry );
extern void set_wait_status( struct wait_queue_entry *entry, int status ); extern void set_wait_status( struct wait_queue_entry *entry, int status );
@ -117,7 +117,7 @@ extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern void kill_thread( struct thread *thread, int violent_death ); extern void kill_thread( struct thread *thread, int violent_death );
extern void wake_up( struct object *obj, int max ); extern void wake_up( struct object *obj, int max );
extern int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const apc_call_t *call_data ); extern int thread_queue_apc( struct process *process, struct thread *thread, struct object *owner, const union apc_call *call_data );
extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type ); extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type );
extern int thread_add_inflight_fd( struct thread *thread, int client, int server ); extern int thread_add_inflight_fd( struct thread *thread, int client, int server );
extern int thread_get_inflight_fd( struct thread *thread, int client ); extern int thread_get_inflight_fd( struct thread *thread, int client );

View file

@ -123,7 +123,7 @@ static void timer_callback( void *private )
/* queue an APC */ /* queue an APC */
if (timer->thread) if (timer->thread)
{ {
apc_call_t data; union apc_call data;
assert (timer->callback); assert (timer->callback);
memset( &data, 0, sizeof(data) ); memset( &data, 0, sizeof(data) );

File diff suppressed because it is too large Load diff

View file

@ -62,7 +62,7 @@ struct key_repeat
int enable; /* enable auto-repeat */ int enable; /* enable auto-repeat */
timeout_t delay; /* auto-repeat delay */ timeout_t delay; /* auto-repeat delay */
timeout_t period; /* auto-repeat period */ timeout_t period; /* auto-repeat period */
hw_input_t input; /* the input to repeat */ union hw_input input; /* the input to repeat */
user_handle_t win; /* target window for input event */ user_handle_t win; /* target window for input event */
struct timeout_user *timeout; /* timeout for repeat */ struct timeout_user *timeout; /* timeout for repeat */
}; };

View file

@ -1,6 +1,6 @@
#! /usr/bin/perl -w #! /usr/bin/perl -w
# #
# Build the server/trace.c and server/request.h files # Build the server protocol definitions
# from the contents of server/protocol.def. # from the contents of server/protocol.def.
# #
# Copyright (C) 1998 Alexandre Julliard # Copyright (C) 1998 Alexandre Julliard
@ -32,55 +32,55 @@ my %formats =
"data_size_t" => [ 4, 4, "%u" ], "data_size_t" => [ 4, 4, "%u" ],
"obj_handle_t" => [ 4, 4, "%04x" ], "obj_handle_t" => [ 4, 4, "%04x" ],
"atom_t" => [ 4, 4, "%04x" ], "atom_t" => [ 4, 4, "%04x" ],
"user_handle_t" => [ 4, 4, "%08x" ],
"process_id_t" => [ 4, 4, "%04x" ], "process_id_t" => [ 4, 4, "%04x" ],
"thread_id_t" => [ 4, 4, "%04x" ], "thread_id_t" => [ 4, 4, "%04x" ],
"client_ptr_t" => [ 8, 8, "&dump_uint64" ], "unsigned __int64" => [ 8, 8, "&uint64" ],
"mod_handle_t" => [ 8, 8, "&dump_uint64" ], "timeout_t" => [ 8, 8 ],
"lparam_t" => [ 8, 8, "&dump_uint64" ], "abstime_t" => [ 8, 8 ],
"apc_param_t" => [ 8, 8, "&dump_uint64" ], "rectangle_t" => [ 16, 4 ],
"file_pos_t" => [ 8, 8, "&dump_uint64" ], "generic_map_t" => [ 16, 4 ],
"mem_size_t" => [ 8, 8, "&dump_uint64" ], "ioctl_code_t" => [ 4, 4 ],
"affinity_t" => [ 8, 8, "&dump_uint64" ], "obj_locator_t" => [ 16, 8 ],
"object_id_t" => [ 8, 8, "&dump_uint64" ],
"timeout_t" => [ 8, 8, "&dump_timeout" ],
"abstime_t" => [ 8, 8, "&dump_abstime" ],
"rectangle_t" => [ 16, 4, "&dump_rectangle" ],
"apc_result_t" => [ 40, 8, "&dump_apc_result" ],
"async_data_t" => [ 40, 8, "&dump_async_data" ],
"irp_params_t" => [ 32, 8, "&dump_irp_params" ],
"struct luid" => [ 8, 4, "&dump_luid" ],
"generic_map_t" => [ 16, 4, "&dump_generic_map" ],
"ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ],
"hw_input_t" => [ 40, 8, "&dump_hw_input" ],
"obj_locator_t" => [ 16, 8, "&dump_obj_locator" ],
# varargs-only structures # varargs-only structures
"apc_call_t" => [ 64, 8 ],
"context_t" => [ 1728, 8 ], "context_t" => [ 1728, 8 ],
"cursor_pos_t" => [ 24, 8 ], "cursor_pos_t" => [ 24, 8 ],
"debug_event_t" => [ 160, 8 ],
"message_data_t" => [ 48, 8 ],
"pe_image_info_t" => [ 88, 8 ], "pe_image_info_t" => [ 88, 8 ],
"property_data_t" => [ 16, 8 ], "property_data_t" => [ 16, 8 ],
"select_op_t" => [ 264, 8 ],
"startup_info_t" => [ 96, 4 ], "startup_info_t" => [ 96, 4 ],
"tcp_connection" => [ 60, 4 ], "tcp_connection" => [ 60, 4 ],
"udp_endpoint" => [ 32, 4 ], "udp_endpoint" => [ 32, 4 ],
"user_apc_t" => [ 40, 8 ], "union apc_call" => [ 64, 8 ],
"union apc_result" => [ 40, 8 ],
"struct async_data" => [ 40, 8 ],
"union debug_event_data" => [ 160, 8 ],
"struct filesystem_event" => [ 12, 4 ], "struct filesystem_event" => [ 12, 4 ],
"struct handle_info" => [ 20, 4 ], "struct handle_info" => [ 20, 4 ],
"union hw_input" => [ 40, 8 ],
"union irp_params" => [ 32, 8 ],
"struct luid" => [ 8, 4 ],
"struct luid_attr" => [ 12, 4 ], "struct luid_attr" => [ 12, 4 ],
"union message_data" => [ 48, 8 ],
"struct object_attributes" => [ 16, 4 ], "struct object_attributes" => [ 16, 4 ],
"struct object_type_info" => [ 44, 4 ], "struct object_type_info" => [ 44, 4 ],
"struct process_info" => [ 40, 8 ], "struct process_info" => [ 40, 8 ],
"struct rawinput_device" => [ 12, 4 ], "struct rawinput_device" => [ 12, 4 ],
"union select_op" => [ 264, 8 ],
"struct thread_info" => [ 40, 8 ], "struct thread_info" => [ 40, 8 ],
"struct user_apc" => [ 40, 8 ],
); );
my $file_header =
"/*\n * Wine server protocol definitions\n *\n" .
" * This file is automatically generated; DO NO EDIT!\n" .
" * Edit server/protocol.def instead and re-run tools/make_requests\n" .
" */\n\n";
my @requests = (); my @requests = ();
my %replies = (); my %replies = ();
my %dump_funcs = ();
my @asserts = (); my @asserts = ();
my @protocol_lines = ();
my @trace_lines = (); my @trace_lines = ();
my $max_req_size = 64; my $max_req_size = 64;
@ -93,7 +93,7 @@ sub add_padding($$)
if ($offset % $padding) if ($offset % $padding)
{ {
my $count = $padding - ($offset % $padding); my $count = $padding - ($offset % $padding);
print SERVER_PROT " char __pad_$offset\[$count\];\n"; push @protocol_lines, " char __pad_$offset\[$count\];\n";
$offset += $count; $offset += $count;
} }
return $offset; return $offset;
@ -115,10 +115,24 @@ sub DO_DUMP_FUNC($$@)
if (defined($formats{$type})) if (defined($formats{$type}))
{ {
my $fmt = ${$formats{$type}}[2]; my $fmt = ${$formats{$type}}[2];
if ($fmt =~ /^&(.*)/) while ($fmt && $fmt !~ /^[%&]/)
{
$type = $fmt;
$fmt = ${$formats{$type}}[2];
}
if (!$fmt)
{
my $func = $type;
$func =~ s/^(struct|union)\s+//;
$func =~ s/_t$//;
push @trace_lines, " dump_$func( \"$prefix$var=\", &req->$var );\n";
$dump_funcs{$func} = $type;
}
elsif ($fmt =~ /^&(.*)/)
{ {
my $func = $1; my $func = $1;
push @trace_lines, " $func( \"$prefix$var=\", &req->$var );\n"; push @trace_lines, " dump_$func( \"$prefix$var=\", &req->$var );\n";
$dump_funcs{$func} = $type;
} }
elsif ($fmt =~ /^(%.*)\s+\((.*)\)/) elsif ($fmt =~ /^(%.*)\s+\((.*)\)/)
{ {
@ -178,8 +192,8 @@ sub PARSE_REQUESTS()
@in_struct = (); @in_struct = ();
@out_struct = (); @out_struct = ();
$offset = 12; $offset = 12;
print SERVER_PROT "struct ${name}_request\n{\n"; push @protocol_lines, "struct ${name}_request\n{\n";
print SERVER_PROT " struct request_header __header;\n"; push @protocol_lines, " struct request_header __header;\n";
$state++; $state++;
next; next;
} }
@ -190,9 +204,9 @@ sub PARSE_REQUESTS()
$offset = add_padding( $offset, 8 ); # all requests should be 8-byte aligned $offset = add_padding( $offset, 8 ); # all requests should be 8-byte aligned
die "request $name too large ($offset)" if ($offset > $max_req_size); die "request $name too large ($offset)" if ($offset > $max_req_size);
push @asserts, "C_ASSERT( sizeof(struct ${name}_request) == $offset );\n"; push @asserts, "C_ASSERT( sizeof(struct ${name}_request) == $offset );\n";
print SERVER_PROT "};\n"; push @protocol_lines, "};\n";
print SERVER_PROT "struct ${name}_reply\n{\n"; push @protocol_lines, "struct ${name}_reply\n{\n";
print SERVER_PROT " struct reply_header __header;\n"; push @protocol_lines, " struct reply_header __header;\n";
$offset = 8; $offset = 8;
$state++; $state++;
next; next;
@ -203,14 +217,14 @@ sub PARSE_REQUESTS()
die "Misplaced \@END" unless ($state == 2 || $state == 3); die "Misplaced \@END" unless ($state == 2 || $state == 3);
$offset = add_padding( $offset, 8 ); # all requests should be 8-byte aligned $offset = add_padding( $offset, 8 ); # all requests should be 8-byte aligned
print SERVER_PROT "};\n"; push @protocol_lines, "};\n";
if ($state == 2) # build dummy reply struct if ($state == 2) # build dummy reply struct
{ {
die "request $name too large ($offset)" if ($offset > $max_req_size); die "request $name too large ($offset)" if ($offset > $max_req_size);
push @asserts, "C_ASSERT( sizeof(struct ${name}_request) == $offset );\n"; push @asserts, "C_ASSERT( sizeof(struct ${name}_request) == $offset );\n";
print SERVER_PROT "struct ${name}_reply\n{\n"; push @protocol_lines, "struct ${name}_reply\n{\n";
print SERVER_PROT " struct reply_header __header;\n"; push @protocol_lines, " struct reply_header __header;\n";
print SERVER_PROT "};\n"; push @protocol_lines, "};\n";
} }
else else
{ {
@ -234,26 +248,22 @@ sub PARSE_REQUESTS()
# skip empty lines (but keep them in output file) # skip empty lines (but keep them in output file)
if (/^$/) if (/^$/)
{ {
print SERVER_PROT "\n"; push @protocol_lines, "\n";
next; next;
} }
if (/^\s*VARARG\((\w+),(\w+),(\d+)\)/) if (/^\s*VARARG\((\w+),(\w+),(\w+)\)/)
{ {
$var = $1; $var = $1;
$type = "dump_varargs_$2( \"%s\", min(cur_size,$3) )"; $type = "dump_varargs_$2( \"%s\", min( cur_size, req->" . $3 . " ))";
s!(VARARG\(.*\)\s*;)!/* $1 */!; $dump_funcs{"varargs_$2"} = $2;
}
elsif (/^\s*VARARG\((\w+),(\w+),(\w+)\)/)
{
$var = $1;
$type = "dump_varargs_" . $2 . "( \"%s\", min(cur_size,req->" . $3 . ") )";
s!(VARARG\(.*\)\s*;)!/* $1 */!; s!(VARARG\(.*\)\s*;)!/* $1 */!;
} }
elsif (/^\s*VARARG\((\w+),(\w+)\)/) elsif (/^\s*VARARG\((\w+),(\w+)\)/)
{ {
$var = $1; $var = $1;
$type = "dump_varargs_" . $2 . "( \"%s\", cur_size )"; $type = "dump_varargs_$2( \"%s\", cur_size )";
$dump_funcs{"varargs_$2"} = $2;
s!(VARARG\(.*\)\s*;)!/* $1 */!; s!(VARARG\(.*\)\s*;)!/* $1 */!;
} }
elsif (/^\s*(\w+\**(\s+\w+\**)*)\s+(\w+);/) elsif (/^\s*(\w+\**(\s+\w+\**)*)\s+(\w+);/)
@ -266,16 +276,16 @@ sub PARSE_REQUESTS()
{ {
my $count = $fmt[1] - ($offset & ($fmt[1] - 1)); my $count = $fmt[1] - ($offset & ($fmt[1] - 1));
print "protocol.def:$.: warning: $name $offset $type $var needs padding\n" if $warnings; print "protocol.def:$.: warning: $name $offset $type $var needs padding\n" if $warnings;
print SERVER_PROT " char __pad_$offset\[$count\];\n"; push @protocol_lines, " char __pad_$offset\[$count\];\n";
$offset += $count; $offset += $count;
} }
if ($state == 2) if ($state == 2)
{ {
push @asserts, "C_ASSERT( FIELD_OFFSET(struct ${name}_request, $var) == $offset );\n"; push @asserts, "C_ASSERT( offsetof(struct ${name}_request, $var) == $offset );\n";
} }
else else
{ {
push @asserts, "C_ASSERT( FIELD_OFFSET(struct ${name}_reply, $var) == $offset );\n"; push @asserts, "C_ASSERT( offsetof(struct ${name}_reply, $var) == $offset );\n";
} }
$offset += $fmt[0]; $offset += $fmt[0];
} }
@ -286,9 +296,18 @@ sub PARSE_REQUESTS()
if ($state == 2) { push @in_struct, $type, $var; } if ($state == 2) { push @in_struct, $type, $var; }
if ($state == 3) { push @out_struct, $type, $var; } if ($state == 3) { push @out_struct, $type, $var; }
} }
elsif (/^typedef\s+(.*)\s+(\w+_t);$/)
{
if (defined $formats{$1} && !defined $formats{$2})
{
@{$formats{$2}} = @{$formats{$1}};
$formats{$2}->[2] = $1;
}
}
# Pass it through into the output file # Pass it through into the output file
print SERVER_PROT $_ . "\n"; push @protocol_lines, $_ . "\n";
} }
close PROTOCOL; close PROTOCOL;
} }
@ -337,9 +356,15 @@ sub GET_ERROR_NAMES()
} }
# update a file if changed # update a file if changed
sub update_file($) sub update_file($@)
{ {
my $file = shift; my ($file, @lines) = @_;
open OUTPUT, ">$file.new" or die "Cannot create $file.new";
print OUTPUT $file_header;
print OUTPUT @lines;
close OUTPUT;
my $ret = !(-f $file) || system "cmp $file $file.new >/dev/null"; my $ret = !(-f $file) || system "cmp $file $file.new >/dev/null";
if (!$ret) if (!$ret)
{ {
@ -353,42 +378,6 @@ sub update_file($)
return $ret; return $ret;
} }
# replace some lines in a file between two markers
sub replace_in_file($$$@)
{
my $file = shift;
my $start = shift;
my $end = shift;
open NEW_FILE, ">$file.new" or die "cannot create $file.new";
if (defined($start))
{
open OLD_FILE, "$file" or die "cannot open $file";
while (<OLD_FILE>)
{
print NEW_FILE $_;
last if /$start/;
}
}
print NEW_FILE "\n", @_, "\n";
if (defined($end))
{
my $skip=1;
while (<OLD_FILE>)
{
$skip = 0 if /$end/;
print NEW_FILE $_ unless $skip;
}
}
close OLD_FILE if defined($start);
close NEW_FILE;
return update_file($file);
}
### Main ### Main
# Get the server protocol version # Get the server protocol version
@ -398,13 +387,8 @@ my %errors = GET_ERROR_NAMES();
### Create server_protocol.h and print header ### Create server_protocol.h and print header
open SERVER_PROT, ">include/wine/server_protocol.h.new" or die "Cannot create include/wine/server_protocol.h.new"; push @protocol_lines, "#ifndef __WINE_WINE_SERVER_PROTOCOL_H\n";
print SERVER_PROT "/*\n * Wine server protocol definitions\n *\n"; push @protocol_lines, "#define __WINE_WINE_SERVER_PROTOCOL_H\n";
print SERVER_PROT " * This file is automatically generated; DO NO EDIT!\n";
print SERVER_PROT " * Edit server/protocol.def instead and re-run tools/make_requests\n";
print SERVER_PROT " */\n\n";
print SERVER_PROT "#ifndef __WINE_WINE_SERVER_PROTOCOL_H\n";
print SERVER_PROT "#define __WINE_WINE_SERVER_PROTOCOL_H\n";
### Parse requests to find request/reply structure definitions ### Parse requests to find request/reply structure definitions
@ -412,57 +396,53 @@ PARSE_REQUESTS();
### Build the request list and structures ### Build the request list and structures
print SERVER_PROT "\n\nenum request\n{\n"; push @protocol_lines, "\n\nenum request\n{\n";
foreach my $req (@requests) { print SERVER_PROT " REQ_$req,\n"; } foreach my $req (@requests) { push @protocol_lines, " REQ_$req,\n"; }
print SERVER_PROT " REQ_NB_REQUESTS\n};\n\n"; push @protocol_lines, " REQ_NB_REQUESTS\n};\n\n";
print SERVER_PROT "union generic_request\n{\n"; push @protocol_lines, "union generic_request\n{\n";
print SERVER_PROT " struct request_max_size max_size;\n"; push @protocol_lines, " struct request_max_size max_size;\n";
print SERVER_PROT " struct request_header request_header;\n"; push @protocol_lines, " struct request_header request_header;\n";
foreach my $req (@requests) { print SERVER_PROT " struct ${req}_request ${req}_request;\n"; } foreach my $req (@requests) { push @protocol_lines, " struct ${req}_request ${req}_request;\n"; }
print SERVER_PROT "};\n"; push @protocol_lines, "};\n";
print SERVER_PROT "union generic_reply\n{\n"; push @protocol_lines, "union generic_reply\n{\n";
print SERVER_PROT " struct request_max_size max_size;\n"; push @protocol_lines, " struct request_max_size max_size;\n";
print SERVER_PROT " struct reply_header reply_header;\n"; push @protocol_lines, " struct reply_header reply_header;\n";
foreach my $req (@requests) { print SERVER_PROT " struct ${req}_reply ${req}_reply;\n"; } foreach my $req (@requests) { push @protocol_lines, " struct ${req}_reply ${req}_reply;\n"; }
print SERVER_PROT "};\n\n"; push @protocol_lines, "};\n\n";
print SERVER_PROT "/* ### protocol_version begin ### */\n\n"; push @protocol_lines, sprintf "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol;
printf SERVER_PROT "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol; push @protocol_lines, "#endif /* __WINE_WINE_SERVER_PROTOCOL_H */\n";
print SERVER_PROT "/* ### protocol_version end ### */\n\n";
print SERVER_PROT "#endif /* __WINE_WINE_SERVER_PROTOCOL_H */\n"; open SERVER_PROT, ">include/wine/server_protocol.h.new" or die "Cannot create include/wine/server_protocol.h.new";
print SERVER_PROT @protocol_lines;
close SERVER_PROT; close SERVER_PROT;
if (update_file( "include/wine/server_protocol.h" )) if (update_file( "include/wine/server_protocol.h", @protocol_lines ))
{ {
my @version_lines = (); $protocol_lines[$#protocol_lines - 1] = sprintf "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol + 1;
update_file( "include/wine/server_protocol.h", @protocol_lines );
push @version_lines, sprintf( "#define SERVER_PROTOCOL_VERSION %d\n", $protocol + 1 );
replace_in_file( "include/wine/server_protocol.h",
"### protocol_version begin ###",
"### protocol_version end ###",
@version_lines );
} }
### Output the dumping function tables ### Output the dumping function tables
push @trace_lines, "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n"; push @trace_lines, "typedef void (*dump_func)( const void *req );\n\n";
push @trace_lines, "static const dump_func req_dumpers[REQ_NB_REQUESTS] =\n{\n";
foreach my $req (@requests) foreach my $req (@requests)
{ {
push @trace_lines, " (dump_func)dump_${req}_request,\n"; push @trace_lines, " (dump_func)dump_${req}_request,\n";
} }
push @trace_lines, "};\n\n"; push @trace_lines, "};\n\n";
push @trace_lines, "static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {\n"; push @trace_lines, "static const dump_func reply_dumpers[REQ_NB_REQUESTS] =\n{\n";
foreach my $req (@requests) foreach my $req (@requests)
{ {
push @trace_lines, " ", $replies{$req} ? "(dump_func)dump_${req}_reply,\n" : "NULL,\n"; push @trace_lines, " ", $replies{$req} ? "(dump_func)dump_${req}_reply,\n" : "NULL,\n";
} }
push @trace_lines, "};\n\n"; push @trace_lines, "};\n\n";
push @trace_lines, "static const char * const req_names[REQ_NB_REQUESTS] = {\n"; push @trace_lines, "static const char * const req_names[REQ_NB_REQUESTS] =\n{\n";
foreach my $req (@requests) foreach my $req (@requests)
{ {
push @trace_lines, " \"$req\",\n"; push @trace_lines, " \"$req\",\n";
@ -481,18 +461,32 @@ foreach my $err (sort keys %errors)
push @trace_lines, " { NULL, 0 }\n"; push @trace_lines, " { NULL, 0 }\n";
push @trace_lines, "};\n"; push @trace_lines, "};\n";
replace_in_file( "server/trace.c",
"### make_requests begin ###", my @trace_header = ();
"### make_requests end ###",
@trace_lines ); foreach my $func (sort keys %dump_funcs)
{
if ($func =~ /^varargs_/)
{
push @trace_header, "static void dump_$func( const char *prefix, data_size_t size );\n";
}
else
{
push @trace_header, "static void dump_$func( const char *prefix, const $dump_funcs{$func} *val );\n";
}
}
push @trace_header, "\nstatic const void *cur_data;\n";
push @trace_header, "static data_size_t cur_size;\n\n";
update_file( "server/request_trace.h", @trace_header, @trace_lines);
### Output the request handlers list ### Output the request handlers list
my @request_lines = (); my @request_lines = ( "#include \"request.h\"\n\n" );
foreach my $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; } foreach my $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; }
push @request_lines, "\n#ifdef WANT_REQUEST_HANDLERS\n\n"; push @request_lines, "\ntypedef void (*req_handler)( const void *req, void *reply );\n";
push @request_lines, "typedef void (*req_handler)( const void *req, void *reply );\n";
push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n"; push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n";
foreach my $req (@requests) foreach my $req (@requests)
{ {
@ -506,10 +500,5 @@ foreach my $type (sort keys %formats)
die "$type: invalid size $size for alignment $align" if $size % $align; die "$type: invalid size $size for alignment $align" if $size % $align;
push @request_lines, "C_ASSERT( sizeof($type) == $size );\n"; push @request_lines, "C_ASSERT( sizeof($type) == $size );\n";
} }
push @request_lines, @asserts;
push @request_lines, "\n#endif /* WANT_REQUEST_HANDLERS */\n";
replace_in_file( "server/request.h", update_file( "server/request_handlers.h", @request_lines, @asserts );
"### make_requests begin ###",
"### make_requests end ###",
@request_lines );