Compare commits

...

57 commits

Author SHA1 Message Date
Rémi Bernon
d615f2aba8 Merge branch 'mr/winex11-config-race' into 'master'
winex11: Refactor window state/config tracker to fix race conditions.

See merge request wine/wine!6569
2024-11-18 22:18:42 +00: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
d7a9e3654b winex11: Request window state updates asynchronously. 2024-11-18 10:30:04 +01:00
Rémi Bernon
c7b391a22c winex11: Update the window client config on window state changes. 2024-11-18 10:30:04 +01:00
Rémi Bernon
071af3e414 winex11: Wait for pending ConfigureNotify before updating the client state. 2024-11-18 10:30:04 +01:00
Rémi Bernon
9633abece0 winex11: Wait for pending _NET_WM_STATE before updating the client state. 2024-11-18 10:30:04 +01:00
Rémi Bernon
ee484eac4c winex11: Don't expect WM_STATE events on override-redirect windows. 2024-11-18 10:30:04 +01:00
Rémi Bernon
eaedc24018 winex11: Listen to PropertyNotify events on the virtual desktop window.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57423
2024-11-18 10:30:04 +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
65 changed files with 8594 additions and 7667 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

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 */
if (LISTVIEW_IsHotTracking(infoPtr)) {
TRACKMOUSEEVENT trackinfo;
NMLISTVIEW nmlv = { 0 };
DWORD flags;
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 */
_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;
@ -9585,6 +9595,7 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, const CREATESTRUCTW *
infoPtr->iVersion = COMCTL32_VERSION;
infoPtr->colRectsDirty = FALSE;
infoPtr->selected_column = -1;
infoPtr->hHotCursor = LoadCursorW(NULL, (LPWSTR)IDC_HAND);
/* get default font (icon title) */
SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);

View file

@ -7255,6 +7255,19 @@ static void test_LVM_GETNEXTITEM(void)
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)
{
ULONG_PTR ctx_cookie;
@ -7322,6 +7335,7 @@ START_TEST(listview)
test_LVM_SETBKIMAGE(FALSE);
test_custom_sort();
test_LVM_GETNEXTITEM();
test_LVM_GETHOTCURSOR();
if (!load_v6_module(&ctx_cookie, &hCtx))
{
@ -7372,6 +7386,7 @@ START_TEST(listview)
test_LVM_GETNEXTITEMINDEX();
test_LVM_GETNEXTITEM();
test_LVM_SETBKIMAGE(TRUE);
test_LVM_GETHOTCURSOR();
unload_v6_module(ctx_cookie, hCtx);

View file

@ -300,20 +300,6 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
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)
{
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);
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);
pcs->loader = &empty_loader_ops;
}
return TRUE;
}
@ -510,8 +499,9 @@ BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeP
if (check_live_target(pcs, wow64, child_wow64))
{
if (fInvadeProcess)
EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
if (pcs->loader) pcs->loader->synchronize_module_list(pcs);
module_refresh_list(pcs);
else
pcs->loader->synchronize_module_list(pcs);
}
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 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_refresh_list(struct process *pcs);
/* msc.c */
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");
module_remove(pcs, elf_info.module);
pcs->loader = &empty_loader_ops;
return FALSE;
}
TRACE("Found ELF debug header %#I64x\n", elf_info.dbg_hdr_addr);

View file

@ -24,6 +24,8 @@
#include <string.h>
#include <assert.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h"
#include "image_private.h"
#include "psapi.h"
@ -1317,7 +1319,11 @@ BOOL WINAPI EnumerateLoadedModulesW64(HANDLE process,
size_t sysdir_len = 0, wowdir_len = 0;
/* 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) &&
pcs_machine != IMAGE_FILE_MACHINE_UNKNOWN &&
(dbghelp_options & SYMOPT_INCLUDE_32BIT_MODULES);
@ -1600,18 +1606,41 @@ void module_reset_debug_info(struct module* module)
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.@)
*/
BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
{
struct process* pcs;
struct process *pcs;
TRACE("(%p)\n", hProcess);
if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
return pcs->loader->synchronize_module_list(pcs);
return module_refresh_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",
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);
else
ret = TRUE;
break;
}
default:
@ -4487,7 +4493,7 @@ typedef struct _FPO_DATA
__ENDTRY
/* 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)};
char buffer[MAX_PATH];
@ -4549,38 +4555,35 @@ DWORD msc_get_file_indexinfo(void* image, const IMAGE_DEBUG_DIRECTORY* debug_dir
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)
{
const IMAGE_SEPARATE_DEBUG_HEADER *header;
IMAGE_DEBUG_DIRECTORY *dbg;
DWORD num_directories;
if (size < sizeof(*header)) return ERROR_BAD_EXE_FORMAT;
if (size < sizeof(*header)) return ERROR_BAD_FORMAT;
header = image;
if (header->Signature != 0x4944 /* DI */ ||
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->NumberOfSections of IMAGE_SECTION_HEADER
* - header->ExportedNameSize
* - 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);
if (!num_directories) return ERROR_BAD_EXE_FORMAT;
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;
return msc_get_file_indexinfo(image, dbg, num_directories, info);
}

View file

@ -832,7 +832,7 @@ BOOL WINAPI SymSrvGetFileIndexInfoW(const WCHAR *file, SYMSRV_INDEX_INFOW* info,
if (hMap) CloseHandle(hMap);
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);
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 ||
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));
}
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;
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 */
info->timestamp = nthdr->FileHeader.TimeDateStamp;

View file

@ -372,6 +372,29 @@ static unsigned get_native_module_count(HANDLE proc)
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
{
HANDLE proc;
@ -424,6 +447,28 @@ static BOOL wrapper_EnumerateLoadedModulesW64(HANDLE proc, PENUMLOADED_MODULES_C
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)
{
BOOL ret;
@ -492,6 +537,7 @@ static BOOL test_modules(void)
ret = SymRefreshModuleList(dummy);
ok(!ret, "SymRefreshModuleList should have failed\n");
ok(GetLastError() == STATUS_INVALID_CID, "Unexpected last error %lx\n", GetLastError());
count = get_module_count(dummy);
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());
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 */
ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
ok(ret, "CreateProcess failed: %lu\n", GetLastError());
@ -885,9 +936,10 @@ static void test_loaded_modules(void)
pcskind = get_process_kind(pi.hProcess);
ret = SymRefreshModuleList(pi.hProcess);
todo_wine_if(pcskind == PCSKIND_WOW64)
ok(ret || broken(GetLastError() == STATUS_PARTIAL_COPY /* Win11 in some cases */), "SymRefreshModuleList failed: %lu\n", GetLastError());
ret = wrapper_SymRefreshModuleList(pi.hProcess);
ok(ret || broken(GetLastError() == STATUS_PARTIAL_COPY /* Win11 in some cases */ ||
GetLastError() == STATUS_INFO_LENGTH_MISMATCH /* Win11 in some cases */),
"SymRefreshModuleList failed: %lx\n", GetLastError());
if (!strcmp(winetest_platform, "wine"))
{
@ -945,8 +997,8 @@ static void test_loaded_modules(void)
"Wrong directory aggregation count %u %u\n",
aggregation.count_systemdir, aggregation.count_wowdir);
}
ret = SymRefreshModuleList(pi.hProcess);
ok(ret, "SymRefreshModuleList failed: %lu\n", GetLastError());
ret = wrapper_SymRefreshModuleList(pi.hProcess);
ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
if (!strcmp(winetest_platform, "wine"))
{
@ -1007,8 +1059,8 @@ static void test_loaded_modules(void)
break;
}
ret = SymRefreshModuleList(pi.hProcess);
ok(ret, "SymRefreshModuleList failed: %lu\n", GetLastError());
ret = wrapper_SymRefreshModuleList(pi.hProcess);
ok(ret, "SymRefreshModuleList failed: %lx\n", GetLastError());
if (!strcmp(winetest_platform, "wine"))
{
@ -1529,6 +1581,75 @@ static void test_function_tables(void)
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)
{
BOOL ret;
@ -1559,6 +1680,7 @@ START_TEST(dbghelp)
test_modules_overlap();
test_loaded_modules();
test_live_modules();
test_refresh_modules();
}
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;
}
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;
/* minimalistic .dbg made of a header and a DEBUG_DIRECTORY without any data */
const IMAGE_SEPARATE_DEBUG_HEADER header = {.Signature = 0x4944 /* DI */,
.Flags = 0, .Machine = machine, .Characteristics = 0x010E, .TimeDateStamp = timestamp,
IMAGE_SEPARATE_DEBUG_HEADER header =
{
.Signature = 0x4944 /* DI */,
.Flags = 0, .Machine = machine, .Characteristics = charac, .TimeDateStamp = timestamp,
.CheckSum = 0, .ImageBase = 0x00040000, .SizeOfImage = size, .NumberOfSections = 0,
.ExportedNamesSize = 0, .DebugDirectorySize = sizeof(IMAGE_DEBUG_DIRECTORY)};
const IMAGE_DEBUG_DIRECTORY debug_dir = {.Characteristics = 0, .TimeDateStamp = timestamp + 1,
.MajorVersion = 0, .MinorVersion = 0, .Type = IMAGE_DEBUG_TYPE_CODEVIEW,
.SizeOfData = 0, .AddressOfRawData = 0,
.PointerToRawData = sizeof(header) + header.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
header.DebugDirectorySize};
.ExportedNamesSize = 0, .DebugDirectorySize = 0
};
DWORD where, expected_size;
if (blob)
header.DebugDirectorySize = sizeof(IMAGE_DEBUG_DIRECTORY);
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());
@ -692,8 +694,18 @@ static BOOL create_test_dbg(const WCHAR* dbg_name, WORD machine, DWORD timestamp
check_write_file(hfile, &header, sizeof(header));
/* FIXME: 0 sections... as header.NumberOfSections */
check_write_file(hfile, &debug_dir, sizeof(debug_dir));
ok(SetFilePointer(hfile, 0, NULL, FILE_CURRENT) == debug_dir.PointerToRawData, "mismatch\n");
if (blob)
{
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);
return TRUE;
@ -725,16 +737,16 @@ static void test_srvgetindexes_pe(void)
DWORD sig;
WCHAR pdb_name[16];
WCHAR dbg_name[16];
BOOL in_error;
DWORD last_error;
}
indexes[] =
{
/* error cases */
/* 0 */{0, {-1, -1, -1}, .in_error = TRUE},
{IMAGE_FILE_DEBUG_STRIPPED, { 0, -1, -1}, .in_error = TRUE},
{IMAGE_FILE_DEBUG_STRIPPED, { 1, -1, -1}, .in_error = TRUE},
{IMAGE_FILE_DEBUG_STRIPPED, { 2, -1, -1}, .in_error = TRUE},
{IMAGE_FILE_DEBUG_STRIPPED, {-1, -1, -1}, .in_error = TRUE}, /* not 100% logical ! */
/* 0 */{0, {-1, -1, -1}, 0, &null_guid, 0, .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_DEBUG_STRIPPED, { 0, -1, -1}, 0, &null_guid, 0, .last_error = ERROR_BAD_EXE_FORMAT},
{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}, 124, &guid1, 0, .pdb_name = L"pdbds.pdb", .last_error = ERROR_BAD_EXE_FORMAT},
{IMAGE_FILE_DEBUG_STRIPPED, {-1, -1, -1}, 0, &null_guid, 0, .last_error = ERROR_BAD_EXE_FORMAT}, /* not 100% logical ! */
/* success */
/* 5 */{0, { 0, -1, -1}, 0, &null_guid, 0 },
{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));
ssii.sizeofstruct = sizeof(ssii);
ret = SymSrvGetFileIndexInfoW(filename, &ssii, 0);
if (indexes[i].in_error)
if (indexes[i].last_error)
{
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
{
ok(ret, "SymSrvGetFileIndexInfo failed: %lu\n", GetLastError());
ok(ssii.age == indexes[i].age, "Mismatch in age: %lx\n", ssii.age);
if (ret || indexes[i].last_error == ERROR_BAD_EXE_FORMAT)
{
ok(ssii.age == indexes[i].age, "Mismatch in age: %lu\n", ssii.age);
ok(IsEqualGUID(&ssii.guid, indexes[i].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];
SYMSRV_INDEX_INFOW ssii;
BOOL ret;
struct debug_directory_blob *blob_refs[1];
static struct
{
/* input parameters */
WORD machine;
DWORD characteristics;
DWORD timestamp;
DWORD imagesize;
int blob;
/* output parameters */
DWORD age;
const GUID *guid;
WCHAR pdbname[16];
WCHAR dbgname[16];
DWORD last_error;
}
indexes[] =
{
{IMAGE_FILE_MACHINE_I386, 0x1234, 0x00560000},
{IMAGE_FILE_MACHINE_AMD64, 0x1235, 0x00570000},
{IMAGE_FILE_MACHINE_I386, 0, 0x1234, 0x00560000, -1, 0, &null_guid, .last_error = ERROR_BAD_EXE_FORMAT},
{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++)
{
winetest_push_context("dbg#%02u", i);
/* create dll */
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);
memset(&ssii, 0x45, sizeof(ssii));
ssii.sizeofstruct = sizeof(ssii);
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(ssii.age == 0, "Mismatch in age: %lx\n", ssii.age);
ok(!memcmp(&ssii.guid, &null_guid, sizeof(GUID)),
ok(ssii.age == indexes[i].age, "Mismatch in age: %lx\n", ssii.age);
ok(IsEqualGUID(&ssii.guid, indexes[i].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.size == indexes[i].imagesize, "Mismatch in size: %lx\n", ssii.size);
ok(!ssii.stripped, "Mismatch in stripped: %x\n", ssii.stripped);
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(!ssii.pdbfile[0], "Mismatch in pdbfile: %ls\n", ssii.pdbfile);
ok(!ssii.dbgfile[0], "Mismatch in dbgfile: %ls\n", ssii.dbgfile);
ok(!wcscmp(ssii.pdbfile, indexes[i].pdbname), "Mismatch in pdbfile: %ls\n", ssii.pdbfile);
ok(!wcscmp(ssii.dbgfile, indexes[i].dbgname), "Mismatch in dbgfile: %ls\n", ssii.dbgfile);
DeleteFileW(filename);
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)
@ -1533,7 +1566,8 @@ static void test_load_modules_path(void)
if (test_files[val].guid)
create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp);
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);
}
@ -1754,7 +1788,7 @@ static void test_load_modules_details(void)
if (test_files[val].guid)
create_test_pdb_ds(filename, test_files[val].guid, test_files[val].age_or_timestamp);
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);
}

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)))
{
RECT rect, new_rect;
POINT mapped_center;
RECT rect;
impl->last_warped = now;
impl->need_warp = FALSE;
if (!GetClientRect( impl->base.win, &rect )) return;
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)
{
/* 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.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 );
TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect ));
ClipCursor( &rect );
impl->clipped = GetClipCursor( &new_rect ) && EqualRect( &rect, &new_rect );
impl->clipped = ClipCursor( &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;
}
static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
DWORD dwFlags, DPID idParent, 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 )
{
struct GroupList *groupList = NULL;
struct GroupData *parent = NULL;
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 */
lpGData = calloc( 1, sizeof( *lpGData ) );
if( lpGData == NULL )
{
return NULL;
return DPERR_OUTOFMEMORY;
}
DPQ_INIT(lpGData->groups);
@ -1304,7 +1315,7 @@ static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, cons
if ( !lpGData->name )
{
free( lpGData );
return NULL;
return DPERR_OUTOFMEMORY;
}
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 );
return NULL;
return DPERR_OUTOFMEMORY;
}
/* FIXME: Should we check that the parent exists? */
lpGData->parent = idParent;
/* 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->name );
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 );
return lpGData;
return DP_OK;
}
/* 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,
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",
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 );
if( lpGData == NULL )
if( FAILED( hr ) )
{
return DPERR_CANTADDPLAYER; /* yes player not group */
}
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 );
return hr;
}
/* 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,
BOOL bAnsi )
{
lpGroupData lpGParentData;
lpGroupList lpGList;
lpGroupData lpGData;
HRESULT hr;
TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
This, idParentGroup, lpidGroup, lpGroupName, lpData,
@ -4471,48 +4501,12 @@ static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr,
return DPERR_UNINITIALIZED;
}
/* Verify that the specified parent is valid */
if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL )
return DPERR_INVALIDGROUP;
hr = DP_CreateGroup(This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
idParentGroup, bAnsi );
lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi );
if( lpGData == NULL )
if( FAILED( hr ) )
{
return DPERR_CANTADDPLAYER; /* yes player not group */
}
/* 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 );
return hr;
}
/* 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,
void *data, DWORD dataSize, void *spData, DWORD spDataSize, DWORD dwFlags,
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 */
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;
}
}
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 )
{

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,
const WCHAR *expectedPassword, DWORD expectedFlags )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
EnumSessionsRequest request;
WCHAR password[ 256 ];
} request;
#include "poppack.h"
DWORD expectedPasswordSize;
unsigned short port;
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 )
static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port, const DPSESSIONDESC2 *dpsd )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -1295,6 +1298,7 @@ static void sendEnumSessionsReply_( int line, SOCKET sock, unsigned short port,
.nameOffset = sizeof( reply.reply ),
},
};
#include "poppack.h"
DWORD passwordSize;
int wsResult;
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 )
static unsigned short receiveRequestPlayerId_( int line, SOCKET sock, DWORD expectedFlags )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
RequestPlayerId request;
} request;
#include "poppack.h"
unsigned short port;
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 )
static void sendRequestPlayerReply_( int line, SOCKET sock, unsigned short port, DPID id, HRESULT result )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -1362,6 +1369,7 @@ static void sendRequestPlayerReply_( int line, SOCKET sock, unsigned short port,
.result = result,
},
};
#include "poppack.h"
int wsResult;
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,
unsigned short *udpPort )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
AddForwardRequest request;
} request;
#include "poppack.h"
DWORD expectedPasswordSize;
WCHAR password[ 256 ];
unsigned short port;
@ -1427,25 +1437,53 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
{
#define SHORT_NAME L"short name"
#define LONG_NAME L"long name"
#include "pshpack1.h"
struct
{
SpHeader spHeader;
SuperEnumPlayersReply reply;
DPSESSIONDESC2 dpsd;
WCHAR sessionName[ 256 ];
SuperPackedPlayer superPackedPlayer0;
BYTE spDataLength0;
SpData spData0;
SuperPackedPlayer superPackedPlayer1;
BYTE spDataLength1;
SpData spData1;
SuperPackedPlayer superPackedPlayer2;
struct
{
SuperPackedPlayer superPackedPlayer;
BYTE spDataLength;
SpData spData;
} player0;
struct
{
SuperPackedPlayer superPackedPlayer;
BYTE spDataLength;
SpData spData;
} player1;
struct
{
SuperPackedPlayer superPackedPlayer;
WCHAR shortName[ ARRAYSIZE( SHORT_NAME ) ];
WCHAR longName[ ARRAYSIZE( LONG_NAME ) ];
BYTE playerDataLength2;
BYTE playerDataLength;
BYTE playerData[ 4 ];
BYTE spDataLength2;
SpData spData2;
BYTE spDataLength;
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 =
{
.spHeader =
@ -1465,8 +1503,8 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.command = 41,
.version = 14,
},
.playerCount = 3,
.groupCount = 0,
.playerCount = 4,
.groupCount = 1,
.packedOffset = sizeof( reply.reply ) + sizeof( reply.dpsd ) + sizeof( reply.sessionName ),
.shortcutCount = 0,
.descriptionOffset = sizeof( reply.reply ),
@ -1474,7 +1512,9 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.passwordOffset = 0,
},
.dpsd = *dpsd,
.superPackedPlayer0 =
.player0 =
{
.superPackedPlayer =
{
.size = 16,
.flags = 0x5,
@ -1482,8 +1522,8 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.infoMask = 0x4,
.versionOrSystemPlayerId = 14,
},
.spDataLength0 = sizeof( SpData ),
.spData0 =
.spDataLength = sizeof( SpData ),
.spData =
{
.tcpAddr =
{
@ -1496,7 +1536,10 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.sin_port = htons( udpPort ),
},
},
.superPackedPlayer1 =
},
.player1 =
{
.superPackedPlayer =
{
.size = 16,
.flags = 0xf,
@ -1504,8 +1547,8 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.infoMask = 0x4,
.versionOrSystemPlayerId = 14,
},
.spDataLength1 = sizeof( SpData ),
.spData1 =
.spDataLength = sizeof( SpData ),
.spData =
{
.tcpAddr =
{
@ -1518,7 +1561,10 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.sin_port = htons( udpPort ),
},
},
.superPackedPlayer2 =
},
.player2 =
{
.superPackedPlayer =
{
.size = 16,
.flags = 0x8,
@ -1528,10 +1574,10 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
},
.shortName = SHORT_NAME,
.longName = LONG_NAME,
.playerDataLength2 = 4,
.playerDataLength = 4,
.playerData = { 1, 2, 3, 4, },
.spDataLength2 = sizeof( SpData ),
.spData2 =
.spDataLength = sizeof( SpData ),
.spData =
{
.tcpAddr =
{
@ -1544,7 +1590,65 @@ static void sendSuperEnumPlayersReply_( int line, SOCKET sock, unsigned short tc
.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 SHORT_NAME
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 )
static void sendAddForwardReply_( int line, SOCKET sock, unsigned short port, HRESULT result )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -1587,6 +1692,7 @@ static void sendAddForwardReply_( int line, SOCKET sock, unsigned short port, HR
.result = result,
},
};
#include "poppack.h"
int wsResult;
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 )
static void sendAddForward_( int line, SOCKET sock, unsigned short port, unsigned short tcpPort, unsigned short udpPort )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -1653,6 +1760,7 @@ static void sendAddForward_( int line, SOCKET sock, unsigned short port, unsigne
},
},
};
#include "poppack.h"
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 )
static unsigned short receiveAddForwardAck_( int line, SOCKET sock, DPID expectedPlayerId )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
AddForwardAck request;
} request;
#include "poppack.h"
unsigned short port;
int wsResult;
@ -1688,11 +1798,13 @@ static unsigned short receiveCreatePlayer_( int line, SOCKET sock, DPID expected
const WCHAR *expectedShortName, const WCHAR *expectedLongName,
void *expectedPlayerData, DWORD expectedPlayerDataSize )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
CreatePlayer request;
} request;
#include "poppack.h"
DWORD expectedShortNameSize;
DWORD expectedLongNameSize;
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,
const WCHAR *shortName, const WCHAR *longName, void *playerData, DWORD playerDataSize )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -1820,6 +1933,7 @@ static void sendCreatePlayer_( int line, SOCKET sock, unsigned short tcpPort, un
},
},
};
#include "poppack.h"
SpData spData = {
.tcpAddr.sin_family = AF_INET,
.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,
void *expectedData, DWORD expectedDataSize )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
GameMessage request;
BYTE data[ 256 ];
} request;
#include "poppack.h"
unsigned short port;
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,
DWORD expectedDataSize )
{
#include "pshpack1.h"
struct
{
GameMessage request;
BYTE data[ 256 ];
} request;
#include "poppack.h"
int wsResult;
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,
DWORD dataSize )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -1945,6 +2064,7 @@ static void sendGuaranteedGameMessage_( int line, SOCKET sock, unsigned short po
.toId = toId,
}
};
#include "poppack.h"
int wsResult;
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 )
static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, void *data, DWORD dataSize )
{
#include "pshpack1.h"
struct
{
GameMessage request;
@ -1970,6 +2091,7 @@ static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, voi
.toId = toId,
}
};
#include "poppack.h"
int wsResult;
DWORD size;
@ -1985,6 +2107,7 @@ static void sendGameMessage_( int line, SOCKET sock, DPID fromId, DPID toId, voi
sendPing_( __LINE__, sock, port, fromId, tickCount )
static void sendPing_( int line, SOCKET sock, unsigned short port, DPID fromId, DWORD tickCount )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
@ -2012,6 +2135,7 @@ static void sendPing_( int line, SOCKET sock, unsigned short port, DPID fromId,
.tickCount = tickCount,
}
};
#include "poppack.h"
int wsResult;
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 )
static unsigned short receivePingReply_( int line, SOCKET sock, DPID expectedFromId, DWORD expectedTickCount )
{
#include "pshpack1.h"
struct
{
SpHeader spHeader;
Ping request;
} request;
#include "poppack.h"
unsigned short port;
int wsResult;
@ -2704,7 +2830,7 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const
HRESULT hr;
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",
playerType );
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",
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 );
memset( &playerData, 0xcc, sizeof( playerData ) );
playerDataSize = sizeof( playerData );
if ( playerType == DPPLAYERTYPE_PLAYER )
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 );
todo_wine_if( playerType == DPPLAYERTYPE_GROUP )
ok_( __FILE__, data->line )( playerDataSize == player->expectedPlayerDataSize,
"got player data size %lu.\n", playerDataSize );
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 ) );
nameDataSize = sizeof( nameData );
if ( playerType == DPPLAYERTYPE_PLAYER )
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 )( ((DPNAME *) nameData)->dwSize == sizeof( DPNAME ),
"got name size %lu.\n", ((DPNAME *) nameData)->dwSize );
@ -2796,7 +2930,8 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const
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 )
{
CheckPlayerListCallbackData data = {
@ -2817,6 +2952,51 @@ static void checkPlayerList_( int line, IDirectPlay4 *dp, ExpectedPlayer *expect
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, \
expectedPlayerData, expectedPlayerDataSize ) \
checkPlayerExists_( __LINE__, dp, expectedDpid, expectedPlayerType, expectedShortName, expectedLongName, \
@ -2918,9 +3098,36 @@ static void check_Open_( int line, IDirectPlay4A *dp, DPSESSIONDESC2 *dpsd, cons
.expectedPlayerData = 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 ) );
checkGroupList_( line, dp, expectedGroups, ARRAYSIZE( expectedGroups ) );
checkGroupPlayerList_( line, 0x5e7, dp, expectedGroupPlayers, ARRAYSIZE( expectedGroupPlayers ) );
hr = IDirectPlayX_Close( dp );
checkHR( DP_OK, hr );
@ -4648,20 +4855,20 @@ static void test_CreatePlayer(void)
/* Player name */
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;
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.dwSize = 1;
dpid = 0xdeadbeef;
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;
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 */
dpid = 0xdeadbeef;
@ -4669,11 +4876,11 @@ static void test_CreatePlayer(void)
/* Flags */
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;
check_CreatePlayer( dp, &dpid, NULL, DPPLAYER_SPECTATOR, DP_OK, 7, recvSock, TRUE, 0x208, NULL, NULL, NULL, NULL,
6 );
7 );
closesocket( recvSock );
closesocket( sendSock );
@ -4920,7 +5127,7 @@ static void test_CREATEPLAYER(void)
checkPlayerExists( dp, 0x07734, DPPLAYERTYPE_PLAYER, "new player short name", "new player long name",
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 );
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, 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 ) );
todo_wine ok( hr == DPERR_INVALIDPARAM, "got hr %#lx.\n", hr );
@ -8289,7 +8496,7 @@ static void test_Receive(void)
waitResult = WaitForSingleObject( event0, 2000 );
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, 0x14, data1, sizeof( data1 ) );

View file

@ -354,7 +354,7 @@ static int wait_select_reply( void *cookie )
/***********************************************************************
* 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],
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
*/
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;
void *addr;
@ -687,20 +687,20 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO
/***********************************************************************
* server_select
*/
unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags,
timeout_t abs_timeout, context_t *context, user_apc_t *user_apc )
unsigned int server_select( const union select_op *select_op, data_size_t size, UINT flags,
timeout_t abs_timeout, context_t *context, struct user_apc *user_apc )
{
unsigned int ret;
int cookie;
obj_handle_t apc_handle = 0;
BOOL suspend_context = !!context;
apc_result_t result;
union apc_result result;
sigset_t old_set;
int signaled;
data_size_t reply_size;
struct
{
apc_call_t call;
union apc_call call;
context_t context[2];
} 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 */
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 );
if (signaled) break;
@ -763,12 +763,12 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
/***********************************************************************
* 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 )
{
timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
unsigned int ret;
user_apc_t apc;
struct user_apc apc;
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 )
{
user_apc_t apc;
struct user_apc apc;
NTSTATUS status;
if (alertable)
@ -811,7 +811,7 @@ NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable )
*/
NTSTATUS WINAPI NtTestAlert(void)
{
user_apc_t apc;
struct user_apc apc;
NTSTATUS status;
status = server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, 0, NULL, &apc );
@ -823,7 +823,7 @@ NTSTATUS WINAPI NtTestAlert(void)
/***********************************************************************
* 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 (;;)
{
@ -1759,8 +1759,8 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
if ((options & DUPLICATE_CLOSE_SOURCE) && source_process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
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 */
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;
@ -1098,7 +1098,7 @@ static NTSTATUS get_image_machine( HANDLE handle, USHORT *machine )
NTSTATUS WINAPI NtWaitForDebugEvent( HANDLE handle, BOOLEAN alertable, LARGE_INTEGER *timeout,
DBGUI_WAIT_STATE_CHANGE *state )
{
debug_event_t data;
union debug_event_data data;
unsigned int ret;
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,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
select_op_t select_op;
union select_op select_op;
UINT i, flags = SELECT_INTERRUPTIBLE;
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;
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] );
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,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
select_op_t select_op;
union select_op select_op;
UINT flags = SELECT_INTERRUPTIBLE;
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,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
select_op_t select_op;
union select_op select_op;
UINT flags = SELECT_INTERRUPTIBLE;
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,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
select_op_t select_op;
union select_op select_op;
UINT flags = SELECT_INTERRUPTIBLE;
if (!handle) handle = keyed_event;

View file

@ -1323,8 +1323,8 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -1512,7 +1512,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c
DWORD i;
obj_handle_t handle = 0;
client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
select_op_t select_op;
union select_op select_op;
sigset_t old_set;
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 );
server_contexts[0].flags |= SERVER_CTX_EXEC_SPACE;
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 );
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 )
{
unsigned int ret;
apc_call_t call;
union apc_call call;
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 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 unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags,
timeout_t abs_timeout, context_t *context, user_apc_t *user_apc );
extern unsigned int server_wait( 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, struct user_apc *user_apc );
extern unsigned int server_wait( const union select_op *select_op, data_size_t size, UINT flags,
const LARGE_INTEGER *timeout );
extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call,
apc_result_t *result );
extern unsigned int server_queue_process_apc( HANDLE process, const union apc_call *call,
union apc_result *result );
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 );
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 );
}
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 )
{
async_data_t async;
struct async_data async;
async.handle = wine_server_obj_handle( handle );
async.user = wine_server_client_ptr( user );
async.iosb = iosb;

View file

@ -4671,8 +4671,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
unsigned int status;
memset( &call, 0, sizeof(call) );
@ -4817,8 +4817,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -4864,8 +4864,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -4962,8 +4962,8 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5146,8 +5146,8 @@ static unsigned int get_basic_memory_info( HANDLE process, LPCVOID addr,
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5559,8 +5559,8 @@ NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size,
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5596,8 +5596,8 @@ NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5672,8 +5672,8 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5744,8 +5744,8 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5788,8 +5788,8 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags )
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -5973,8 +5973,8 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
memset( &call, 0, sizeof(call) );
@ -6359,8 +6359,8 @@ NTSTATUS WINAPI NtWow64AllocateVirtualMemory64( HANDLE process, ULONG64 *ret, UL
if (process != NtCurrentProcess())
{
apc_call_t call;
apc_result_t result;
union apc_call call;
union apc_result result;
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
{
irp_params_t params;
union irp_params params;
HANDLE handle;
struct irp_data *irp_data;
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);
if (0) check_wnd_state(hwnd2, hwnd2, hwnd2, 0);
/* FIXME: these tests are failing because of a race condition
* between internal focus state applied immediately and X11 focus
* 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());
ok(GetActiveWindow() == hwnd2, "Expected active window %p, got %p.\n", hwnd2, GetActiveWindow());
ok(GetFocus() == hwnd2, "Expected focus window %p, got %p.\n", hwnd2, GetFocus());
SetForegroundWindow(hwnd);
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;
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;
/* 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 )
{
struct packed_message data;
message_data_t msg_data;
union message_data msg_data;
unsigned int res;
int i;
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},
};
struct iohid_device *impl;
USAGE_AND_PAGE usages;
CFStringRef str;
desc.usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey)));
desc.usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey)));
usages.UsagePage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsagePageKey)));
usages.Usage = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDPrimaryUsageKey)));
desc.vid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDVendorIDKey)));
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) ||
!CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0);
if (desc.usages.UsagePage != HID_USAGE_PAGE_GENERIC ||
!(desc.usages.Usage == HID_USAGE_GENERIC_JOYSTICK || desc.usages.Usage == HID_USAGE_GENERIC_GAMEPAD))
if (usages.UsagePage != HID_USAGE_PAGE_GENERIC ||
!(usages.Usage == HID_USAGE_GENERIC_JOYSTICK || usages.Usage == HID_USAGE_GENERIC_GAMEPAD))
{
/* winebus isn't currently meant to handle anything but these, and
* opening keyboards, mice, or the Touch Bar on older MacBooks triggers

View file

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

View file

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

View file

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

View file

@ -38,7 +38,6 @@ struct device_desc
UINT version;
UINT input;
UINT uid;
USAGE_AND_PAGE usages;
BOOL is_gamepad;
BOOL is_hidraw;
BOOL is_bluetooth;
@ -151,8 +150,8 @@ enum unix_funcs
static inline const char *debugstr_device_desc(struct device_desc *desc)
{
if (!desc) return "(null)";
return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, usage %04x:%04x, is_gamepad %u, is_hidraw %u, is_bluetooth %u}",
desc->vid, desc->pid, desc->version, desc->input, desc->uid, desc->usages.UsagePage, desc->usages.Usage,
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->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 */
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 );
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))
{
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",
hwnd, NtUserIsWindowEnabled(hwnd), NtUserIsWindowVisible(hwnd),
(int)NtUserGetWindowLongW(hwnd, GWL_STYLE),
get_focus(), get_active_window(), NtUserGetForegroundWindow(), last_focus );
if (window_has_pending_wm_state( hwnd, -1 ))
{
WARN( "Ignoring window %p/%lx WM_TAKE_FOCUS serial %lu, event_time %ld, foreground %p during WM_STATE change\n",
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))
{
@ -783,7 +791,7 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
}
else if (hwnd == NtUserGetDesktopWindow())
{
hwnd = NtUserGetForegroundWindow();
hwnd = foreground;
if (!hwnd) hwnd = last_focus;
if (!hwnd) hwnd = NtUserGetDesktopWindow();
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 )
{
HWND foreground = NtUserGetForegroundWindow();
XFocusChangeEvent *event = &xev->xfocus;
BOOL was_grabbed;
if (event->detail == NotifyPointer) 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 */
if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) reapply_cursor_clipping();
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 )
{
HWND foreground = NtUserGetForegroundWindow();
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 (!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 (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 */
keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed;
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;
RECT rect;
POINT pos = {event->x, event->y};
UINT style, flags = 0, config_cmd = 0;
int cx, cy, x, y;
UINT config_cmd, state_cmd;
if (!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 );
window_configure_notify( data, event->serial, &rect );
if (!data->mapped || data->iconic) goto done;
if (!data->whole_window || !data->managed) goto done;
if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
{
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:
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 );
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 );
}
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.
*/
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;
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 (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)
{
case PropertyDelete:
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;
}
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 );
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 );
if (state_cmd)
@ -1304,6 +1221,12 @@ done:
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 );
}
}
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 )
{
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 (event->state == PropertyNewValue) value = get_window_net_wm_state( event->display, event->window );
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 );
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;
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(_NET_WM_STATE)) handle_net_wm_state_notify( hwnd, event );
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.@)
*

View file

@ -46,7 +46,7 @@
#include "winuser.h"
#include "winreg.h"
#include "winnls.h"
#include "ime.h"
#include "kbd.h"
#include "wine/server.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];
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)
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;
data->desired_state.net_wm_state = new_state;
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 (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 );
}
}
XFlush( data->display );
}
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;
XWindowChanges changes;
data->desired_state.rect = *new_rect;
if (!data->whole_window) return; /* no window, 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 );
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 ((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 );
data->net_wm_state = new_state;
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;
data->desired_state.wm_state = new_state;
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 */
data->pending_state.wm_state = new_state;
data->wm_state_serial = NextRequest( data->display );
TRACE( "window %p/%lx, requesting WM_STATE %#x -> %#x serial %lu\n", data->hwnd, data->whole_window,
old_state, new_state, data->wm_state_serial );
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, NtUserGetForegroundWindow() );
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 );
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;
make_owner_managed( hwnd );
wait_for_withdrawn_state( hwnd, TRUE );
if (!(data = get_win_data( hwnd ))) return;
@ -1464,7 +1475,6 @@ static void map_window( HWND hwnd, DWORD new_style )
sync_window_style( data );
window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState );
XFlush( data->display );
data->mapped = TRUE;
data->iconic = (new_style & WS_MINIMIZE) != 0;
@ -1481,8 +1491,6 @@ static void unmap_window( HWND hwnd )
{
struct x11drv_win_data *data;
wait_for_withdrawn_state( hwnd, FALSE );
if (!(data = get_win_data( hwnd ))) return;
if (data->mapped)
@ -1490,14 +1498,96 @@ static void unmap_window( HWND hwnd )
TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
window_set_wm_state( data, WithdrawnState );
data->mapped = FALSE;
data->net_wm_state = 0;
}
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 )
{
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;
const char *reason = NULL, *expected, *received;
@ -1522,16 +1612,20 @@ void window_wm_state_notify( struct x11drv_win_data *data, unsigned long serial,
else
{
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;
*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 )
{
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;
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
{
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;
*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 )
{
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;
const char *reason = NULL, *expected, *received;
@ -1586,13 +1684,26 @@ void window_configure_notify( struct x11drv_win_data *data, unsigned long serial
else
{
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;
*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
*/
@ -1600,7 +1711,6 @@ void make_window_embedded( struct x11drv_win_data *data )
{
/* the window cannot be mapped before being embedded */
window_set_wm_state( data, WithdrawnState );
data->net_wm_state = 0;
data->embedded = TRUE;
data->managed = TRUE;
sync_window_style( data );
@ -1957,6 +2067,7 @@ static void create_whole_window( struct x11drv_win_data *data )
if (!data->whole_window) goto done;
SetRect( &data->current_state.rect, pos.x, pos.y, pos.x + cx, pos.y + cy );
data->pending_state.rect = data->current_state.rect;
data->desired_state.rect = data->current_state.rect;
x11drv_xinput2_enable( 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 );
data->whole_window = data->client_window = 0;
data->whole_colormap = 0;
data->wm_state = WithdrawnState;
data->net_wm_state = 0;
data->mapped = FALSE;
memset( &data->desired_state, 0, sizeof(data->desired_state) );
memset( &data->pending_state, 0, sizeof(data->pending_state) );
memset( &data->current_state, 0, sizeof(data->current_state) );
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 is_fullscreen : 1; /* is the window visible rect fullscreen */
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 */
Pixmap icon_pixmap;
Pixmap icon_mask;
unsigned long *icon_bits;
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 current_state; /* window state tracking the current X11 state */
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_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_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 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 void update_user_time( Time time );
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)
{
time_t tmpTime;
struct tm tmpTM;
SYSTEMTIME *STHook;
SYSTEMTIME st;
tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
tmpTM = *gmtime(&tmpTime);
STHook = (SYSTEMTIME *)lpBuffer;
STHook->wDay = tmpTM.tm_mday;
STHook->wHour = tmpTM.tm_hour;
STHook->wMilliseconds = 0;
STHook->wMinute = tmpTM.tm_min;
STHook->wDayOfWeek = tmpTM.tm_wday;
STHook->wMonth = tmpTM.tm_mon + 1;
STHook->wSecond = tmpTM.tm_sec;
STHook->wYear = 1900+tmpTM.tm_year;
TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
if (!InternetTimeToSystemTimeW(lphttpHdr->lpszValue, &st, 0))
{
LeaveCriticalSection( &request->headers_section );
return ERROR_HTTP_INVALID_HEADER;
}
if (*lpdwBufferLength < sizeof(st))
{
*lpdwBufferLength = sizeof(st);
LeaveCriticalSection( &request->headers_section );
return ERROR_INSUFFICIENT_BUFFER;
}
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);
memcpy(lpBuffer, &st, sizeof(st));
*lpdwBufferLength = sizeof(st);
}
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
* 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));
return FALSE;
@ -4598,7 +4595,7 @@ static BOOL HTTP_ParseRfc1123Date(LPCWSTR value, FILETIME *ft)
while (iswspace(*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));
return FALSE;
@ -4715,7 +4712,7 @@ static BOOL HTTP_ParseRfc850Date(LPCWSTR value, FILETIME *ft)
while (iswspace(*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));
return FALSE;

View file

@ -2412,6 +2412,7 @@ static const char okmsg2[] =
"Content-Length: 0\r\n"
"Set-Cookie: one\r\n"
"Set-Cookie: two\r\n"
"Last-Modified: Mon, 01 Dec 2008 13:44:34 UTC\r\n"
"\r\n";
static DWORD64 content_length;
@ -4566,9 +4567,11 @@ static void test_head_request(int port)
static void test_HttpQueryInfo(int port)
{
static const SYSTEMTIME expect = {2008, 12, 1, 1, 13, 44, 34};
test_request_t req;
DWORD size, index, error;
char buffer[1024];
SYSTEMTIME st;
BOOL ret;
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);
index = 0;
size = sizeof(buffer);
ret = HttpQueryInfoA(req.request, HTTP_QUERY_DATE | HTTP_QUERY_FLAG_SYSTEMTIME, buffer, &size, &index);
size = 0;
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(!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);
index = 0;

View file

@ -1116,9 +1116,11 @@ static void test_InternetTimeToSystemTime(void)
test_data[] =
{
{ "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, 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 UTC", &expect1, TRUE },
{ "5, 07-01-2005 12:06:35 GMT;", &expect1, TRUE },
{ "5, 07-01-2005 12:06:35 GMT123", &expect1, 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-Jan-2022 11:13:05", &expect2, TRUE },
{ "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);

View file

@ -39,92 +39,6 @@
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)
{
ADDRINFOW *res, hints;

View file

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

View file

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

View file

@ -7,5 +7,5 @@
@ stub RoGetMetaDataFile
@ stdcall RoIsApiContractMajorVersionPresent(wstr long ptr)
@ stub RoIsApiContractPresent
@ stub RoParseTypeName
@ stdcall RoParseTypeName(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"
#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 */

View file

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

View file

@ -430,6 +430,36 @@ library UIAutomationClient {
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>")]
module UIA_LandmarkTypeIds
{

View file

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

View file

@ -45,7 +45,7 @@ struct async
struct timeout_user *timeout;
unsigned int timeout_status; /* status to report upon timeout */
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 */
obj_handle_t wait_handle; /* pre-allocated wait handle */
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)
{
apc_call_t data;
union apc_call data;
memset( &data, 0, sizeof(data) );
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 */
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 async *async;
@ -515,7 +515,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
{
if (async->data.apc)
{
apc_call_t data;
union apc_call data;
memset( &data, 0, sizeof(data) );
data.type = APC_USER;
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
* 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 iosb *iosb;

View file

@ -48,7 +48,7 @@ struct debug_event
struct file *file; /* file object for events that need one */
enum debug_event_state state; /* event state */
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'};
@ -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 )
{
const debug_event_t *data = arg;
const union debug_event_data *data = arg;
event->data.exception = data->exception;
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;
if (debug_obj)
{
debug_event_t data;
union debug_event_data data;
struct debug_event *event;
struct thread *thread = current;

View file

@ -49,7 +49,7 @@ struct irp_call
struct device_file *file; /* file containing this irp */
struct thread *thread; /* thread that queued the irp */
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 */
int canceled; /* the call was canceled */
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 );
}
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;
@ -455,7 +456,7 @@ static struct object *device_open_file( struct object *obj, unsigned int access,
if (device->manager)
{
struct irp_call *irp;
irp_params_t params;
union irp_params params;
memset( &params, 0, sizeof(params) );
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 */
{
struct irp_call *irp;
irp_params_t params;
union irp_params params;
file->closed = 1;
memset( &params, 0, sizeof(params) );
@ -542,7 +543,7 @@ static void device_file_destroy( struct object *obj )
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)
{
@ -595,7 +596,7 @@ static void free_irp_params( struct irp_call *irp )
}
/* 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 );
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 )
{
struct device_file *file = get_fd_user( fd );
irp_params_t params;
union irp_params params;
memset( &params, 0, sizeof(params) );
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 )
{
struct device_file *file = get_fd_user( fd );
irp_params_t params;
union irp_params params;
memset( &params, 0, sizeof(params) );
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 )
{
struct device_file *file = get_fd_user( fd );
irp_params_t params;
union irp_params params;
memset( &params, 0, sizeof(params) );
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 )
{
struct device_file *file = get_fd_user( fd );
irp_params_t params;
union irp_params params;
memset( &params, 0, sizeof(params) );
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 )
{
struct device_file *file = get_fd_user( fd );
irp_params_t params;
union irp_params params;
memset( &params, 0, sizeof(params) );
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 )
{
struct irp_call *cancel_irp;
irp_params_t params;
union irp_params params;
irp->canceled = 1;
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 irp_call *irp;
irp_params_t params;
union irp_params params;
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 );
}
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);
}
@ -257,7 +257,7 @@ static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *en
{
struct wait_queue_entry *ptr;
struct process *process;
enum select_op select_op;
enum select_opcode select_op;
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 );
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_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data,
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 struct async_data *data,
int is_system );
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 );

View file

@ -262,6 +262,9 @@ void init_memory(void)
page_mask = sysconf( _SC_PAGESIZE ) - 1;
free_map_addr( 0x60000000, 0x1c000000 );
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 )

View file

@ -73,7 +73,7 @@ struct request_max_size
/* debug event data */
typedef union
union debug_event_data
{
int code; /* event code */
struct
@ -125,7 +125,7 @@ typedef union
int __pad;
mod_handle_t base; /* base address of the dll */
} unload_dll;
} debug_event_t;
};
enum context_exec_space
@ -276,7 +276,7 @@ typedef struct
} rectangle_t;
/* 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 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 apc; /* user APC to call */
apc_param_t apc_context; /* user APC context or completion value */
} async_data_t;
};
/* structures for extra message data */
@ -328,7 +328,7 @@ struct winevent_msg_data
/* followed by module name if any */
};
typedef union
union hw_input
{
int type;
struct
@ -358,15 +358,15 @@ typedef union
lparam_t lparam; /* parameters */
struct hid_input hid; /* defined in ntuser.h */
} hw;
} hw_input_t;
};
typedef union
union message_data
{
unsigned char bytes[1]; /* raw data for sent messages */
struct hardware_msg_data hardware;
struct callback_msg_data callback;
struct winevent_msg_data winevent;
} message_data_t;
};
/* structure returned in filesystem events */
struct filesystem_event
@ -451,7 +451,7 @@ struct object_type_info
/* VARARG(name,unicode_str); */
};
enum select_op
enum select_opcode
{
SELECT_NONE,
SELECT_WAIT,
@ -461,28 +461,28 @@ enum select_op
SELECT_KEYED_EVENT_RELEASE
};
typedef union
union select_op
{
enum select_op op;
enum select_opcode op;
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];
int __pad;
} wait;
struct
{
enum select_op op; /* SELECT_SIGNAL_AND_WAIT */
enum select_opcode op; /* SELECT_SIGNAL_AND_WAIT */
obj_handle_t wait;
obj_handle_t signal; /* must be last in the structure so we can remove it on retries */
} signal_and_wait;
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;
client_ptr_t key;
} keyed_event;
} select_op_t;
};
enum apc_type
{
@ -504,18 +504,18 @@ enum apc_type
APC_DUP_HANDLE
};
typedef struct
struct user_apc
{
enum apc_type type; /* APC_USER */
int __pad;
client_ptr_t func; /* void (__stdcall *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR); */
apc_param_t args[3]; /* arguments for user function */
} user_apc_t;
};
typedef union
union apc_call
{
enum apc_type type;
user_apc_t user;
struct user_apc user;
struct
{
enum apc_type type; /* APC_ASYNC_IO */
@ -636,9 +636,9 @@ typedef union
unsigned int attributes; /* object attributes */
unsigned int options; /* duplicate options */
} dup_handle;
} apc_call_t;
};
typedef union
union apc_result
{
enum apc_type type;
struct
@ -748,7 +748,7 @@ typedef union
enum apc_type type; /* APC_BREAK_PROCESS */
unsigned int status; /* status returned by call */
} break_process;
} apc_result_t;
};
enum irp_type
{
@ -764,7 +764,7 @@ enum irp_type
IRP_CALL_CANCEL
};
typedef union
union irp_params
{
enum irp_type type; /* irp call type */
struct
@ -832,7 +832,7 @@ typedef union
int __pad;
client_ptr_t irp; /* opaque ptr for canceled irp */
} cancel;
} irp_params_t;
};
/* information about a PE image mapping, roughly equivalent to SECTION_IMAGE_INFORMATION */
typedef struct
@ -1232,7 +1232,7 @@ typedef struct
@REQ(get_apc_result)
obj_handle_t handle; /* handle to the APC */
@REPLY
apc_result_t result; /* result of the APC */
union apc_result result; /* result of the APC */
@END
@ -1539,7 +1539,7 @@ enum server_fd_type
/* Flush a file buffers */
@REQ(flush)
async_data_t async; /* async I/O parameters */
struct async_data async; /* async I/O parameters */
@REPLY
obj_handle_t event; /* event set when finished */
@END
@ -1555,7 +1555,7 @@ enum server_fd_type
/* Query volume information */
@REQ(get_volume_info)
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 */
@REPLY
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 */
@REQ(recv_socket)
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? */
@REPLY
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 */
@REQ(send_socket)
unsigned int flags; /* SERVER_SOCKET_IO_* flags */
async_data_t async; /* async I/O parameters */
struct async_data async; /* async I/O parameters */
@REPLY
obj_handle_t wait; /* handle to wait on for blocking send */
unsigned int options; /* device open options */
@ -1656,7 +1656,7 @@ enum server_fd_type
unsigned int filter; /* notification filter */
int subtree; /* watch the subtree? */
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
@ -2241,7 +2241,7 @@ enum message_type
/* Send a hardware message to a thread queue */
@REQ(send_hardware_message)
user_handle_t win; /* window handle */
hw_input_t input; /* input data */
union hw_input input; /* input data */
unsigned int flags; /* flags (see below) */
VARARG(report,bytes); /* HID report data */
@REPLY
@ -2355,7 +2355,7 @@ enum message_type
/* Create an async I/O */
@REQ(register_async)
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 */
@END
#define ASYNC_TYPE_READ 0x01
@ -2392,7 +2392,7 @@ enum message_type
/* Perform a read on a file object */
@REQ(read)
async_data_t async; /* async I/O parameters */
struct async_data async; /* async I/O parameters */
file_pos_t pos; /* read position */
@REPLY
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 */
@REQ(write)
async_data_t async; /* async I/O parameters */
struct async_data async; /* async I/O parameters */
file_pos_t pos; /* write position */
VARARG(data,bytes); /* write data */
@REPLY
@ -2416,7 +2416,7 @@ enum message_type
/* Perform an ioctl on a file */
@REQ(ioctl)
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 */
@REPLY
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 */
VARARG(data,bytes); /* output data of the previous irp */
@REPLY
irp_params_t params; /* irp parameters */
union irp_params params; /* irp parameters */
obj_handle_t next; /* handle to the next irp */
thread_id_t client_tid; /* tid of thread 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;
}
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->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 */
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 )
{
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;
}
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 );
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 */
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 )
{
const desktop_shm_t *desktop_shm = desktop->shared;
@ -2502,7 +2502,7 @@ struct pointer
struct desktop *desktop;
user_handle_t win;
int primary;
hw_input_t input;
union hw_input input;
};
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 desktop *desktop = pointer->desktop;
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;
timeout_t time = get_tick_count();
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 */
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;
struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };

View file

@ -60,8 +60,7 @@
#include "thread.h"
#include "security.h"
#include "handle.h"
#define WANT_REQUEST_HANDLERS
#include "request.h"
#include "request_handlers.h"
/* Some versions of glibc don't define this */
#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 flags;
int abandoned;
enum select_op select;
enum select_opcode select;
client_ptr_t key; /* wait key for keyed events */
client_ptr_t cookie; /* magic cookie to return to client */
abstime_t when;
@ -79,8 +79,8 @@ struct thread_apc
struct thread *caller; /* thread that queued this apc */
struct object *owner; /* object that queued this apc */
int executed; /* has it been executed by the client? */
apc_call_t call; /* call arguments */
apc_result_t result; /* call results once executed */
union apc_call call; /* call arguments */
union apc_result result; /* call results once executed */
};
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 */
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;
@ -721,7 +721,7 @@ struct thread *get_wait_queue_thread( struct wait_queue_entry *entry )
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;
}
@ -775,7 +775,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status )
}
/* 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 )
{
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;
}
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 )
{
struct object *objects[MAXIMUM_WAIT_OBJECTS];
@ -981,7 +981,7 @@ static int signal_object( obj_handle_t handle )
}
/* 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 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_ALL:
count = (op_size - offsetof( select_op_t, wait.handles )) / sizeof(select_op->wait.handles[0]);
if (op_size < offsetof( select_op_t, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS)
count = (op_size - offsetof( union select_op, wait.handles )) / sizeof(select_op->wait.handles[0]);
if (op_size < offsetof( union select_op, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS)
{
set_error( STATUS_INVALID_PARAMETER );
return 1;
@ -1155,7 +1155,7 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr
}
/* 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;
int ret = 0;
@ -1580,11 +1580,11 @@ DECL_HANDLER(resume_thread)
/* select on a handle list */
DECL_HANDLER(select)
{
select_op_t select_op;
union select_op select_op;
data_size_t op_size, ctx_size;
struct context *ctx;
struct thread_apc *apc;
const apc_result_t *result = get_req_data();
const union apc_result *result = get_req_data();
unsigned int ctx_count;
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 );
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 );
set_reply_data( &apc->call, sizeof(apc->call) );
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 );
if ((reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 )))
@ -1685,13 +1685,13 @@ DECL_HANDLER(select)
}
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)
{
ctx = current->context;
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);
unsigned int flags = system_flags & ctx->regs[CTX_NATIVE].flags;
@ -1718,7 +1718,7 @@ DECL_HANDLER(queue_apc)
struct thread *thread = NULL;
struct process *process = NULL;
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;

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_pid( int pid );
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 void make_wait_abandoned( struct wait_queue_entry *entry );
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 kill_thread( struct thread *thread, int violent_death );
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 int thread_add_inflight_fd( struct thread *thread, int client, int server );
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 */
if (timer->thread)
{
apc_call_t data;
union apc_call data;
assert (timer->callback);
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 */
timeout_t delay; /* auto-repeat delay */
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 */
struct timeout_user *timeout; /* timeout for repeat */
};

View file

@ -1,6 +1,6 @@
#! /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.
#
# Copyright (C) 1998 Alexandre Julliard
@ -32,55 +32,55 @@ my %formats =
"data_size_t" => [ 4, 4, "%u" ],
"obj_handle_t" => [ 4, 4, "%04x" ],
"atom_t" => [ 4, 4, "%04x" ],
"user_handle_t" => [ 4, 4, "%08x" ],
"process_id_t" => [ 4, 4, "%04x" ],
"thread_id_t" => [ 4, 4, "%04x" ],
"client_ptr_t" => [ 8, 8, "&dump_uint64" ],
"mod_handle_t" => [ 8, 8, "&dump_uint64" ],
"lparam_t" => [ 8, 8, "&dump_uint64" ],
"apc_param_t" => [ 8, 8, "&dump_uint64" ],
"file_pos_t" => [ 8, 8, "&dump_uint64" ],
"mem_size_t" => [ 8, 8, "&dump_uint64" ],
"affinity_t" => [ 8, 8, "&dump_uint64" ],
"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" ],
"unsigned __int64" => [ 8, 8, "&uint64" ],
"timeout_t" => [ 8, 8 ],
"abstime_t" => [ 8, 8 ],
"rectangle_t" => [ 16, 4 ],
"generic_map_t" => [ 16, 4 ],
"ioctl_code_t" => [ 4, 4 ],
"obj_locator_t" => [ 16, 8 ],
# varargs-only structures
"apc_call_t" => [ 64, 8 ],
"context_t" => [ 1728, 8 ],
"cursor_pos_t" => [ 24, 8 ],
"debug_event_t" => [ 160, 8 ],
"message_data_t" => [ 48, 8 ],
"pe_image_info_t" => [ 88, 8 ],
"property_data_t" => [ 16, 8 ],
"select_op_t" => [ 264, 8 ],
"startup_info_t" => [ 96, 4 ],
"tcp_connection" => [ 60, 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 handle_info" => [ 20, 4 ],
"union hw_input" => [ 40, 8 ],
"union irp_params" => [ 32, 8 ],
"struct luid" => [ 8, 4 ],
"struct luid_attr" => [ 12, 4 ],
"union message_data" => [ 48, 8 ],
"struct object_attributes" => [ 16, 4 ],
"struct object_type_info" => [ 44, 4 ],
"struct process_info" => [ 40, 8 ],
"struct rawinput_device" => [ 12, 4 ],
"union select_op" => [ 264, 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 %replies = ();
my %dump_funcs = ();
my @asserts = ();
my @protocol_lines = ();
my @trace_lines = ();
my $max_req_size = 64;
@ -93,7 +93,7 @@ sub add_padding($$)
if ($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;
}
return $offset;
@ -115,10 +115,24 @@ sub DO_DUMP_FUNC($$@)
if (defined($formats{$type}))
{
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;
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+\((.*)\)/)
{
@ -178,8 +192,8 @@ sub PARSE_REQUESTS()
@in_struct = ();
@out_struct = ();
$offset = 12;
print SERVER_PROT "struct ${name}_request\n{\n";
print SERVER_PROT " struct request_header __header;\n";
push @protocol_lines, "struct ${name}_request\n{\n";
push @protocol_lines, " struct request_header __header;\n";
$state++;
next;
}
@ -190,9 +204,9 @@ sub PARSE_REQUESTS()
$offset = add_padding( $offset, 8 ); # all requests should be 8-byte aligned
die "request $name too large ($offset)" if ($offset > $max_req_size);
push @asserts, "C_ASSERT( sizeof(struct ${name}_request) == $offset );\n";
print SERVER_PROT "};\n";
print SERVER_PROT "struct ${name}_reply\n{\n";
print SERVER_PROT " struct reply_header __header;\n";
push @protocol_lines, "};\n";
push @protocol_lines, "struct ${name}_reply\n{\n";
push @protocol_lines, " struct reply_header __header;\n";
$offset = 8;
$state++;
next;
@ -203,14 +217,14 @@ sub PARSE_REQUESTS()
die "Misplaced \@END" unless ($state == 2 || $state == 3);
$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
{
die "request $name too large ($offset)" if ($offset > $max_req_size);
push @asserts, "C_ASSERT( sizeof(struct ${name}_request) == $offset );\n";
print SERVER_PROT "struct ${name}_reply\n{\n";
print SERVER_PROT " struct reply_header __header;\n";
print SERVER_PROT "};\n";
push @protocol_lines, "struct ${name}_reply\n{\n";
push @protocol_lines, " struct reply_header __header;\n";
push @protocol_lines, "};\n";
}
else
{
@ -234,26 +248,22 @@ sub PARSE_REQUESTS()
# skip empty lines (but keep them in output file)
if (/^$/)
{
print SERVER_PROT "\n";
push @protocol_lines, "\n";
next;
}
if (/^\s*VARARG\((\w+),(\w+),(\d+)\)/)
if (/^\s*VARARG\((\w+),(\w+),(\w+)\)/)
{
$var = $1;
$type = "dump_varargs_$2( \"%s\", min(cur_size,$3) )";
s!(VARARG\(.*\)\s*;)!/* $1 */!;
}
elsif (/^\s*VARARG\((\w+),(\w+),(\w+)\)/)
{
$var = $1;
$type = "dump_varargs_" . $2 . "( \"%s\", min(cur_size,req->" . $3 . ") )";
$type = "dump_varargs_$2( \"%s\", min( cur_size, req->" . $3 . " ))";
$dump_funcs{"varargs_$2"} = $2;
s!(VARARG\(.*\)\s*;)!/* $1 */!;
}
elsif (/^\s*VARARG\((\w+),(\w+)\)/)
{
$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 */!;
}
elsif (/^\s*(\w+\**(\s+\w+\**)*)\s+(\w+);/)
@ -266,16 +276,16 @@ sub PARSE_REQUESTS()
{
my $count = $fmt[1] - ($offset & ($fmt[1] - 1));
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;
}
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
{
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];
}
@ -286,9 +296,18 @@ sub PARSE_REQUESTS()
if ($state == 2) { push @in_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
print SERVER_PROT $_ . "\n";
push @protocol_lines, $_ . "\n";
}
close PROTOCOL;
}
@ -337,9 +356,15 @@ sub GET_ERROR_NAMES()
}
# 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";
if (!$ret)
{
@ -353,42 +378,6 @@ sub update_file($)
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
# Get the server protocol version
@ -398,13 +387,8 @@ my %errors = GET_ERROR_NAMES();
### 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";
print SERVER_PROT "/*\n * Wine server protocol definitions\n *\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";
push @protocol_lines, "#ifndef __WINE_WINE_SERVER_PROTOCOL_H\n";
push @protocol_lines, "#define __WINE_WINE_SERVER_PROTOCOL_H\n";
### Parse requests to find request/reply structure definitions
@ -412,57 +396,53 @@ PARSE_REQUESTS();
### Build the request list and structures
print SERVER_PROT "\n\nenum request\n{\n";
foreach my $req (@requests) { print SERVER_PROT " REQ_$req,\n"; }
print SERVER_PROT " REQ_NB_REQUESTS\n};\n\n";
push @protocol_lines, "\n\nenum request\n{\n";
foreach my $req (@requests) { push @protocol_lines, " REQ_$req,\n"; }
push @protocol_lines, " REQ_NB_REQUESTS\n};\n\n";
print SERVER_PROT "union generic_request\n{\n";
print SERVER_PROT " struct request_max_size max_size;\n";
print SERVER_PROT " struct request_header request_header;\n";
foreach my $req (@requests) { print SERVER_PROT " struct ${req}_request ${req}_request;\n"; }
print SERVER_PROT "};\n";
push @protocol_lines, "union generic_request\n{\n";
push @protocol_lines, " struct request_max_size max_size;\n";
push @protocol_lines, " struct request_header request_header;\n";
foreach my $req (@requests) { push @protocol_lines, " struct ${req}_request ${req}_request;\n"; }
push @protocol_lines, "};\n";
print SERVER_PROT "union generic_reply\n{\n";
print SERVER_PROT " struct request_max_size max_size;\n";
print SERVER_PROT " struct reply_header reply_header;\n";
foreach my $req (@requests) { print SERVER_PROT " struct ${req}_reply ${req}_reply;\n"; }
print SERVER_PROT "};\n\n";
push @protocol_lines, "union generic_reply\n{\n";
push @protocol_lines, " struct request_max_size max_size;\n";
push @protocol_lines, " struct reply_header reply_header;\n";
foreach my $req (@requests) { push @protocol_lines, " struct ${req}_reply ${req}_reply;\n"; }
push @protocol_lines, "};\n\n";
print SERVER_PROT "/* ### protocol_version begin ### */\n\n";
printf SERVER_PROT "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol;
print SERVER_PROT "/* ### protocol_version end ### */\n\n";
print SERVER_PROT "#endif /* __WINE_WINE_SERVER_PROTOCOL_H */\n";
push @protocol_lines, sprintf "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol;
push @protocol_lines, "#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;
if (update_file( "include/wine/server_protocol.h" ))
if (update_file( "include/wine/server_protocol.h", @protocol_lines ))
{
my @version_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 );
$protocol_lines[$#protocol_lines - 1] = sprintf "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol + 1;
update_file( "include/wine/server_protocol.h", @protocol_lines );
}
### 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)
{
push @trace_lines, " (dump_func)dump_${req}_request,\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)
{
push @trace_lines, " ", $replies{$req} ? "(dump_func)dump_${req}_reply,\n" : "NULL,\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)
{
push @trace_lines, " \"$req\",\n";
@ -481,18 +461,32 @@ foreach my $err (sort keys %errors)
push @trace_lines, " { NULL, 0 }\n";
push @trace_lines, "};\n";
replace_in_file( "server/trace.c",
"### make_requests begin ###",
"### make_requests end ###",
@trace_lines );
my @trace_header = ();
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
my @request_lines = ();
my @request_lines = ( "#include \"request.h\"\n\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, "typedef void (*req_handler)( const void *req, void *reply );\n";
push @request_lines, "\ntypedef void (*req_handler)( const void *req, void *reply );\n";
push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n";
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;
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",
"### make_requests begin ###",
"### make_requests end ###",
@request_lines );
update_file( "server/request_handlers.h", @request_lines, @asserts );