1
0
mirror of https://github.com/wine-mirror/wine synced 2024-06-29 06:14:34 +00:00

Compare commits

...

27 Commits

Author SHA1 Message Date
Rémi Bernon
8c64979dcb winex11: Create a global vulkan instance for xrandr. 2024-06-20 23:03:26 +02:00
Rémi Bernon
6e526d19f7 win32u: Remove now unused vulkan_funcs in d3dkmt.c. 2024-06-20 23:03:26 +02:00
Jacek Caban
ec17fc4ca3 mshtml: Add support for using apply on builtin function objects.
Based on patch by Gabriel Ivăncescu.
2024-06-20 23:03:26 +02:00
Jacek Caban
7b95b93c42 mshtml: Add support for using call on builtin function objects.
Based on patch by Gabriel Ivăncescu.
2024-06-20 23:03:26 +02:00
Jacek Caban
005e164751 mshtml: Rename builtin function helpers. 2024-06-20 23:03:26 +02:00
Jacek Caban
bea627b646 mshtml: Introduce IWineJSDispatchHost interface.
Based on patch by Gabriel Ivăncescu.
2024-06-20 23:03:26 +02:00
Rémi Bernon
81eafa9b78 win32u: Use the desktop shared data for GetCursorPos.
Based on a patch by Huw Davies.
2024-06-20 23:03:26 +02:00
Rémi Bernon
5488d99b3e server: Move the last cursor time to the desktop session object.
Based on a patch by Huw Davies.
2024-06-20 23:03:26 +02:00
Rémi Bernon
728049d6fa server: Move the cursor position to the desktop session object.
Based on a patch by Huw Davies.
2024-06-20 23:03:26 +02:00
Rémi Bernon
eb63ac74dc win32u: Open the desktop shared object in NtUserSetThreadDesktop. 2024-06-20 23:03:26 +02:00
Rémi Bernon
20f4c9af0f server: Return the desktop object locator in (get|set)_thread_desktop. 2024-06-20 23:03:26 +02:00
Rémi Bernon
1e10e3a1c0 server: Allocate shared session object for desktops. 2024-06-20 23:03:26 +02:00
Rémi Bernon
f82b1c1fcf include: Add ReadNoFence64 inline helpers. 2024-06-20 23:03:26 +02:00
Rémi Bernon
fac940dfac server: Create a global session shared mapping. 2024-06-20 23:03:26 +02:00
Eric Pouech
96d682e5f7 cmd: Test input has been read before using it.
This let confirmations fail when reading from NUL
(instead of looping forever).

Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-06-20 23:03:26 +02:00
Eric Pouech
96762f12e7 cmd: Remove old FOR loop related code.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-06-20 23:03:26 +02:00
Eric Pouech
f98077591f cmd: Fix delayed expansion in FOR loop on file sets.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-06-20 23:03:26 +02:00
Eric Pouech
0ca28d3a70 cmd: Split parsing from executing FOR loops for file walking.
Signed-off-by: Eric Pouech <epouech@codeweavers.com>
2024-06-20 23:03:26 +02:00
Alexandre Julliard
6e82d33eb7 ntdll: Don't set the TEB ExceptionList to -1 on 64-bit.
The tests show that it should be zero.
2024-06-20 23:03:26 +02:00
Alexandre Julliard
0d5936563d ntdll: Fix the fake 32-bit %cs value on ARM64EC. 2024-06-20 23:03:26 +02:00
Alexandre Julliard
b7a3023ca1 ntdll: Send cross-process notification in memory functions on ARM64EC.
Copied from the corresponding code in wow64.dll.
2024-06-20 23:03:26 +02:00
Alexandre Julliard
9f8d4d0b0a ntdll: Add helper macros to define syscalls on ARM64EC. 2024-06-20 23:03:26 +02:00
Ziqing Hui
417b4cb453 winegstreamer: Implement stubs for h264 encoder. 2024-06-20 11:16:46 +02:00
Ziqing Hui
9dfc402cc3 mf/tests: Add tests for H264 encoder types. 2024-06-20 11:16:46 +02:00
Elizabeth Figura
85fd5e283a maintainers: Remove myself as a winegstreamer maintainer. 2024-06-20 11:15:57 +02:00
Alex Henrie
867af68b17 ntdll: Fix handling of non-string types with RTL_QUERY_REGISTRY_DIRECT. 2024-06-20 11:14:07 +02:00
Brendan Shanks
802a52cb1b ntdll: Make __wine_syscall_dispatcher_return a separate function to fix Xcode 16 build errors.
LLVM no longer allows non-private labels to appear between
.cfi_startproc/endproc when targeting Mach-O.
For consistency, also modify ARM and i386.
2024-06-20 11:13:44 +02:00
58 changed files with 2218 additions and 2380 deletions

View File

@ -158,7 +158,7 @@ M: Marcus Meissner <marcus@jet.franken.de>
F: dlls/gphoto2.ds/
GStreamer multimedia backend
M: Elizabeth Figura <zfigura@codeweavers.com>
P: Elizabeth Figura <zfigura@codeweavers.com>
P: Rémi Bernon <rbernon@codeweavers.com>
F: dlls/winegstreamer/

View File

@ -694,8 +694,9 @@ static void check_mft_set_input_type_required_(int line, IMFTransform *transform
ok_(__FILE__, line)(!ref, "Release returned %lu\n", ref);
}
#define check_mft_set_input_type(a, b) check_mft_set_input_type_(__LINE__, a, b, FALSE)
static void check_mft_set_input_type_(int line, IMFTransform *transform, const struct attribute_desc *attributes, BOOL todo)
#define check_mft_set_input_type(a, b, c) check_mft_set_input_type_(__LINE__, a, b, c, FALSE)
static void check_mft_set_input_type_(int line, IMFTransform *transform, const struct attribute_desc *attributes,
HRESULT expect_hr, BOOL todo)
{
IMFMediaType *media_type;
HRESULT hr;
@ -705,10 +706,10 @@ static void check_mft_set_input_type_(int line, IMFTransform *transform, const s
init_media_type(media_type, attributes, -1);
hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY);
ok_(__FILE__, line)(hr == S_OK, "SetInputType returned %#lx.\n", hr);
ok_(__FILE__, line)(hr == expect_hr, "SetInputType returned %#lx.\n", hr);
hr = IMFTransform_SetInputType(transform, 0, media_type, 0);
todo_wine_if(todo)
ok_(__FILE__, line)(hr == S_OK, "SetInputType returned %#lx.\n", hr);
ok_(__FILE__, line)(hr == expect_hr, "SetInputType returned %#lx.\n", hr);
IMFMediaType_Release(media_type);
}
@ -2154,7 +2155,7 @@ static void test_aac_encoder(void)
check_mft_get_output_current_type(transform, expect_output_type_desc);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type(transform, expect_input_type_desc);
check_mft_get_input_stream_info(transform, S_OK, &input_info);
@ -2412,7 +2413,7 @@ static void test_aac_decoder_subtype(const struct attribute_desc *input_type_des
check_mft_get_output_current_type(transform, NULL);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type(transform, input_type_desc);
/* check new output media types */
@ -2920,7 +2921,7 @@ static void test_wma_encoder(void)
check_mft_get_output_current_type(transform, expect_output_type_desc);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type(transform, expect_input_type_desc);
check_mft_get_input_stream_info(transform, S_OK, &input_info);
@ -3235,7 +3236,7 @@ static void test_wma_decoder(void)
check_mft_get_output_current_type_(__LINE__, transform, NULL, TRUE, FALSE);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, TRUE, FALSE);
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
@ -3809,6 +3810,32 @@ static void test_h264_encoder(void)
{.subtype = &MFVideoFormat_H264},
},
};
static const media_type_desc default_outputs[] =
{
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264),
},
};
static const media_type_desc default_inputs[] =
{
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_IYUV),
},
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YV12),
},
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12),
},
{
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_YUY2),
},
};
static const struct attribute_desc expect_transform_attributes[] =
{
ATTR_UINT32(MFT_ENCODER_SUPPORTS_CONFIG_EVENT, 1),
@ -3854,9 +3881,11 @@ static void test_h264_encoder(void)
static const MFT_OUTPUT_STREAM_INFO expect_output_info = {.cbSize = 0x8000};
MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_H264};
MFT_REGISTER_TYPE_INFO input_type = {MFMediaType_Video, MFVideoFormat_NV12};
IMFMediaType *media_type;
IMFTransform *transform;
HRESULT hr;
ULONG ret;
DWORD i;
hr = CoInitialize(NULL);
ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr);
@ -3874,7 +3903,10 @@ static void test_h264_encoder(void)
check_mft_get_info(class_id, &expect_mft_info);
hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform);
todo_wine
ok(hr == S_OK, "CoCreateInstance returned %#lx.\n", hr);
if (hr != S_OK)
goto failed;
check_interface(transform, &IID_IMFTransform, TRUE);
check_interface(transform, &IID_IMediaObject, FALSE);
@ -3885,17 +3917,49 @@ static void test_h264_encoder(void)
check_mft_get_input_stream_info(transform, S_OK, NULL);
check_mft_get_output_stream_info(transform, S_OK, NULL);
/* No input type is available before an output type is set. */
hr = IMFTransform_GetInputAvailableType(transform, 0, 0, &media_type);
ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetInputAvailableType returned %#lx\n", hr);
check_mft_set_input_type(transform, input_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET);
check_mft_get_input_current_type(transform, NULL);
/* Check available output types. */
i = -1;
while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &media_type)))
{
winetest_push_context("out %lu", i);
ok(hr == S_OK, "GetOutputAvailableType returned %#lx.\n", hr);
check_media_type(media_type, default_outputs[i], -1);
ret = IMFMediaType_Release(media_type);
ok(ret == 0, "Release returned %lu\n", ret);
winetest_pop_context();
}
ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx.\n", hr);
ok(i == ARRAY_SIZE(default_outputs), "%lu output media types.\n", i);
check_mft_set_output_type_required(transform, output_type_desc);
check_mft_set_output_type(transform, output_type_desc, S_OK);
check_mft_get_output_current_type(transform, expect_output_type_desc);
check_mft_get_output_stream_info(transform, S_OK, &expect_output_info);
/* Input types can now be enumerated. */
i = -1;
while (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform, 0, ++i, &media_type)))
{
winetest_push_context("out %lu", i);
ok(hr == S_OK, "IMFTransform_GetInputAvailableType returned %#lx\n", hr);
check_media_type(media_type, default_inputs[i], -1);
ret = IMFMediaType_Release(media_type);
ok(ret == 0, "Release returned %lu\n", ret);
winetest_pop_context();
}
ok(hr == MF_E_NO_MORE_TYPES, "IMFTransform_GetInputAvailableType returned %#lx\n", hr);
ok(i == ARRAY_SIZE(default_inputs), "%lu input media types\n", i);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type(transform, expect_input_type_desc);
check_mft_get_output_current_type(transform, expect_output_type_desc);
check_mft_get_input_stream_info(transform, S_OK, NULL);
check_mft_get_output_stream_info(transform, S_OK, &expect_output_info);
ret = IMFTransform_Release(transform);
ok(ret == 0, "Release returned %lu\n", ret);
@ -4294,7 +4358,7 @@ static void test_h264_decoder(void)
ok(i == 2 || broken(i == 1) /* Win7 */, "%lu input media types\n", i);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
check_mft_get_input_stream_info(transform, S_OK, &input_info);
@ -4971,7 +5035,7 @@ static void test_audio_convert(void)
check_mft_get_output_current_type(transform, NULL);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
@ -5446,7 +5510,7 @@ static void test_wmv_encoder(void)
check_mft_get_output_current_type(transform, NULL);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
check_mft_set_output_type_required(transform, output_type_desc);
@ -6034,7 +6098,7 @@ static void test_wmv_decoder(void)
check_mft_get_output_current_type(transform, NULL);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
i = -1;
@ -7159,7 +7223,7 @@ static void test_color_convert(void)
ok(i == 20, "%lu input media types\n", i);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
for (i = 0; i < ARRAY_SIZE(color_conversion_tests); i++)
@ -7939,7 +8003,7 @@ static void test_video_processor(void)
ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr);
/* MFVideoFormat_ABGR32 isn't supported by the video processor in non-D3D mode */
check_mft_set_input_type(transform, nv12_default_stride);
check_mft_set_input_type(transform, nv12_default_stride, S_OK);
hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type);
ok(hr == S_OK, "got %#lx\n", hr);
@ -7961,7 +8025,7 @@ static void test_video_processor(void)
winetest_push_context("transform #%lu", i);
check_mft_set_input_type_required(transform, test->input_type_desc);
check_mft_set_input_type(transform, test->input_type_desc);
check_mft_set_input_type(transform, test->input_type_desc, S_OK);
check_mft_get_input_current_type(transform, test->input_type_desc);
if (i >= 15)
@ -8111,13 +8175,13 @@ skip_test:
&IID_IMFTransform, (void **)&transform);
ok(hr == S_OK, "got hr %#lx\n", hr);
check_mft_set_input_type(transform, nv12_no_aperture);
check_mft_set_input_type(transform, nv12_no_aperture, S_OK);
check_mft_get_input_current_type(transform, nv12_no_aperture);
check_mft_set_output_type(transform, rgb32_no_aperture, S_OK);
check_mft_get_output_current_type(transform, rgb32_no_aperture);
check_mft_set_input_type_(__LINE__, transform, nv12_with_aperture, TRUE);
check_mft_set_input_type_(__LINE__, transform, nv12_with_aperture, S_OK, TRUE);
check_mft_get_input_current_type_(__LINE__, transform, nv12_with_aperture, TRUE, FALSE);
/* output type is the same as before */
@ -8376,7 +8440,7 @@ static void test_mp3_decoder(void)
check_mft_get_output_current_type(transform, NULL);
check_mft_set_input_type_required(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc);
check_mft_set_input_type(transform, input_type_desc, S_OK);
check_mft_get_input_current_type(transform, expect_input_type_desc);
check_mft_get_input_stream_info(transform, MF_E_TRANSFORM_TYPE_NOT_SET, NULL);
@ -9427,7 +9491,7 @@ static void test_video_processor_with_dxgi_manager(void)
/* check RGB32 output aperture cropping with D3D buffers */
check_mft_set_input_type(transform, nv12_with_aperture);
check_mft_set_input_type(transform, nv12_with_aperture, S_OK);
check_mft_set_output_type_(__LINE__, transform, rgb32_no_aperture, S_OK, TRUE);
load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len);
@ -9495,7 +9559,7 @@ static void test_video_processor_with_dxgi_manager(void)
skip_rgb32:
/* check ABGR32 output with D3D buffers */
check_mft_set_input_type(transform, nv12_with_aperture);
check_mft_set_input_type(transform, nv12_with_aperture, S_OK);
check_mft_set_output_type_(__LINE__, transform, abgr32_no_aperture, S_OK, TRUE);
load_resource(L"nv12frame.bmp", &nv12frame_data, &nv12frame_data_len);

View File

@ -787,7 +787,7 @@ static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags,
return hres;
}
hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&unk);
hres = IWineJSDispatchHost_QueryInterface(&This->IWineJSDispatchHost_iface, tid_ids[func->tid], (void**)&unk);
if(FAILED(hres)) {
ERR("Could not get iface %s: %08lx\n", debugstr_mshtml_guid(tid_ids[func->tid]), hres);
return E_FAIL;
@ -799,6 +799,138 @@ static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags,
return hres;
}
static HRESULT get_disp_prop(IDispatchEx *dispex, const WCHAR *name, LCID lcid, VARIANT *res,
EXCEPINFO *ei, IServiceProvider *caller)
{
DISPPARAMS dp = { 0 };
DISPID dispid;
HRESULT hres;
BSTR bstr;
if(!(bstr = SysAllocString(name)))
return E_OUTOFMEMORY;
hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid);
SysFreeString(bstr);
if(SUCCEEDED(hres))
hres = IDispatchEx_InvokeEx(dispex, dispid, lcid, DISPATCH_PROPERTYGET, &dp, res, ei, caller);
return hres;
}
static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
{
IWineJSDispatchHost *this_iface;
DISPPARAMS params = { 0 };
IDispatchEx *array = NULL;
UINT argc = 0;
VARIANT *arg;
HRESULT hres;
arg = dp->rgvarg + dp->cArgs - 1;
if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !V_DISPATCH(arg))
return CTL_E_ILLEGALFUNCTIONCALL;
hres = IDispatch_QueryInterface(V_DISPATCH(arg), &IID_IWineJSDispatchHost, (void**)&this_iface);
if(FAILED(hres))
return CTL_E_ILLEGALFUNCTIONCALL;
if(dp->cArgs >= 2) {
VARIANT length;
arg--;
if(V_VT(arg) != VT_DISPATCH) {
hres = CTL_E_ILLEGALFUNCTIONCALL;
goto fail;
}
/* FIXME: Native checks if it's an acual JS array. */
hres = IDispatch_QueryInterface(V_DISPATCH(arg), &IID_IDispatchEx, (void**)&array);
if(FAILED(hres))
goto fail;
V_VT(&length) = VT_EMPTY;
hres = get_disp_prop(array, L"length", lcid, &length, ei, caller);
if(FAILED(hres)) {
if(hres == DISP_E_UNKNOWNNAME)
hres = CTL_E_ILLEGALFUNCTIONCALL;
goto fail;
}
if(V_VT(&length) != VT_I4) {
VARIANT tmp = length;
hres = change_type(&length, &tmp, VT_I4, caller);
if(FAILED(hres)) {
hres = CTL_E_ILLEGALFUNCTIONCALL;
goto fail;
}
}
if(V_I4(&length) < 0) {
hres = CTL_E_ILLEGALFUNCTIONCALL;
goto fail;
}
params.cArgs = V_I4(&length);
/* alloc new params */
if(params.cArgs) {
if(!(params.rgvarg = malloc(params.cArgs * sizeof(VARIANTARG)))) {
hres = E_OUTOFMEMORY;
goto fail;
}
for(argc = 0; argc < params.cArgs; argc++) {
WCHAR buf[12];
arg = params.rgvarg + params.cArgs - argc - 1;
swprintf(buf, ARRAY_SIZE(buf), L"%u", argc);
hres = get_disp_prop(array, buf, lcid, arg, ei, caller);
if(FAILED(hres)) {
if(hres == DISP_E_UNKNOWNNAME) {
V_VT(arg) = VT_EMPTY;
continue;
}
goto fail;
}
}
}
}
hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, &params, res, ei, caller);
fail:
while(argc--)
VariantClear(&params.rgvarg[params.cArgs - argc - 1]);
free(params.rgvarg);
if(array)
IDispatchEx_Release(array);
IWineJSDispatchHost_Release(this_iface);
return hres == E_UNEXPECTED ? CTL_E_ILLEGALFUNCTIONCALL : hres;
}
static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
{
DISPPARAMS params = { dp->rgvarg, NULL, dp->cArgs - 1, 0 };
IWineJSDispatchHost *this_iface;
VARIANT *arg;
HRESULT hres;
arg = dp->rgvarg + dp->cArgs - 1;
if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !V_DISPATCH(arg))
return CTL_E_ILLEGALFUNCTIONCALL;
hres = IDispatch_QueryInterface(V_DISPATCH(arg), &IID_IWineJSDispatchHost, (void**)&this_iface);
if(FAILED(hres))
return CTL_E_ILLEGALFUNCTIONCALL;
hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, &params, res, ei, caller);
IWineJSDispatchHost_Release(this_iface);
return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres;
}
static const struct {
const WCHAR *name;
HRESULT (*invoke)(func_disp_t*,DISPPARAMS*,LCID,VARIANT*,EXCEPINFO*,IServiceProvider*);
} function_props[] = {
{ L"apply", function_apply },
{ L"call", function_call }
};
static inline func_disp_t *impl_from_DispatchEx(DispatchEx *iface)
{
return CONTAINING_RECORD(iface, func_disp_t, dispex);
@ -866,9 +998,58 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR
return hres;
}
static HRESULT function_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
{
DWORD i;
for(i = 0; i < ARRAY_SIZE(function_props); i++) {
if((flags & fdexNameCaseInsensitive) ? wcsicmp(name, function_props[i].name) : wcscmp(name, function_props[i].name))
continue;
*dispid = MSHTML_DISPID_CUSTOM_MIN + i;
return S_OK;
}
return DISP_E_UNKNOWNNAME;
}
static HRESULT function_get_name(DispatchEx *dispex, DISPID id, BSTR *name)
{
DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
if(idx >= ARRAY_SIZE(function_props))
return DISP_E_MEMBERNOTFOUND;
return (*name = SysAllocString(function_props[idx].name)) ? S_OK : E_OUTOFMEMORY;
}
static HRESULT function_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
{
func_disp_t *This = impl_from_DispatchEx(dispex);
DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
if(idx >= ARRAY_SIZE(function_props))
return DISP_E_MEMBERNOTFOUND;
switch(flags) {
case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
if(!res)
return E_INVALIDARG;
/* fall through */
case DISPATCH_METHOD:
return function_props[idx].invoke(This, params, lcid, res, ei, caller);
default:
return MSHTML_E_INVALID_PROPERTY;
}
return S_OK;
}
static const dispex_static_data_vtbl_t function_dispex_vtbl = {
.destructor = function_destructor,
.value = function_value,
.get_dispid = function_get_dispid,
.get_name = function_get_name,
.invoke = function_invoke
};
static const tid_t function_iface_tids[] = {0};
@ -916,7 +1097,7 @@ static HRESULT invoke_disp_value(DispatchEx *This, IDispatch *func_disp, LCID lc
memcpy(new_dp.rgvarg+1, dp->rgvarg, dp->cArgs*sizeof(VARIANTARG));
V_VT(new_dp.rgvarg) = VT_DISPATCH;
V_DISPATCH(new_dp.rgvarg) = (IDispatch*)&This->IDispatchEx_iface;
V_DISPATCH(new_dp.rgvarg) = (IDispatch*)&This->IWineJSDispatchHost_iface;
hres = IDispatch_QueryInterface(func_disp, &IID_IDispatchEx, (void**)&dispex);
TRACE(">>>\n");
@ -957,9 +1138,9 @@ static HRESULT get_func_obj_entry(DispatchEx *This, func_info_t *func, func_obj_
if(!entry->func_obj)
return E_OUTOFMEMORY;
IDispatchEx_AddRef(&entry->func_obj->dispex.IDispatchEx_iface);
IWineJSDispatchHost_AddRef(&entry->func_obj->dispex.IWineJSDispatchHost_iface);
V_VT(&entry->val) = VT_DISPATCH;
V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface;
V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface;
}
*ret = entry;
@ -1082,7 +1263,7 @@ static HRESULT builtin_propget(DispatchEx *This, func_info_t *func, DISPPARAMS *
assert(func->get_vtbl_off);
hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface);
hres = IWineJSDispatchHost_QueryInterface(&This->IWineJSDispatchHost_iface, tid_ids[func->tid], (void**)&iface);
if(SUCCEEDED(hres)) {
switch(func->prop_vt) {
#define CASE_VT(vt,type,access) \
@ -1139,7 +1320,7 @@ static HRESULT builtin_propput(DispatchEx *This, func_info_t *func, DISPPARAMS *
v = &tmpv;
}
hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface);
hres = IWineJSDispatchHost_QueryInterface(&This->IWineJSDispatchHost_iface, tid_ids[func->tid], (void**)&iface);
if(SUCCEEDED(hres)) {
switch(func->prop_vt) {
#define CASE_VT(vt,type,access) \
@ -1161,8 +1342,8 @@ static HRESULT builtin_propput(DispatchEx *This, func_info_t *func, DISPPARAMS *
return hres;
}
static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, DISPPARAMS *dp,
VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
static HRESULT call_builtin_function(DispatchEx *This, func_info_t *func, DISPPARAMS *dp,
VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
{
VARIANT arg_buf[MAX_ARGS], *arg_ptrs[MAX_ARGS], *arg, retv, ret_ref, vhres;
unsigned i, nconv = 0;
@ -1183,7 +1364,7 @@ static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, DISP
return E_INVALIDARG;
}
hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface);
hres = IWineJSDispatchHost_QueryInterface(&This->IWineJSDispatchHost_iface, tid_ids[func->tid], (void**)&iface);
if(FAILED(hres))
return hres;
@ -1268,7 +1449,7 @@ static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, DISP
return V_ERROR(&vhres);
}
static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
EXCEPINFO *ei, IServiceProvider *caller)
{
HRESULT hres;
@ -1288,7 +1469,7 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags,
return E_NOTIMPL;
}
if((IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface != V_DISPATCH(&entry->val)) {
if((IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface != V_DISPATCH(&entry->val)) {
if(!V_DISPATCH(&entry->val)) {
FIXME("Calling null\n");
return E_FAIL;
@ -1299,7 +1480,7 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags,
}
}
hres = invoke_builtin_function(This, func, dp, res, ei, caller);
hres = call_builtin_function(This, func, dp, res, ei, caller);
break;
case DISPATCH_PROPERTYGET: {
func_obj_entry_t *entry;
@ -1365,7 +1546,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD
return hres;
if(func->func_disp_idx >= 0)
return function_invoke(This, func, flags, dp, res, ei, caller);
return invoke_builtin_function(This, func, flags, dp, res, ei, caller);
if(func->hook) {
hres = func->hook(This, flags, dp, res, ei, caller);
@ -1422,7 +1603,7 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp,
if(FAILED(hres))
return hres;
return invoke_builtin_function(dispex, func, dp, res, ei, caller);
return call_builtin_function(dispex, func, dp, res, ei, caller);
}
HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success)
@ -1464,14 +1645,14 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success)
entry = This->dynamic_data->func_disps + func->func_disp_idx;
if(V_VT(&entry->val) == VT_DISPATCH
&& V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface) {
&& V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface) {
*success = VARIANT_FALSE;
return S_OK;
}
VariantClear(&entry->val);
V_VT(&entry->val) = VT_DISPATCH;
V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface;
V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IWineJSDispatchHost_iface;
IDispatch_AddRef(V_DISPATCH(&entry->val));
*success = VARIANT_TRUE;
return S_OK;
@ -1549,14 +1730,14 @@ static BOOL ensure_real_info(DispatchEx *dispex)
return dispex->info != NULL;
}
static inline DispatchEx *impl_from_IDispatchEx(IDispatchEx *iface)
static inline DispatchEx *impl_from_IWineJSDispatchHost(IWineJSDispatchHost *iface)
{
return CONTAINING_RECORD(iface, DispatchEx, IDispatchEx_iface);
return CONTAINING_RECORD(iface, DispatchEx, IWineJSDispatchHost_iface);
}
static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatchHost *iface, REFIID riid, void **ppv)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
TRACE("%s (%p)->(%s %p)\n", This->info->desc->name, This, debugstr_mshtml_guid(riid), ppv);
@ -1567,12 +1748,14 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid,
}
if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IDispatchEx, riid))
*ppv = &This->IDispatchEx_iface;
*ppv = &This->IWineJSDispatchHost_iface;
else if(IsEqualGUID(&IID_IWineJSDispatchHost, riid))
*ppv = &This->IWineJSDispatchHost_iface;
else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) {
*ppv = &dispex_ccp;
return S_OK;
}else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
*ppv = &This->IDispatchEx_iface;
*ppv = &This->IWineJSDispatchHost_iface;
return S_OK;
}else if(IsEqualGUID(&IID_IDispatchJS, riid) ||
IsEqualGUID(&IID_UndocumentedScriptIface, riid) ||
@ -1587,24 +1770,24 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid,
}
ret:
IDispatchEx_AddRef(&This->IDispatchEx_iface);
IWineJSDispatchHost_AddRef(&This->IWineJSDispatchHost_iface);
return S_OK;
}
static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
static ULONG WINAPI DispatchEx_AddRef(IWineJSDispatchHost *iface)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
LONG ref = ccref_incr(&This->ccref, (nsISupports*)&This->IDispatchEx_iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
LONG ref = ccref_incr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface);
TRACE("%s (%p) ref=%ld\n", This->info->desc->name, This, ref);
return ref;
}
static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
static ULONG WINAPI DispatchEx_Release(IWineJSDispatchHost *iface)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
LONG ref = ccref_decr(&This->ccref, (nsISupports*)&This->IDispatchEx_iface, &dispex_ccp);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
LONG ref = ccref_decr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface, &dispex_ccp);
TRACE("%s (%p) ref=%ld\n", This->info->desc->name, This, ref);
@ -1612,17 +1795,17 @@ static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
* an extra care for objects that need an immediate clean up. See Gecko's
* NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE for details. */
if(!ref && This->info->desc->vtbl->last_release) {
ccref_incr(&This->ccref, (nsISupports*)&This->IDispatchEx_iface);
ccref_incr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface);
This->info->desc->vtbl->last_release(This);
ccref_decr(&This->ccref, (nsISupports*)&This->IDispatchEx_iface, &dispex_ccp);
ccref_decr(&This->ccref, (nsISupports*)&This->IWineJSDispatchHost_iface, &dispex_ccp);
}
return ref;
}
static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IWineJSDispatchHost *iface, UINT *pctinfo)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
TRACE("%s (%p)->(%p)\n", This->info->desc->name, This, pctinfo);
@ -1630,10 +1813,10 @@ static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pcti
return S_OK;
}
static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
static HRESULT WINAPI DispatchEx_GetTypeInfo(IWineJSDispatchHost *iface, UINT iTInfo,
LCID lcid, ITypeInfo **ppTInfo)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
HRESULT hres;
TRACE("%s (%p)->(%u %lu %p)\n", This->info->desc->name, This, iTInfo, lcid, ppTInfo);
@ -1646,11 +1829,11 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
return S_OK;
}
static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
static HRESULT WINAPI DispatchEx_GetIDsOfNames(IWineJSDispatchHost *iface, REFIID riid,
LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
HRESULT hres = S_OK;
TRACE("%s (%p)->(%s %p %u %lu %p)\n", This->info->desc->name, This, debugstr_guid(riid), rgszNames,
@ -1658,27 +1841,27 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
/* Native ignores all cNames > 1, and doesn't even fill them */
if(cNames)
hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[0], 0, rgDispId);
hres = IWineJSDispatchHost_GetDispID(&This->IWineJSDispatchHost_iface, rgszNames[0], 0, rgDispId);
return hres;
}
static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
static HRESULT WINAPI DispatchEx_Invoke(IWineJSDispatchHost *iface, DISPID dispIdMember,
REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
TRACE("%s (%p)->(%ld %s %ld %d %p %p %p %p)\n", This->info->desc->name, This, dispIdMember,
debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams,
return IWineJSDispatchHost_InvokeEx(&This->IWineJSDispatchHost_iface, dispIdMember, lcid, wFlags, pDispParams,
pVarResult, pExcepInfo, NULL);
}
static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
static HRESULT WINAPI DispatchEx_GetDispID(IWineJSDispatchHost *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
dynamic_prop_t *dprop = NULL;
HRESULT hres;
@ -1711,10 +1894,10 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW
return S_OK;
}
static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatchHost *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
HRESULT hres;
TRACE("%s (%p)->(%lx %lx %x %p %p %p %p)\n", This->info->desc->name, This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
@ -1803,9 +1986,9 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
}
}
static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR name, DWORD grfdex)
static HRESULT WINAPI DispatchEx_DeleteMemberByName(IWineJSDispatchHost *iface, BSTR name, DWORD grfdex)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
DISPID id;
HRESULT hres;
@ -1814,7 +1997,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR nam
if(dispex_compat_mode(This) < COMPAT_MODE_IE8 && !This->info->desc->vtbl->delete)
return E_NOTIMPL;
hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, name, grfdex & ~fdexNameEnsure, &id);
hres = IWineJSDispatchHost_GetDispID(&This->IWineJSDispatchHost_iface, name, grfdex & ~fdexNameEnsure, &id);
if(FAILED(hres)) {
compat_mode_t compat_mode = dispex_compat_mode(This);
TRACE("property %s not found\n", debugstr_w(name));
@ -1822,12 +2005,12 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR nam
compat_mode < COMPAT_MODE_IE9 ? hres : S_OK;
}
return IDispatchEx_DeleteMemberByDispID(&This->IDispatchEx_iface, id);
return IWineJSDispatchHost_DeleteMemberByDispID(&This->IWineJSDispatchHost_iface, id);
}
static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IWineJSDispatchHost *iface, DISPID id)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
TRACE("%s (%p)->(%lx)\n", This->info->desc->name, This, id);
@ -1855,16 +2038,16 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID
return S_OK;
}
static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
static HRESULT WINAPI DispatchEx_GetMemberProperties(IWineJSDispatchHost *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
FIXME("%s (%p)->(%lx %lx %p)\n", This->info->desc->name, This, id, grfdexFetch, pgrfdex);
return E_NOTIMPL;
}
static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
static HRESULT WINAPI DispatchEx_GetMemberName(IWineJSDispatchHost *iface, DISPID id, BSTR *pbstrName)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
func_info_t *func;
HRESULT hres;
@ -1917,9 +2100,9 @@ static HRESULT next_dynamic_id(DispatchEx *dispex, DWORD idx, DISPID *ret_id)
return S_OK;
}
static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
static HRESULT WINAPI DispatchEx_GetNextDispID(IWineJSDispatchHost *iface, DWORD grfdex, DISPID id, DISPID *pid)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
func_info_t *func;
HRESULT hres;
@ -1971,14 +2154,31 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex,
return S_FALSE;
}
static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IWineJSDispatchHost *iface, IUnknown **ppunk)
{
DispatchEx *This = impl_from_IDispatchEx(iface);
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
FIXME("%s (%p)->(%p)\n", This->info->desc->name, This, ppunk);
return E_NOTIMPL;
}
static IDispatchExVtbl DispatchExVtbl = {
static HRESULT WINAPI DispatchEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret,
EXCEPINFO *ei, IServiceProvider *caller)
{
DispatchEx *This = impl_from_IWineJSDispatchHost(iface);
func_info_t *func;
HRESULT hres;
TRACE("%s (%p)->(%lx %x %p %p %p %p)\n", This->info->desc->name, This, id, iid, dp, ret, ei, caller);
hres = get_builtin_func(This->info, id, &func);
if(FAILED(hres))
return hres;
if(func->tid != iid || func->func_disp_idx < 0)
return E_UNEXPECTED;
return call_builtin_function(This, func, dp, ret, ei, caller);
}
static IWineJSDispatchHostVtbl JSDispatchHostVtbl = {
DispatchEx_QueryInterface,
DispatchEx_AddRef,
DispatchEx_Release,
@ -1993,12 +2193,13 @@ static IDispatchExVtbl DispatchExVtbl = {
DispatchEx_GetMemberProperties,
DispatchEx_GetMemberName,
DispatchEx_GetNextDispID,
DispatchEx_GetNameSpaceParent
DispatchEx_GetNameSpaceParent,
DispatchEx_CallFunction,
};
static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb)
{
DispatchEx *This = impl_from_IDispatchEx(p);
DispatchEx *This = impl_from_IWineJSDispatchHost(p);
dynamic_prop_t *prop;
describe_cc_node(&This->ccref, This->info->desc->name, cb);
@ -2018,7 +2219,7 @@ static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTrave
for(iter = This->dynamic_data->func_disps; iter < end; iter++) {
if(!iter->func_obj)
continue;
note_cc_edge((nsISupports*)&iter->func_obj->dispex.IDispatchEx_iface, "func_obj", cb);
note_cc_edge((nsISupports*)&iter->func_obj->dispex.IWineJSDispatchHost_iface, "func_obj", cb);
traverse_variant(&iter->val, "func_val", cb);
}
}
@ -2045,7 +2246,7 @@ void dispex_props_unlink(DispatchEx *This)
if(!iter->func_obj)
continue;
iter->func_obj->obj = NULL;
IDispatchEx_Release(&iter->func_obj->dispex.IDispatchEx_iface);
IWineJSDispatchHost_Release(&iter->func_obj->dispex.IWineJSDispatchHost_iface);
VariantClear(&iter->val);
}
@ -2056,7 +2257,7 @@ void dispex_props_unlink(DispatchEx *This)
static nsresult NSAPI dispex_unlink(void *p)
{
DispatchEx *This = impl_from_IDispatchEx(p);
DispatchEx *This = impl_from_IWineJSDispatchHost(p);
if(This->info->desc->vtbl->unlink)
This->info->desc->vtbl->unlink(This);
@ -2067,7 +2268,7 @@ static nsresult NSAPI dispex_unlink(void *p)
static void NSAPI dispex_delete_cycle_collectable(void *p)
{
DispatchEx *This = impl_from_IDispatchEx(p);
DispatchEx *This = impl_from_IWineJSDispatchHost(p);
dynamic_prop_t *prop;
if(This->info->desc->vtbl->unlink)
@ -2089,7 +2290,7 @@ static void NSAPI dispex_delete_cycle_collectable(void *p)
for(iter = This->dynamic_data->func_disps; iter < This->dynamic_data->func_disps + This->info->func_disp_cnt; iter++) {
if(iter->func_obj) {
iter->func_obj->obj = NULL;
IDispatchEx_Release(&iter->func_obj->dispex.IDispatchEx_iface);
IWineJSDispatchHost_Release(&iter->func_obj->dispex.IWineJSDispatchHost_iface);
}
VariantClear(&iter->val);
}
@ -2122,7 +2323,7 @@ void init_dispatch(DispatchEx *dispex, dispex_static_data_t *data, compat_mode_t
{
assert(compat_mode < COMPAT_MODE_CNT);
dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
dispex->IWineJSDispatchHost_iface.lpVtbl = &JSDispatchHostVtbl;
dispex->dynamic_data = NULL;
ccref_init(&dispex->ccref, 1);

View File

@ -55,7 +55,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BS
return *p ? S_OK : E_OUTOFMEMORY;
}
return IDispatchEx_GetMemberName(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, p);
return IWineJSDispatchHost_GetMemberName(&This->elem->node.event_target.dispex.IWineJSDispatchHost_iface, This->dispid, p);
}
static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, VARIANT v)
@ -73,7 +73,7 @@ static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, V
memset(&ei, 0, sizeof(ei));
return IDispatchEx_InvokeEx(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
return IWineJSDispatchHost_InvokeEx(&This->elem->node.event_target.dispex.IWineJSDispatchHost_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYPUT, &dp, &ret, &ei, NULL);
}
@ -110,7 +110,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V
return S_OK;
}
hres = IDispatchEx_GetMemberName(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, &name);
hres = IWineJSDispatchHost_GetMemberName(&This->elem->node.event_target.dispex.IWineJSDispatchHost_iface, This->dispid, &name);
if(FAILED(hres))
return hres;

View File

@ -5529,8 +5529,8 @@ static HRESULT HTMLDocumentNode_location_hook(DispatchEx *dispex, WORD flags, DI
if(!This->window->base.outer_window)
return E_FAIL;
return IDispatchEx_InvokeEx(&This->window->event_target.dispex.IDispatchEx_iface, DISPID_IHTMLWINDOW2_LOCATION,
0, flags, dp, res, ei, caller);
return IWineJSDispatchHost_InvokeEx(&This->window->event_target.dispex.IWineJSDispatchHost_iface,
DISPID_IHTMLWINDOW2_LOCATION, 0, flags, dp, res, ei, caller);
}
static HRESULT HTMLDocumentNode_pre_handle_event(DispatchEx* dispex, DOMEvent *event)

View File

@ -1170,7 +1170,7 @@ static HRESULT set_elem_attr_value_by_dispid(HTMLElement *elem, DISPID dispid, V
return S_OK;
}
return IDispatchEx_InvokeEx(&elem->node.event_target.dispex.IDispatchEx_iface, dispid,
return IWineJSDispatchHost_InvokeEx(&elem->node.event_target.dispex.IWineJSDispatchHost_iface, dispid,
LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, NULL);
}
@ -1189,7 +1189,7 @@ static HRESULT WINAPI HTMLElement_setAttribute(IHTMLElement *iface, BSTR strAttr
TRACE("(%p)->(%s %s %08lx)\n", This, debugstr_w(strAttributeName), debugstr_variant(&AttributeValue), lFlags);
if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) {
hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, translate_attr_name(strAttributeName, compat_mode),
hres = IWineJSDispatchHost_GetDispID(&This->node.event_target.dispex.IWineJSDispatchHost_iface, translate_attr_name(strAttributeName, compat_mode),
(lFlags&ATTRFLAG_CASESENSITIVE ? fdexNameCaseSensitive : fdexNameCaseInsensitive) | fdexNameEnsure, &dispid);
if(FAILED(hres))
return hres;
@ -1241,7 +1241,7 @@ HRESULT get_elem_attr_value_by_dispid(HTMLElement *elem, DISPID dispid, VARIANT
DISPPARAMS dispParams = {NULL, NULL, 0, 0};
EXCEPINFO excep;
return IDispatchEx_InvokeEx(&elem->node.event_target.dispex.IDispatchEx_iface, dispid, LOCALE_SYSTEM_DEFAULT,
return IWineJSDispatchHost_InvokeEx(&elem->node.event_target.dispex.IWineJSDispatchHost_iface, dispid, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET, &dispParams, ret, &excep, NULL);
}
@ -1288,7 +1288,7 @@ static HRESULT WINAPI HTMLElement_getAttribute(IHTMLElement *iface, BSTR strAttr
FIXME("Unsupported flags %lx\n", lFlags);
if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) {
hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, translate_attr_name(strAttributeName, compat_mode),
hres = IWineJSDispatchHost_GetDispID(&This->node.event_target.dispex.IWineJSDispatchHost_iface, translate_attr_name(strAttributeName, compat_mode),
lFlags&ATTRFLAG_CASESENSITIVE ? fdexNameCaseSensitive : fdexNameCaseInsensitive, &dispid);
if(FAILED(hres)) {
V_VT(AttributeValue) = VT_NULL;
@ -1336,7 +1336,7 @@ static HRESULT WINAPI HTMLElement_removeAttribute(IHTMLElement *iface, BSTR strA
TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(strAttributeName), lFlags, pfSuccess);
if(compat_mode < COMPAT_MODE_IE9 || !This->dom_element) {
hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, translate_attr_name(strAttributeName, compat_mode),
hres = IWineJSDispatchHost_GetDispID(&This->node.event_target.dispex.IWineJSDispatchHost_iface, translate_attr_name(strAttributeName, compat_mode),
lFlags&ATTRFLAG_CASESENSITIVE ? fdexNameCaseSensitive : fdexNameCaseInsensitive, &id);
if(hres == DISP_E_UNKNOWNNAME) {
*pfSuccess = VARIANT_FALSE;
@ -2483,7 +2483,7 @@ static HRESULT WINAPI HTMLElement_toString(IHTMLElement *iface, BSTR *String)
if(!String)
return E_INVALIDARG;
hres = IDispatchEx_InvokeEx(&This->node.event_target.dispex.IDispatchEx_iface, DISPID_VALUE,
hres = IWineJSDispatchHost_InvokeEx(&This->node.event_target.dispex.IWineJSDispatchHost_iface, DISPID_VALUE,
LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, NULL, &var, NULL, NULL);
if(SUCCEEDED(hres)) {
assert(V_VT(&var) == VT_BSTR);
@ -4429,7 +4429,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD
return E_INVALIDARG;
}
hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface,
hres = IWineJSDispatchHost_GetDispID(&This->node.event_target.dispex.IWineJSDispatchHost_iface,
attr->name, fdexNameCaseInsensitive|fdexNameEnsure, &dispid);
if(FAILED(hres))
return hres;
@ -6399,7 +6399,7 @@ HRESULT HTMLElement_populate_props(DispatchEx *dispex)
continue;
}
hres = IDispatchEx_GetDispID(&dispex->IDispatchEx_iface, name, fdexNameCaseInsensitive, &id);
hres = IWineJSDispatchHost_GetDispID(&dispex->IWineJSDispatchHost_iface, name, fdexNameCaseInsensitive, &id);
if(hres != DISP_E_UNKNOWNNAME) {
nsIDOMAttr_Release(attr);
SysFreeString(name);
@ -7544,7 +7544,7 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters
static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, DISPID *dispid)
{
IDispatchEx *dispex = &This->elem->node.event_target.dispex.IDispatchEx_iface;
IWineJSDispatchHost *dispex = &This->elem->node.event_target.dispex.IWineJSDispatchHost_iface;
DISPID id = start;
LONG len = -1;
HRESULT hres;
@ -7552,7 +7552,7 @@ static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LO
FIXME("filter non-enumerable attributes out\n");
while(1) {
hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, id, &id);
hres = IWineJSDispatchHost_GetNextDispID(dispex, fdexEnumAll, id, &id);
if(FAILED(hres))
return hres;
else if(hres == S_FALSE)
@ -7593,7 +7593,7 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BST
}
}
hres = IDispatchEx_GetDispID(&This->elem->node.event_target.dispex.IDispatchEx_iface,
hres = IWineJSDispatchHost_GetDispID(&This->elem->node.event_target.dispex.IWineJSDispatchHost_iface,
name, fdexNameCaseInsensitive, id);
return hres;
}

View File

@ -315,7 +315,7 @@ static BOOL is_elem_name(HTMLElement *elem, LPCWSTR name)
static HRESULT get_item_idx(HTMLElementCollection *This, UINT idx, IDispatch **ret)
{
if(idx < This->len) {
*ret = (IDispatch*)&This->elems[idx]->node.event_target.dispex.IDispatchEx_iface;
*ret = (IDispatch*)&This->elems[idx]->node.event_target.dispex.IWineJSDispatchHost_iface;
IDispatch_AddRef(*ret);
}

View File

@ -2056,7 +2056,7 @@ static HRESULT WINAPI DOMEvent_get_srcElement(IDOMEvent *iface, IHTMLElement **p
TRACE("(%p)->(%p)\n", This, p);
if(This->target)
IDispatchEx_QueryInterface(&This->target->dispex.IDispatchEx_iface, &IID_IHTMLElement, (void**)p);
IWineJSDispatchHost_QueryInterface(&This->target->dispex.IWineJSDispatchHost_iface, &IID_IHTMLElement, (void**)p);
else
*p = NULL;
return S_OK;
@ -4167,7 +4167,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
skip_onevent_listener = TRUE;
V_VT(&arg) = VT_DISPATCH;
V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IWineJSDispatchHost_iface;
V_VT(&v) = VT_EMPTY;
if(vtbl->get_dispatch_this)
V_DISPATCH(&arg) = vtbl->get_dispatch_this(&event_target->dispex);
@ -4249,7 +4249,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp
DISPPARAMS dp = {args, &named_arg, 2, 1};
V_VT(args) = VT_DISPATCH;
V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IWineJSDispatchHost_iface;
if(vtbl->get_dispatch_this)
V_DISPATCH(args) = vtbl->get_dispatch_this(&event_target->dispex);
IDispatch_AddRef(V_DISPATCH(args));

View File

@ -893,7 +893,7 @@ static HRESULT HTMLFrameElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid,
return E_FAIL;
}
return IDispatchEx_InvokeEx(&This->framebase.content_window->IDispatchEx_iface, id, lcid,
return IWineJSDispatchHost_InvokeEx(&This->framebase.content_window->IWineJSDispatchHost_iface, id, lcid,
flags, params, res, ei, caller);
}
@ -1330,7 +1330,7 @@ static HRESULT HTMLIFrame_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD
return E_FAIL;
}
return IDispatchEx_InvokeEx(&This->framebase.content_window->IDispatchEx_iface, id, lcid,
return IWineJSDispatchHost_InvokeEx(&This->framebase.content_window->IWineJSDispatchHost_iface, id, lcid,
flags, params, res, ei, caller);
}

View File

@ -2917,7 +2917,7 @@ static HRESULT WINAPI HTMLStyle_removeAttribute(IHTMLStyle *iface, BSTR strAttri
DISPID dispid;
unsigned i;
hres = IDispatchEx_GetDispID(&This->css_style.dispex.IDispatchEx_iface, strAttributeName,
hres = IWineJSDispatchHost_GetDispID(&This->css_style.dispex.IWineJSDispatchHost_iface, strAttributeName,
(lFlags&1) ? fdexNameCaseSensitive : fdexNameCaseInsensitive, &dispid);
if(hres != S_OK) {
*pfSuccess = VARIANT_FALSE;

View File

@ -211,8 +211,8 @@ static HRESULT WINAPI outer_window_QueryInterface(IHTMLWindow2 *iface, REFIID ri
}else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
*ppv = &This->base.IHTMLWindow2_iface;
return S_OK;
}else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
*ppv = &This->IDispatchEx_iface;
}else if(IsEqualGUID(&IID_IDispatchEx, riid) || IsEqualGUID(&IID_IWineJSDispatchHost, riid)) {
*ppv = &This->IWineJSDispatchHost_iface;
}else if(IsEqualGUID(&IID_IEventTarget, riid)) {
if(!This->base.inner_window->doc || This->base.inner_window->doc->document_mode < COMPAT_MODE_IE9)
return E_NOINTERFACE;
@ -3277,34 +3277,34 @@ static const IWineHTMLWindowCompatPrivateVtbl WineHTMLWindowCompatPrivateVtbl =
window_compat_private_get_performance,
};
static inline HTMLOuterWindow *impl_from_IDispatchEx(IDispatchEx *iface)
static inline HTMLOuterWindow *impl_from_IWineJSDispatchHost(IWineJSDispatchHost *iface)
{
return CONTAINING_RECORD(iface, HTMLOuterWindow, IDispatchEx_iface);
return CONTAINING_RECORD(iface, HTMLOuterWindow, IWineJSDispatchHost_iface);
}
static HRESULT WINAPI WindowDispEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
static HRESULT WINAPI WindowDispEx_QueryInterface(IWineJSDispatchHost *iface, REFIID riid, void **ppv)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IHTMLWindow2_QueryInterface(&This->base.IHTMLWindow2_iface, riid, ppv);
}
static ULONG WINAPI WindowDispEx_AddRef(IDispatchEx *iface)
static ULONG WINAPI WindowDispEx_AddRef(IWineJSDispatchHost *iface)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IHTMLWindow2_AddRef(&This->base.IHTMLWindow2_iface);
}
static ULONG WINAPI WindowDispEx_Release(IDispatchEx *iface)
static ULONG WINAPI WindowDispEx_Release(IWineJSDispatchHost *iface)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IHTMLWindow2_Release(&This->base.IHTMLWindow2_iface);
}
DISPEX_IDISPATCH_NOUNK_IMPL(WindowDispEx, IDispatchEx,
impl_from_IDispatchEx(iface)->base.inner_window->event_target.dispex)
DISPEX_IDISPATCH_NOUNK_IMPL(WindowDispEx, IWineJSDispatchHost,
impl_from_IWineJSDispatchHost(iface)->base.inner_window->event_target.dispex)
static global_prop_t *alloc_global_prop(HTMLInnerWindow *This, global_prop_type_t type, BSTR name)
{
@ -3369,69 +3369,70 @@ HRESULT search_window_props(HTMLInnerWindow *This, BSTR bstrName, DWORD grfdex,
return DISP_E_UNKNOWNNAME;
}
static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
static HRESULT WINAPI WindowDispEx_GetDispID(IWineJSDispatchHost *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IDispatchEx_GetDispID(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, bstrName, grfdex, pid);
return IWineJSDispatchHost_GetDispID(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, bstrName, grfdex, pid);
}
static HRESULT WINAPI WindowDispEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
static HRESULT WINAPI WindowDispEx_InvokeEx(IWineJSDispatchHost *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
return IDispatchEx_InvokeEx(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IWineJSDispatchHost_InvokeEx(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id, lcid, wFlags,
pdp, pvarRes, pei, pspCaller);
}
static HRESULT WINAPI WindowDispEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
static HRESULT WINAPI WindowDispEx_DeleteMemberByName(IWineJSDispatchHost *iface, BSTR bstrName, DWORD grfdex)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex);
return IDispatchEx_DeleteMemberByName(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, bstrName, grfdex);
return IWineJSDispatchHost_DeleteMemberByName(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, bstrName, grfdex);
}
static HRESULT WINAPI WindowDispEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
static HRESULT WINAPI WindowDispEx_DeleteMemberByDispID(IWineJSDispatchHost *iface, DISPID id)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
TRACE("(%p)->(%lx)\n", This, id);
return IDispatchEx_DeleteMemberByDispID(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, id);
return IWineJSDispatchHost_DeleteMemberByDispID(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id);
}
static HRESULT WINAPI WindowDispEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
static HRESULT WINAPI WindowDispEx_GetMemberProperties(IWineJSDispatchHost *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
TRACE("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex);
return IDispatchEx_GetMemberProperties(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, id, grfdexFetch,
return IWineJSDispatchHost_GetMemberProperties(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id, grfdexFetch,
pgrfdex);
}
static HRESULT WINAPI WindowDispEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
static HRESULT WINAPI WindowDispEx_GetMemberName(IWineJSDispatchHost *iface, DISPID id, BSTR *pbstrName)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
TRACE("(%p)->(%lx %p)\n", This, id, pbstrName);
return IDispatchEx_GetMemberName(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, id, pbstrName);
return IWineJSDispatchHost_GetMemberName(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id, pbstrName);
}
static HRESULT WINAPI WindowDispEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
static HRESULT WINAPI WindowDispEx_GetNextDispID(IWineJSDispatchHost *iface, DWORD grfdex, DISPID id, DISPID *pid)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
TRACE("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid);
return IDispatchEx_GetNextDispID(&This->base.inner_window->event_target.dispex.IDispatchEx_iface, grfdex, id, pid);
return IWineJSDispatchHost_GetNextDispID(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, grfdex, id, pid);
}
static HRESULT WINAPI WindowDispEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
static HRESULT WINAPI WindowDispEx_GetNameSpaceParent(IWineJSDispatchHost *iface, IUnknown **ppunk)
{
HTMLOuterWindow *This = impl_from_IDispatchEx(iface);
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
TRACE("(%p)->(%p)\n", This, ppunk);
@ -3439,7 +3440,16 @@ static HRESULT WINAPI WindowDispEx_GetNameSpaceParent(IDispatchEx *iface, IUnkno
return S_OK;
}
static const IDispatchExVtbl WindowDispExVtbl = {
static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret,
EXCEPINFO *ei, IServiceProvider *caller)
{
HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface);
return IWineJSDispatchHost_CallFunction(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface,
id, iid, dp, ret, ei, caller);
}
static const IWineJSDispatchHostVtbl WindowDispExVtbl = {
WindowDispEx_QueryInterface,
WindowDispEx_AddRef,
WindowDispEx_Release,
@ -3454,7 +3464,8 @@ static const IDispatchExVtbl WindowDispExVtbl = {
WindowDispEx_GetMemberProperties,
WindowDispEx_GetMemberName,
WindowDispEx_GetNextDispID,
WindowDispEx_GetNameSpaceParent
WindowDispEx_GetNameSpaceParent,
WindowDispEx_CallFunction,
};
static inline HTMLOuterWindow *impl_from_IEventTarget(IEventTarget *iface)
@ -3810,7 +3821,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD
prop->type = GLOBAL_DISPEXVAR;
prop->id = dispex_id;
return IDispatchEx_InvokeEx(&This->event_target.dispex.IDispatchEx_iface, dispex_id, 0, flags, params, res, ei, caller);
return IWineJSDispatchHost_InvokeEx(&This->event_target.dispex.IWineJSDispatchHost_iface, dispex_id, 0, flags, params, res, ei, caller);
}
default:
FIXME("Not supported flags: %x\n", flags);
@ -3838,7 +3849,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD
return E_NOTIMPL;
}
case GLOBAL_DISPEXVAR:
return IDispatchEx_InvokeEx(&This->event_target.dispex.IDispatchEx_iface, prop->id, 0, flags, params, res, ei, caller);
return IWineJSDispatchHost_InvokeEx(&This->event_target.dispex.IWineJSDispatchHost_iface, prop->id, 0, flags, params, res, ei, caller);
default:
ERR("invalid type %d\n", prop->type);
hres = DISP_E_MEMBERNOTFOUND;
@ -3901,7 +3912,7 @@ static HRESULT IHTMLWindow2_location_hook(DispatchEx *dispex, WORD flags, DISPPA
if(FAILED(hres))
return hres;
hres = IDispatchEx_InvokeEx(&location->dispex.IDispatchEx_iface, DISPID_VALUE, 0, flags, dp, res, ei, caller);
hres = IWineJSDispatchHost_InvokeEx(&location->dispex.IWineJSDispatchHost_iface, DISPID_VALUE, 0, flags, dp, res, ei, caller);
IHTMLLocation_Release(&location->IHTMLLocation_iface);
return hres;
}
@ -4204,7 +4215,7 @@ HRESULT create_outer_window(GeckoBrowser *browser, mozIDOMWindowProxy *mozwindow
if(!window)
return E_OUTOFMEMORY;
window->base.IHTMLWindow2_iface.lpVtbl = &outer_window_HTMLWindow2Vtbl;
window->IDispatchEx_iface.lpVtbl = &WindowDispExVtbl;
window->IWineJSDispatchHost_iface.lpVtbl = &WindowDispExVtbl;
window->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
window->base.outer_window = window;

View File

@ -413,7 +413,7 @@ typedef struct {
} dispex_hook_t;
struct DispatchEx {
IDispatchEx IDispatchEx_iface;
IWineJSDispatchHost IWineJSDispatchHost_iface;
nsCycleCollectingAutoRefCnt ccref;
@ -424,38 +424,38 @@ struct DispatchEx {
#define DISPEX_IDISPATCH_NOUNK_IMPL(prefix, iface_name, dispex) \
static HRESULT WINAPI prefix##_GetTypeInfoCount(iface_name *iface, UINT *count) \
{ \
return IDispatchEx_GetTypeInfoCount(&(dispex).IDispatchEx_iface, count); \
return IWineJSDispatchHost_GetTypeInfoCount(&(dispex).IWineJSDispatchHost_iface, count); \
} \
static HRESULT WINAPI prefix##_GetTypeInfo(iface_name *iface, \
UINT index, LCID lcid, ITypeInfo **ret) \
{ \
return IDispatchEx_GetTypeInfo(&(dispex).IDispatchEx_iface, index, lcid, ret); \
return IWineJSDispatchHost_GetTypeInfo(&(dispex).IWineJSDispatchHost_iface, index, lcid, ret); \
} \
static HRESULT WINAPI prefix##_GetIDsOfNames(iface_name *iface, REFIID riid, \
LPOLESTR *names, UINT count, LCID lcid, DISPID *dispid) \
{ \
return IDispatchEx_GetIDsOfNames(&(dispex).IDispatchEx_iface, \
return IWineJSDispatchHost_GetIDsOfNames(&(dispex).IWineJSDispatchHost_iface, \
riid, names, count, lcid, dispid); \
} \
static HRESULT WINAPI prefix##_Invoke(iface_name *iface, DISPID dispid, REFIID riid, \
LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, UINT *err) \
{ \
return IDispatchEx_Invoke(&(dispex).IDispatchEx_iface, dispid, \
return IWineJSDispatchHost_Invoke(&(dispex).IWineJSDispatchHost_iface, dispid, \
riid, lcid, flags, params, res, ei, err); \
}
#define DISPEX_IDISPATCH_IMPL(prefix, iface_name, dispex) \
static HRESULT WINAPI prefix##_QueryInterface(iface_name *iface, REFIID riid, void **ppv) \
{ \
return IDispatchEx_QueryInterface(&(dispex).IDispatchEx_iface, riid, ppv); \
return IWineJSDispatchHost_QueryInterface(&(dispex).IWineJSDispatchHost_iface, riid, ppv); \
} \
static ULONG WINAPI prefix##_AddRef(iface_name *iface) \
{ \
return IDispatchEx_AddRef(&(dispex).IDispatchEx_iface); \
return IWineJSDispatchHost_AddRef(&(dispex).IWineJSDispatchHost_iface); \
} \
static ULONG WINAPI prefix##_Release(iface_name *iface) \
{ \
return IDispatchEx_Release(&(dispex).IDispatchEx_iface); \
return IWineJSDispatchHost_Release(&(dispex).IWineJSDispatchHost_iface); \
} \
DISPEX_IDISPATCH_NOUNK_IMPL(prefix, iface_name, dispex)
@ -594,7 +594,7 @@ struct HTMLWindow {
struct HTMLOuterWindow {
HTMLWindow base;
IEventTarget IEventTarget_iface;
IDispatchEx IDispatchEx_iface;
IWineJSDispatchHost IWineJSDispatchHost_iface;
nsCycleCollectingAutoRefCnt ccref;
LONG task_magic;

View File

@ -258,3 +258,13 @@ interface IWineXMLHttpRequestPrivate : IDispatch
}
} /* library MSHTML_private */
[
object,
uuid(d359f2fe-5531-741b-a41a-5cf92edc971b),
local
]
interface IWineJSDispatchHost : IDispatchEx
{
HRESULT CallFunction(DISPID id, UINT32 iid, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller);
}

View File

@ -1301,6 +1301,6 @@ HRESULT create_mutation_observer_ctor(compat_mode_t compat_mode, IDispatch **ret
init_dispatch(&obj->dispex, &mutation_observer_ctor_dispex, compat_mode);
*ret = (IDispatch *)&obj->dispex.IDispatchEx_iface;
*ret = (IDispatch *)&obj->dispex.IWineJSDispatchHost_iface;
return S_OK;
}

View File

@ -3542,7 +3542,7 @@ static HRESULT WINAPI DocObjDispatchEx_GetDispID(IDispatchEx *iface, BSTR name,
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_GetDispID(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, name, grfdex, pid);
return IWineJSDispatchHost_GetDispID(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, name, grfdex, pid);
}
static HRESULT WINAPI DocObjDispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
@ -3550,29 +3550,29 @@ static HRESULT WINAPI DocObjDispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, L
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_InvokeEx(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, id, lcid,
wFlags, pdp, pvarRes, pei, pspCaller);
return IWineJSDispatchHost_InvokeEx(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, id, lcid,
wFlags, pdp, pvarRes, pei, pspCaller);
}
static HRESULT WINAPI DocObjDispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_DeleteMemberByName(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, bstrName, grfdex);
return IWineJSDispatchHost_DeleteMemberByName(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, bstrName, grfdex);
}
static HRESULT WINAPI DocObjDispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_DeleteMemberByDispID(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, id);
return IWineJSDispatchHost_DeleteMemberByDispID(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, id);
}
static HRESULT WINAPI DocObjDispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_GetMemberProperties(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, id, grfdexFetch,
return IWineJSDispatchHost_GetMemberProperties(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, id, grfdexFetch,
pgrfdex);
}
@ -3580,21 +3580,21 @@ static HRESULT WINAPI DocObjDispatchEx_GetMemberName(IDispatchEx *iface, DISPID
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_GetMemberName(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, id, name);
return IWineJSDispatchHost_GetMemberName(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, id, name);
}
static HRESULT WINAPI DocObjDispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_GetNextDispID(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, grfdex, id, pid);
return IWineJSDispatchHost_GetNextDispID(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, grfdex, id, pid);
}
static HRESULT WINAPI DocObjDispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
{
HTMLDocumentObj *This = impl_from_IDispatchEx(iface);
return IDispatchEx_GetNameSpaceParent(&This->doc_node->node.event_target.dispex.IDispatchEx_iface, ppunk);
return IWineJSDispatchHost_GetNameSpaceParent(&This->doc_node->node.event_target.dispex.IWineJSDispatchHost_iface, ppunk);
}
static const IDispatchExVtbl DocObjDispatchExVtbl = {

View File

@ -2313,7 +2313,7 @@ static nsresult NSAPI media_query_list_callback_HandleChange(nsIDOMMediaQueryLis
DISPPARAMS dp = { args, NULL, 1, 0 };
V_VT(args) = VT_DISPATCH;
V_DISPATCH(args) = (IDispatch*)&media_query_list->dispex.IDispatchEx_iface;
V_DISPATCH(args) = (IDispatch*)&media_query_list->dispex.IWineJSDispatchHost_iface;
V_VT(&v) = VT_EMPTY;
TRACE("%p >>>\n", media_query_list);

View File

@ -1573,7 +1573,7 @@ static EventTarget *find_event_target(HTMLDocumentNode *doc, HTMLScriptElement *
}else if(!wcscmp(target_id, L"window")) {
if(doc->window) {
event_target = &doc->window->event_target;
IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
IWineJSDispatchHost_AddRef(&event_target->dispex.IWineJSDispatchHost_iface);
}
}else {
HTMLElement *target_elem;
@ -1731,14 +1731,14 @@ void bind_event_scripts(HTMLDocumentNode *doc)
if(event_disp) {
event_target = find_event_target(doc, script_elem);
if(event_target) {
hres = IDispatchEx_QueryInterface(&event_target->dispex.IDispatchEx_iface, &IID_HTMLPluginContainer,
hres = IWineJSDispatchHost_QueryInterface(&event_target->dispex.IWineJSDispatchHost_iface, &IID_HTMLPluginContainer,
(void**)&plugin_container);
if(SUCCEEDED(hres))
bind_activex_event(doc, plugin_container, event, event_disp);
else
bind_target_event(doc, event_target, event, event_disp);
IDispatchEx_Release(&event_target->dispex.IDispatchEx_iface);
IWineJSDispatchHost_Release(&event_target->dispex.IWineJSDispatchHost_iface);
if(plugin_container)
node_release(&plugin_container->element.node);
}

View File

@ -352,6 +352,73 @@ sync_test("builtin_toString", function() {
}
});
sync_test("builtin_obj", function() {
var v = document.documentMode;
var f = document.createElement;
var e;
if(v < 9) {
ok(!(window instanceof Object), "window instance of Object");
ok(!(document instanceof Object), "document instance of Object");
ok(!("arguments" in f), "arguments in f");
ok(!("length" in f), "length in f");
e = 0;
try {
f.toString();
}catch(ex) {
e = ex.number;
}
ok(e === 0xa01b6 - 0x80000000, "[f.toString] e = " + e);
try {
window.toString.call(null);
ok(false, "expected exception calling window.toString with null context");
}catch(ex) {}
}
e = 0;
try {
f.call(Object, "div");
}catch(ex) {
e = ex.number;
}
todo_wine_if(v >= 9).
ok(e === (v < 9 ? 0xa0005 : 0x0ffff) - 0x80000000, "[f.call(Object, 'div')] e = " + e);
e = 0;
try {
f.call(null, "div");
}catch(ex) {
e = ex.number;
}
todo_wine_if(v >= 9).
ok(e === (v < 9 ? 0xa0005 : 0x0ffff) - 0x80000000, "[f.call(null, 'div')] e = " + e);
var elem1 = f.call(document, "div");
var elem2 = f.call(document, "br");
document.body.appendChild(elem1);
document.body.appendChild(elem2);
elem1.onclick = function() { ok(false, "unexpected elem1.onclick"); };
var clicked = false;
elem2.onclick = function() { clicked = true; };
elem1.click.call(elem2);
ok(clicked === true, "elem2.onclick not called");
elem1 = f.apply(document, ["div"]);
elem2 = f.apply(document, ["br"]);
document.body.appendChild(elem1);
document.body.appendChild(elem2);
elem1.onclick = function() { ok(false, "unexpected elem1.onclick"); };
clicked = false;
elem2.onclick = function() { clicked = true; };
elem1.click.apply(elem2);
ok(clicked === true, "elem2.onclick not called");
try {
elem1.click.apply(elem2, { length: -1 });
ok(false, "exception expected");
}catch(ex) {}
});
sync_test("elem_props", function() {
var elem = document.documentElement;

View File

@ -249,7 +249,7 @@ NTSTATUS WINAPI RtlWow64GetThreadSelectorEntry( HANDLE handle, THREAD_DESCRIPTOR
{
/* hardcoded values */
#ifdef __arm64ec__
context.SegCs = 0x33;
context.SegCs = 0x23;
context.SegSs = 0x2b;
context.SegFs = 0x53;
#elif defined(__x86_64__)

View File

@ -341,20 +341,19 @@ static NTSTATUS RTL_ReportRegistryValue(PKEY_VALUE_FULL_INFORMATION pInfo,
pInfo->DataLength);
else
{
if (bin[0] <= sizeof(ULONG))
if (bin[0] < 0)
{
memcpy(&bin[1], ((CHAR*)pInfo) + pInfo->DataOffset,
min(-bin[0], pInfo->DataLength));
if (pInfo->DataLength <= -bin[0])
memcpy(bin, (char*)pInfo + pInfo->DataOffset, pInfo->DataLength);
}
else
else if (pInfo->DataLength <= bin[0])
{
len = min(bin[0], pInfo->DataLength);
bin[1] = len;
bin[2] = pInfo->Type;
memcpy(&bin[3], ((CHAR*)pInfo) + pInfo->DataOffset, len);
bin[0] = len;
bin[1] = pInfo->Type;
memcpy(bin + 2, (char*)pInfo + pInfo->DataOffset, len);
}
}
break;
}
break;
}
}
else if (pQuery->QueryRoutine)

File diff suppressed because it is too large Load Diff

View File

@ -2553,6 +2553,7 @@ struct query_reg_values_test
ULONG expected_type;
const WCHAR *expected_data;
ULONG expected_data_size;
ULONG size_limit;
};
static unsigned int query_routine_calls;
@ -2625,6 +2626,23 @@ static NTSTATUS WINAPI query_routine(const WCHAR *value_name, ULONG value_type,
static UNICODE_STRING query_reg_values_direct_str;
static ULONG query_reg_values_direct_int;
static union
{
ULONG size;
char data[16];
}
query_reg_values_direct_sized;
static struct
{
ULONG size;
ULONG type;
char data[16];
}
query_reg_values_direct_typed;
static struct query_reg_values_test query_reg_values_tests[] =
{
/* Empty table */
@ -2644,7 +2662,7 @@ static struct query_reg_values_test query_reg_values_tests[] =
/* The query routine is called for every value in current key */
{
{{ query_routine }},
STATUS_SUCCESS, 4, SKIP_NAME_CHECK | SKIP_DATA_CHECK
STATUS_SUCCESS, 6, SKIP_NAME_CHECK | SKIP_DATA_CHECK
},
/* NOVALUE is ignored when the name is not null */
{
@ -2678,6 +2696,26 @@ static struct query_reg_values_test query_reg_values_tests[] =
&query_reg_values_direct_str }},
STATUS_SUCCESS, 0, 0, REG_SZ, L"%SYSTEMDRIVE%"
},
{
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife32", &query_reg_values_direct_int }},
STATUS_SUCCESS, 0, 0, REG_DWORD, (WCHAR*)42
},
{
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife64", &query_reg_values_direct_sized }},
STATUS_SUCCESS, 0, 0, REG_NONE, L"\x2a\0\0", sizeof(UINT64)
},
{
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife64", &query_reg_values_direct_sized }},
STATUS_SUCCESS, 0, 0, REG_NONE, L"\xff", 1, 1
},
{
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife64", &query_reg_values_direct_typed }},
STATUS_SUCCESS, 0, 0, REG_QWORD, L"\x2a\0\0", sizeof(UINT64)
},
{
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"MeaningOfLife64", &query_reg_values_direct_typed }},
STATUS_SUCCESS, 0, 0, 0x23, L"\x23", 1, 1
},
/* DIRECT on a multi-string crashes on Windows without NOEXPAND */
/* {
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"CapitalsOfEurope", &query_reg_values_direct_str }},
@ -2783,8 +2821,8 @@ static struct query_reg_values_test query_reg_values_tests[] =
/* DIRECT additionally requires the default value to be a string */
{
{{ NULL, RTL_QUERY_REGISTRY_DIRECT, (WCHAR*)L"I don't exist",
&query_reg_values_direct_str, REG_DWORD, (WCHAR*)0xdeadbeef }},
STATUS_SUCCESS, 0, 0, REG_NONE, NULL, -1
&query_reg_values_direct_int, REG_DWORD, (WCHAR*)0xdeadbeef }},
STATUS_SUCCESS, 0
},
/* REQUIRED fails if the value doesn't exist and there is no default */
{
@ -2821,8 +2859,16 @@ static void test_RtlQueryRegistryValues(void)
L"Brussels\0Paris\0%PATH%", sizeof(L"Brussels\0Paris\0%PATH%"));
ok(status == ERROR_SUCCESS, "Failed to create registry value CapitalsOfEurope: %lu\n", status);
status = RegSetKeyValueW(HKEY_CURRENT_USER, L"WineTest", L"MeaningOfLife32", REG_DWORD,
L"\x2a", sizeof(DWORD));
ok(status == ERROR_SUCCESS, "Failed to create registry value MeaningOfLife32: %lu\n", status);
status = RegSetKeyValueW(HKEY_CURRENT_USER, L"WineTest", L"MeaningOfLife64", REG_QWORD,
L"\x2a\0\0", sizeof(UINT64));
ok(status == ERROR_SUCCESS, "Failed to create registry value MeaningOfLife64: %lu\n", status);
status = RegSetKeyValueW(HKEY_CURRENT_USER, L"WineTest\\subkey", L"Color", REG_SZ,
(void*)L"Yellow", sizeof(L"Yellow"));
L"Yellow", sizeof(L"Yellow"));
ok(status == ERROR_SUCCESS, "Failed to create registry value Color: %lu\n", status);
query_reg_values_direct_str.MaximumLength = 32 * sizeof(WCHAR);
@ -2846,10 +2892,22 @@ static void test_RtlQueryRegistryValues(void)
}
query_routine_calls = 0;
query_reg_values_direct_str.Length = query_reg_values_direct_str.MaximumLength - sizeof(WCHAR);
memset(query_reg_values_direct_str.Buffer, 0x23, query_reg_values_direct_str.Length);
query_reg_values_direct_str.Buffer[query_reg_values_direct_str.Length] = 0;
query_reg_values_direct_int = 1;
memset(query_reg_values_direct_sized.data, 0x23, sizeof(query_reg_values_direct_sized));
query_reg_values_direct_sized.size = test->size_limit ? -test->size_limit
: -(LONG)sizeof(query_reg_values_direct_sized);
query_reg_values_direct_typed.size = test->size_limit ? test->size_limit
: sizeof(query_reg_values_direct_typed.data);
query_reg_values_direct_typed.type = 0x23;
memset(query_reg_values_direct_typed.data, 0x23, sizeof(query_reg_values_direct_typed.data));
status = pRtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, winetestpath.Buffer, test->query_table, test, NULL);
todo_wine_if(test->flags & WINE_TODO_RET)
@ -2877,22 +2935,54 @@ static void test_RtlQueryRegistryValues(void)
expected_size = test->expected_data_size;
}
if (!expected_size && expected_data && (expected_type == REG_SZ || expected_type == REG_EXPAND_SZ))
expected_size = (wcslen(expected_data) + 1) * sizeof(WCHAR);
else if (expected_size == -1)
expected_size = query_reg_values_direct_str.MaximumLength;
todo_wine_if(test->flags & WINE_TODO_SIZE)
ok(query_reg_values_direct_str.Length + sizeof(WCHAR) == expected_size,
"Expected size %lu, got %Iu\n", expected_size,
query_reg_values_direct_str.Length + sizeof(WCHAR));
if (expected_data)
if (query->EntryContext == &query_reg_values_direct_str)
{
todo_wine_if(test->flags & WINE_TODO_DATA)
ok(!memcmp(query_reg_values_direct_str.Buffer, expected_data, expected_size),
"Expected data %s, got %s\n", debugstr_w(expected_data),
debugstr_w(query_reg_values_direct_str.Buffer));
if (!expected_size && expected_data)
expected_size = (wcslen(expected_data) + 1) * sizeof(WCHAR);
else if (expected_size == -1)
expected_size = query_reg_values_direct_str.MaximumLength;
todo_wine_if(test->flags & WINE_TODO_SIZE)
ok(query_reg_values_direct_str.Length + sizeof(WCHAR) == expected_size,
"Expected size %lu, got %Iu\n", expected_size,
query_reg_values_direct_str.Length + sizeof(WCHAR));
if (expected_data)
{
todo_wine_if(test->flags & WINE_TODO_DATA)
ok(!memcmp(query_reg_values_direct_str.Buffer, expected_data, expected_size),
"Expected data %s, got %s\n", debugstr_w(expected_data),
debugstr_w(query_reg_values_direct_str.Buffer));
}
}
else if (query->EntryContext == &query_reg_values_direct_int)
{
if (expected_data)
{
ok(!memcmp(&query_reg_values_direct_int, &expected_data, expected_size),
"Data does not match\n");
}
else
{
- ok(query_reg_values_direct_int == 1,
"Expected data to not change, got %lu\n", query_reg_values_direct_int);
}
}
else if (query->EntryContext == &query_reg_values_direct_sized)
{
ok(!memcmp(query_reg_values_direct_sized.data, expected_data, expected_size),
"Data does not match\n");
}
else if (query->EntryContext == &query_reg_values_direct_typed)
{
ok(query_reg_values_direct_typed.size == expected_size,
"Expected size %lu, got %lu\n", expected_size, query_reg_values_direct_typed.size);
ok(query_reg_values_direct_typed.type == expected_type,
"Expected type %lu, got %lu\n", expected_type, query_reg_values_direct_typed.type);
ok(!memcmp(query_reg_values_direct_typed.data, expected_data, expected_size),
"Data does not match\n");
}
}
}

View File

@ -1252,9 +1252,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"5:\tmovw r0, #0x000d\n\t" /* STATUS_INVALID_PARAMETER */
"movt r0, #0xc000\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
"mov r8, r0\n\t"
"mov r0, r1\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )

View File

@ -1607,9 +1607,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"ret x16\n"
"4:\tmov x0, #0xc0000000\n\t" /* STATUS_INVALID_PARAMETER */
"movk x0, #0x000d\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
"mov sp, x0\n\t"
"mov x0, x1\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )

View File

@ -2768,10 +2768,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
__ASM_CFI("\t.cfi_restore_state\n")
"6:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
"jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
"jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
"movl 8(%esp),%eax\n\t"
"movl 4(%esp),%esp\n\t"
"jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )

View File

@ -2876,9 +2876,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
__ASM_CFI("\t.cfi_restore_state\n")
"5:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
"movq %rsp,%rcx\n\t"
"jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
"jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
"movq %rdi,%rcx\n\t"
"movl 0xb0(%rcx),%r14d\n\t" /* frame->syscall_flags */
"movq %rsi,%rax\n\t"

View File

@ -3621,6 +3621,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow )
if (is_wow) teb64->WowTebOffset = teb_offset;
#else
teb = (TEB *)teb32;
teb32->Tib.ExceptionList = ~0u;
teb64->Peb = PtrToUlong( (char *)peb - page_size );
teb64->Tib.Self = PtrToUlong( teb64 );
teb64->Tib.ExceptionList = PtrToUlong( teb32 );
@ -3639,7 +3640,6 @@ static TEB *init_teb( void *ptr, BOOL is_wow )
#endif
teb->Peb = peb;
teb->Tib.Self = &teb->Tib;
teb->Tib.ExceptionList = (void *)~0ul;
teb->Tib.StackBase = (void *)~0ul;
teb->ActivationContextStackPointer = &teb->ActivationContextStack;
InitializeListHead( &teb->ActivationContextStack.FrameListCache );

View File

@ -65,7 +65,6 @@ static PFN_vkGetPhysicalDeviceMemoryProperties2KHR pvkGetPhysicalDeviceMemoryPro
static PFN_vkGetPhysicalDeviceMemoryProperties pvkGetPhysicalDeviceMemoryProperties;
static PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
static PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
static const struct vulkan_funcs *vulkan_funcs;
static void d3dkmt_init_vulkan(void)
{
@ -94,7 +93,6 @@ static void d3dkmt_init_vulkan(void)
if ((vr = p_vkCreateInstance( &create_info, NULL, &d3dkmt_vk_instance )))
{
WARN( "Failed to create a Vulkan instance, vr %d.\n", vr );
vulkan_funcs = NULL;
return;
}
@ -104,7 +102,7 @@ static void d3dkmt_init_vulkan(void)
{ \
WARN( "Failed to load " #f ".\n" ); \
p_vkDestroyInstance( d3dkmt_vk_instance, NULL ); \
vulkan_funcs = NULL; \
d3dkmt_vk_instance = NULL; \
return; \
}
LOAD_VK_FUNC( vkEnumeratePhysicalDevices )
@ -118,7 +116,7 @@ static BOOL d3dkmt_use_vulkan(void)
{
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once( &once, d3dkmt_init_vulkan );
return !!vulkan_funcs;
return !!d3dkmt_vk_instance;
}
/* d3dkmt_lock must be held */

View File

@ -740,22 +740,22 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y )
*/
BOOL get_cursor_pos( POINT *pt )
{
struct object_lock lock = OBJECT_LOCK_INIT;
const desktop_shm_t *desktop_shm;
BOOL ret;
DWORD last_change;
DWORD last_change = 0;
NTSTATUS status;
UINT dpi;
if (!pt) return FALSE;
SERVER_START_REQ( set_cursor )
while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING)
{
if ((ret = !wine_server_call( req )))
{
pt->x = reply->new_x;
pt->y = reply->new_y;
last_change = reply->last_change;
}
pt->x = desktop_shm->cursor.x;
pt->y = desktop_shm->cursor.y;
last_change = desktop_shm->cursor.last_change;
}
SERVER_END_REQ;
ret = !status;
/* query new position from graphics driver if we haven't updated recently */
if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt );

View File

@ -124,6 +124,7 @@ struct user_thread_info
UINT spy_indent; /* Current spy indent */
BOOL clipping_cursor; /* thread is currently clipping */
DWORD clipping_reset; /* time when clipping was last reset */
struct session_thread_data *session_data; /* shared session thread data */
};
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) );

View File

@ -6340,6 +6340,7 @@ static void thread_detach(void)
cleanup_imm_thread();
NtClose( thread_info->server_queue );
free( thread_info->session_data );
exiting_thread_id = 0;
}

View File

@ -205,6 +205,22 @@ extern void free_vulkan_gpu( struct vulkan_gpu *gpu );
extern BOOL get_vulkan_uuid_from_luid( const LUID *luid, GUID *uuid );
/* winstation.c */
struct object_lock
{
UINT64 id;
UINT64 seq;
};
#define OBJECT_LOCK_INIT {0}
/* Get shared session object's data pointer, must be called in a loop while STATUS_PENDING
* is returned, lock must be initialized with OBJECT_LOCK_INIT.
*
* The data read from the objects may be transient and no logic should be executed based
* on it, within the loop, or after, unless the function has returned STATUS_SUCCESS.
*/
extern NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm );
extern BOOL is_virtual_desktop(void);
/* window.c */

View File

@ -22,9 +22,14 @@
#pragma makedep unix
#endif
#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <pthread.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "ntuser.h"
@ -40,6 +45,180 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
struct session_thread_data
{
const shared_object_t *shared_desktop; /* thread desktop shared session cached object */
};
struct session_block
{
struct list entry; /* entry in the session block list */
const char *data; /* base pointer for the mmaped data */
SIZE_T offset; /* offset of data in the session shared mapping */
SIZE_T size; /* size of the mmaped data */
};
static pthread_mutex_t session_lock = PTHREAD_MUTEX_INITIALIZER;
static struct list session_blocks = LIST_INIT(session_blocks);
static struct session_thread_data *get_session_thread_data(void)
{
struct user_thread_info *thread_info = get_user_thread_info();
if (!thread_info->session_data) thread_info->session_data = calloc(1, sizeof(*thread_info->session_data));
return thread_info->session_data;
}
#if defined(__i386__) || defined(__x86_64__)
/* this prevents compilers from incorrectly reordering non-volatile reads (e.g., memcpy) from shared memory */
#define __SHARED_READ_FENCE do { __asm__ __volatile__( "" ::: "memory" ); } while (0)
#else
#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE )
#endif
static void shared_object_acquire_seqlock( const shared_object_t *object, UINT64 *seq )
{
while ((*seq = ReadNoFence64( &object->seq )) & 1) YieldProcessor();
__SHARED_READ_FENCE;
}
static BOOL shared_object_release_seqlock( const shared_object_t *object, UINT64 seq )
{
__SHARED_READ_FENCE;
return ReadNoFence64( &object->seq ) == seq;
}
static object_id_t shared_object_get_id( const shared_object_t *object )
{
struct object_lock lock = OBJECT_LOCK_INIT;
do
{
shared_object_acquire_seqlock( object, &lock.seq );
lock.id = object->id;
} while (!shared_object_release_seqlock( object, lock.seq ));
return lock.id;
}
static NTSTATUS map_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret )
{
static const WCHAR nameW[] =
{
'\\','K','e','r','n','e','l','O','b','j','e','c','t','s','\\',
'_','_','w','i','n','e','_','s','e','s','s','i','o','n',0
};
UNICODE_STRING name = RTL_CONSTANT_STRING( nameW );
LARGE_INTEGER off = {.QuadPart = offset - (offset % system_info.AllocationGranularity)};
struct session_block *block;
OBJECT_ATTRIBUTES attr;
unsigned int status;
HANDLE handle;
assert( offset + size > offset );
if (!(block = calloc( 1, sizeof(*block) ))) return STATUS_NO_MEMORY;
InitializeObjectAttributes( &attr, &name, 0, NULL, NULL );
if ((status = NtOpenSection( &handle, SECTION_MAP_READ, &attr )))
WARN( "Failed to open shared session section, status %#x\n", status );
else
{
if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), (void **)&block->data, 0, 0,
&off, &block->size, ViewUnmap, 0, PAGE_READONLY )))
WARN( "Failed to map shared session block, status %#x\n", status );
else
{
list_add_tail( &session_blocks, &block->entry );
block->offset = off.QuadPart;
assert( block->offset + block->size > block->offset );
}
NtClose( handle );
}
if (status) free( block );
else *ret = block;
return status;
}
static NTSTATUS find_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret )
{
struct session_block *block;
UINT status;
assert( offset + size > offset );
pthread_mutex_lock( &session_lock );
LIST_FOR_EACH_ENTRY( block, &session_blocks, struct session_block, entry )
{
if (block->offset < offset && offset + size <= block->offset + block->size)
{
*ret = block;
pthread_mutex_unlock( &session_lock );
return STATUS_SUCCESS;
}
}
if ((status = map_shared_session_block( offset, size, ret )))
{
WARN( "Failed to map session block for offset %s, size %s, status %#x\n",
wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size), status );
}
pthread_mutex_unlock( &session_lock );
return status;
}
static const shared_object_t *find_shared_session_object( obj_locator_t locator )
{
const shared_object_t *object;
struct session_block *block;
NTSTATUS status;
if (locator.id && !(status = find_shared_session_block( locator.offset, sizeof(*object), &block )))
{
object = (const shared_object_t *)(block->data + locator.offset - block->offset);
if (locator.id == shared_object_get_id( object )) return object;
WARN( "Session object id doesn't match expected id %s\n", wine_dbgstr_longlong(locator.id) );
}
return NULL;
}
NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm )
{
struct session_thread_data *data = get_session_thread_data();
const shared_object_t *object;
TRACE( "lock %p, desktop_shm %p\n", lock, desktop_shm );
if (!(object = data->shared_desktop))
{
obj_locator_t locator;
SERVER_START_REQ( get_thread_desktop )
{
req->tid = GetCurrentThreadId();
wine_server_call( req );
locator = reply->locator;
}
SERVER_END_REQ;
data->shared_desktop = find_shared_session_object( locator );
if (!(object = data->shared_desktop)) return STATUS_INVALID_HANDLE;
memset( lock, 0, sizeof(*lock) );
}
if (!lock->id || !shared_object_release_seqlock( object, lock->seq ))
{
shared_object_acquire_seqlock( object, &lock->seq );
*desktop_shm = &object->shm.desktop;
lock->id = object->id;
return STATUS_PENDING;
}
return STATUS_SUCCESS;
}
BOOL is_virtual_desktop(void)
{
HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() );
@ -249,11 +428,13 @@ HDESK WINAPI NtUserGetThreadDesktop( DWORD thread )
BOOL WINAPI NtUserSetThreadDesktop( HDESK handle )
{
BOOL ret, was_virtual_desktop = is_virtual_desktop();
obj_locator_t locator;
SERVER_START_REQ( set_thread_desktop )
{
req->handle = wine_server_obj_handle( handle );
ret = !wine_server_call_err( req );
locator = reply->locator;
}
SERVER_END_REQ;
@ -261,6 +442,7 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle )
{
struct user_thread_info *thread_info = get_user_thread_info();
struct user_key_state_info *key_state_info = thread_info->key_state;
get_session_thread_data()->shared_desktop = find_shared_session_object( locator );
thread_info->client_info.top_window = 0;
thread_info->client_info.msg_window = 0;
if (key_state_info) key_state_info->time = 0;

View File

@ -19,6 +19,7 @@ SOURCES = \
rsrc.rc \
unixlib.c \
video_decoder.c \
video_encoder.c \
video_processor.c \
wg_allocator.c \
wg_format.c \

View File

@ -167,6 +167,8 @@ HRESULT aac_decoder_create(REFIID riid, void **ret);
HRESULT h264_decoder_create(REFIID riid, void **ret);
HRESULT video_processor_create(REFIID riid, void **ret);
HRESULT h264_encoder_create(REFIID riid, void **ret);
extern const GUID MFAudioFormat_RAW_AAC;
#endif /* __GST_PRIVATE_INCLUDED__ */

View File

@ -133,6 +133,7 @@ class_objects[] =
{ &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create },
{ &CLSID_MSAACDecMFT, &aac_decoder_create },
{ &CLSID_MSH264DecoderMFT, &h264_decoder_create },
{ &CLSID_MSH264EncoderMFT, &h264_encoder_create },
};
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
@ -208,6 +209,18 @@ HRESULT mfplat_DllRegisterServer(void)
{MFMediaType_Video, MFVideoFormat_YUY2},
};
MFT_REGISTER_TYPE_INFO h264_encoder_input_types[] =
{
{MFMediaType_Video, MFVideoFormat_IYUV},
{MFMediaType_Video, MFVideoFormat_YV12},
{MFMediaType_Video, MFVideoFormat_NV12},
{MFMediaType_Video, MFVideoFormat_YUY2},
};
MFT_REGISTER_TYPE_INFO h264_encoder_output_types[] =
{
{MFMediaType_Video, MFVideoFormat_H264},
};
MFT_REGISTER_TYPE_INFO video_processor_input_types[] =
{
{MFMediaType_Video, MFVideoFormat_IYUV},
@ -371,6 +384,16 @@ HRESULT mfplat_DllRegisterServer(void)
ARRAY_SIZE(h264_decoder_output_types),
h264_decoder_output_types,
},
{
CLSID_MSH264EncoderMFT,
MFT_CATEGORY_VIDEO_ENCODER,
L"H264 Encoder MFT",
MFT_ENUM_FLAG_SYNCMFT,
ARRAY_SIZE(h264_encoder_input_types),
h264_encoder_input_types,
ARRAY_SIZE(h264_encoder_output_types),
h264_encoder_output_types,
},
{
CLSID_WMVDecoderMFT,
MFT_CATEGORY_VIDEO_DECODER,

View File

@ -0,0 +1,338 @@
/* Generic Video Encoder Transform
*
* Copyright 2024 Ziqing Hui for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "gst_private.h"
#include "mfapi.h"
#include "mferror.h"
#include "mfobjects.h"
#include "mftransform.h"
#include "mediaerr.h"
#include "wmcodecdsp.h"
#include "wine/debug.h"
#include "initguid.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
struct video_encoder
{
IMFTransform IMFTransform_iface;
LONG refcount;
IMFAttributes *attributes;
};
static inline struct video_encoder *impl_from_IMFTransform(IMFTransform *iface)
{
return CONTAINING_RECORD(iface, struct video_encoder, IMFTransform_iface);
}
static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
{
struct video_encoder *encoder = impl_from_IMFTransform(iface);
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
if (IsEqualGUID(iid, &IID_IMFTransform) || IsEqualGUID(iid, &IID_IUnknown))
*out = &encoder->IMFTransform_iface;
else
{
*out = NULL;
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown *)*out);
return S_OK;
}
static ULONG WINAPI transform_AddRef(IMFTransform *iface)
{
struct video_encoder *encoder = impl_from_IMFTransform(iface);
ULONG refcount = InterlockedIncrement(&encoder->refcount);
TRACE("iface %p increasing refcount to %lu.\n", encoder, refcount);
return refcount;
}
static ULONG WINAPI transform_Release(IMFTransform *iface)
{
struct video_encoder *encoder = impl_from_IMFTransform(iface);
ULONG refcount = InterlockedDecrement(&encoder->refcount);
TRACE("iface %p decreasing refcount to %lu.\n", encoder, refcount);
if (!refcount)
{
IMFAttributes_Release(encoder->attributes);
free(encoder);
}
return refcount;
}
static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
{
TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
iface, input_minimum, input_maximum, output_minimum, output_maximum);
*input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
return S_OK;
}
static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
{
TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
*inputs = *outputs = 1;
return S_OK;
}
static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
DWORD output_size, DWORD *outputs)
{
FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
input_size, inputs, output_size, outputs);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
{
FIXME("iface %p, id %#lx, info %p.\n", iface, id, info);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
{
FIXME("iface %p, id %#lx, info %p.\n", iface, id, info);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
{
struct video_encoder *encoder = impl_from_IMFTransform(iface);
TRACE("iface %p, attributes %p.\n", iface, attributes);
if (!attributes)
return E_POINTER;
IMFAttributes_AddRef((*attributes = encoder->attributes));
return S_OK;
}
static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
{
FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
{
FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
{
FIXME("iface %p, id %#lx.\n", iface, id);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
{
FIXME("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
IMFMediaType **type)
{
FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
DWORD index, IMFMediaType **type)
{
FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
{
FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
{
FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
{
FIXME("iface %p, id %#lx, type %p\n", iface, id, type);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
{
FIXME("iface %p, id %#lx, type %p\n", iface, id, type);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
{
FIXME("iface %p, id %#lx, flags %p.\n", iface, id, flags);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
{
FIXME("iface %p, flags %p stub!\n", iface, flags);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
{
FIXME("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
{
FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
{
FIXME("iface %p, message %#x, param %Ix.\n", iface, message, param);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
{
FIXME("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
return E_NOTIMPL;
}
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
{
FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
return E_NOTIMPL;
}
static const IMFTransformVtbl transform_vtbl =
{
transform_QueryInterface,
transform_AddRef,
transform_Release,
transform_GetStreamLimits,
transform_GetStreamCount,
transform_GetStreamIDs,
transform_GetInputStreamInfo,
transform_GetOutputStreamInfo,
transform_GetAttributes,
transform_GetInputStreamAttributes,
transform_GetOutputStreamAttributes,
transform_DeleteInputStream,
transform_AddInputStreams,
transform_GetInputAvailableType,
transform_GetOutputAvailableType,
transform_SetInputType,
transform_SetOutputType,
transform_GetInputCurrentType,
transform_GetOutputCurrentType,
transform_GetInputStatus,
transform_GetOutputStatus,
transform_SetOutputBounds,
transform_ProcessEvent,
transform_ProcessMessage,
transform_ProcessInput,
transform_ProcessOutput,
};
static HRESULT video_encoder_create(struct video_encoder **out)
{
struct video_encoder *encoder;
HRESULT hr;
if (!(encoder = calloc(1, sizeof(*encoder))))
return E_OUTOFMEMORY;
encoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
encoder->refcount = 1;
if (FAILED(hr = MFCreateAttributes(&encoder->attributes, 16)))
goto failed;
if (FAILED(hr = IMFAttributes_SetUINT32(encoder->attributes, &MFT_ENCODER_SUPPORTS_CONFIG_EVENT, TRUE)))
goto failed;
*out = encoder;
TRACE("Created video encoder %p\n", encoder);
return S_OK;
failed:
if (encoder->attributes)
IMFAttributes_Release(encoder->attributes);
free(encoder);
return hr;
}
HRESULT h264_encoder_create(REFIID riid, void **out)
{
const MFVIDEOFORMAT input_format =
{
.dwSize = sizeof(MFVIDEOFORMAT),
.videoInfo = {.dwWidth = 1920, .dwHeight = 1080},
.guidFormat = MFVideoFormat_NV12,
};
const MFVIDEOFORMAT output_format =
{
.dwSize = sizeof(MFVIDEOFORMAT),
.videoInfo = {.dwWidth = 1920, .dwHeight = 1080},
.guidFormat = MFVideoFormat_H264,
};
struct video_encoder *encoder;
HRESULT hr;
TRACE("riid %s, out %p.\n", debugstr_guid(riid), out);
if (FAILED(hr = check_video_transform_support(&input_format, &output_format)))
{
ERR_(winediag)("GStreamer doesn't support H.264 encoding, please install appropriate plugins\n");
return hr;
}
if (FAILED(hr = video_encoder_create(&encoder)))
return hr;
TRACE("Created h264 encoder transform %p.\n", &encoder->IMFTransform_iface);
hr = IMFTransform_QueryInterface(&encoder->IMFTransform_iface, riid, out);
IMFTransform_Release(&encoder->IMFTransform_iface);
return hr;
}

View File

@ -107,6 +107,12 @@ coclass CWMVDecMediaObject {}
]
coclass CMSH264DecoderMFT {}
[
threading(both),
uuid(6ca50344-051a-4ded-9779-a43305165e35)
]
coclass CMSH264EncoderMFT {}
[
threading(both),
uuid(f447b69e-1884-4a7e-8055-346f74d6edb3)

View File

@ -48,9 +48,14 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
#include "wine/vulkan.h"
#include "wine/vulkan_driver.h"
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
static void *xrandr_handle;
static void *vulkan_handle;
static void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *);
static VkInstance vk_instance; /* Vulkan instance for XRandR functions */
static VkResult (*p_vkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
static PFN_vkGetPhysicalDeviceProperties2KHR p_vkGetPhysicalDeviceProperties2KHR;
static PFN_vkEnumeratePhysicalDevices p_vkEnumeratePhysicalDevices;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f;
MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
@ -140,8 +145,31 @@ sym_not_found:
#ifdef SONAME_LIBVULKAN
static void *vulkan_handle;
static void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *);
static void vulkan_init_once(void)
{
static const char *extensions[] =
{
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
"VK_EXT_acquire_xlib_display",
"VK_EXT_direct_mode_display",
"VK_KHR_display",
VK_KHR_SURFACE_EXTENSION_NAME,
};
VkInstanceCreateInfo create_info =
{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.ppEnabledExtensionNames = extensions,
.enabledExtensionCount = ARRAY_SIZE(extensions),
};
PFN_vkDestroyInstance p_vkDestroyInstance;
PFN_vkCreateInstance p_vkCreateInstance;
VkResult vr;
if (!(vulkan_handle = dlopen( SONAME_LIBVULKAN, RTLD_NOW )))
{
ERR( "Failed to load %s\n", SONAME_LIBVULKAN );
@ -153,12 +181,33 @@ static void vulkan_init_once(void)
{ \
ERR( "Failed to find " #f "\n" ); \
dlclose( vulkan_handle ); \
vulkan_handle = NULL; \
return; \
}
LOAD_FUNCPTR( vkGetInstanceProcAddr );
#undef LOAD_FUNCPTR
p_vkCreateInstance = p_vkGetInstanceProcAddr( NULL, "vkCreateInstance" );
if ((vr = p_vkCreateInstance( &create_info, NULL, &vk_instance )))
{
WARN( "Failed to create a Vulkan instance, vr %d.\n", vr );
return;
}
p_vkDestroyInstance = p_vkGetInstanceProcAddr( vk_instance, "vkDestroyInstance" );
#define LOAD_VK_FUNC(f) \
if (!(p_##f = (void *)p_vkGetInstanceProcAddr( vk_instance, #f ))) \
{ \
WARN("Failed to load " #f ".\n"); \
p_vkDestroyInstance( vk_instance, NULL ); \
vk_instance = NULL; \
return; \
}
LOAD_VK_FUNC( vkEnumeratePhysicalDevices )
LOAD_VK_FUNC( vkGetPhysicalDeviceProperties2KHR )
LOAD_VK_FUNC( vkGetRandROutputDisplayEXT )
#undef LOAD_VK_FUNC
}
#else /* SONAME_LIBVULKAN */
@ -174,7 +223,7 @@ static BOOL vulkan_init(void)
{
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
pthread_once( &init_once, vulkan_init_once );
return !!vulkan_handle;
return !!vk_instance;
}
static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
@ -668,65 +717,20 @@ static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc )
crtc->y + crtc->height == primary.bottom;
}
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR)
static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRProviderInfo *provider_info,
struct x11drv_gpu *prev_gpus, int prev_gpu_count )
{
static const char *extensions[] =
{
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
"VK_EXT_acquire_xlib_display",
"VK_EXT_direct_mode_display",
"VK_KHR_display",
VK_KHR_SURFACE_EXTENSION_NAME,
};
VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
uint32_t device_count, device_idx, output_idx, i;
PFN_vkDestroyInstance pvkDestroyInstance = NULL;
VkPhysicalDevice *vk_physical_devices = NULL;
VkPhysicalDeviceProperties2 properties2;
PFN_vkCreateInstance pvkCreateInstance;
VkInstanceCreateInfo create_info;
VkPhysicalDeviceIDProperties id;
VkInstance vk_instance = NULL;
VkDisplayKHR vk_display;
BOOL ret = FALSE;
VkResult vr;
if (!vulkan_init()) goto done;
memset( &create_info, 0, sizeof(create_info) );
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
create_info.ppEnabledExtensionNames = extensions;
#define LOAD_VK_FUNC(f) \
if (!(p##f = (void *)p_vkGetInstanceProcAddr( vk_instance, #f ))) \
{ \
WARN("Failed to load " #f ".\n"); \
goto done; \
}
LOAD_VK_FUNC( vkCreateInstance )
vr = pvkCreateInstance( &create_info, NULL, &vk_instance );
if (vr != VK_SUCCESS)
{
WARN( "Failed to create a Vulkan instance, vr %d.\n", vr );
goto done;
}
LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
LOAD_VK_FUNC(vkDestroyInstance)
#undef LOAD_VK_FUNC
vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
vr = p_vkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
if (vr != VK_SUCCESS || !device_count)
{
WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count);
@ -736,7 +740,7 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
if (!(vk_physical_devices = calloc( device_count, sizeof(*vk_physical_devices) )))
goto done;
vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
vr = p_vkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices );
if (vr != VK_SUCCESS)
{
WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr);
@ -749,8 +753,8 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
{
for (output_idx = 0; output_idx < provider_info->noutputs; ++output_idx)
{
vr = pvkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
provider_info->outputs[output_idx], &vk_display );
vr = p_vkGetRandROutputDisplayEXT( vk_physical_devices[device_idx], gdi_display,
provider_info->outputs[output_idx], &vk_display );
if (vr != VK_SUCCESS || vk_display == VK_NULL_HANDLE)
continue;
@ -759,7 +763,7 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties2.pNext = &id;
pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
p_vkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 );
for (i = 0; i < prev_gpu_count; ++i)
{
if (!memcmp( &prev_gpus[i].vulkan_uuid, &id.deviceUUID, sizeof(id.deviceUUID) ))
@ -788,7 +792,6 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
done:
free( vk_physical_devices );
if (vk_instance && pvkDestroyInstance) pvkDestroyInstance( vk_instance, NULL );
return ret;
}

View File

@ -29,6 +29,7 @@ typedef unsigned __int64 mem_size_t;
typedef unsigned __int64 file_pos_t;
typedef unsigned __int64 client_ptr_t;
typedef unsigned __int64 affinity_t;
typedef unsigned __int64 object_id_t;
typedef client_ptr_t mod_handle_t;
struct request_header
@ -882,6 +883,39 @@ struct directory_entry
struct shared_cursor
{
int x;
int y;
unsigned int last_change;
};
typedef volatile struct
{
struct shared_cursor cursor;
} desktop_shm_t;
typedef volatile union
{
desktop_shm_t desktop;
} object_shm_t;
typedef volatile struct
{
LONG64 seq;
object_id_t id;
object_shm_t shm;
} shared_object_t;
typedef struct
{
object_id_t id;
mem_size_t offset;
} obj_locator_t;
struct new_process_request
{
@ -3874,8 +3908,9 @@ struct get_thread_desktop_request
struct get_thread_desktop_reply
{
struct reply_header __header;
obj_handle_t handle;
char __pad_12[4];
obj_locator_t locator;
obj_handle_t handle;
char __pad_28[4];
};
@ -3888,6 +3923,7 @@ struct set_thread_desktop_request
struct set_thread_desktop_reply
{
struct reply_header __header;
obj_locator_t locator;
};
@ -6531,7 +6567,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 808
#define SERVER_PROTOCOL_VERSION 813
/* ### protocol_version end ### */

View File

@ -7082,11 +7082,14 @@ static FORCEINLINE void MemoryBarrier(void)
*/
#if _MSC_VER >= 1700
#pragma intrinsic(__iso_volatile_load32)
#pragma intrinsic(__iso_volatile_load64)
#pragma intrinsic(__iso_volatile_store32)
#define __WINE_LOAD32_NO_FENCE(src) (__iso_volatile_load32(src))
#define __WINE_LOAD64_NO_FENCE(src) (__iso_volatile_load64(src))
#define __WINE_STORE32_NO_FENCE(dest, value) (__iso_volatile_store32(dest, value))
#else /* _MSC_VER >= 1700 */
#define __WINE_LOAD32_NO_FENCE(src) (*(src))
#define __WINE_LOAD64_NO_FENCE(src) (*(src))
#define __WINE_STORE32_NO_FENCE(dest, value) ((void)(*(dest) = (value)))
#endif /* _MSC_VER >= 1700 */
@ -7120,6 +7123,12 @@ static FORCEINLINE LONG ReadNoFence( LONG const volatile *src )
return value;
}
static FORCEINLINE LONG64 ReadNoFence64( LONG64 const volatile *src )
{
LONG64 value = __WINE_LOAD64_NO_FENCE( (__int64 const volatile *)src );
return value;
}
static FORCEINLINE void WriteRelease( LONG volatile *dest, LONG value )
{
__wine_memory_barrier_acq_rel();
@ -7306,6 +7315,13 @@ static FORCEINLINE LONG ReadNoFence( LONG const volatile *src )
return value;
}
static FORCEINLINE LONG64 ReadNoFence64( LONG64 const volatile *src )
{
LONG64 value;
__WINE_ATOMIC_LOAD_RELAXED( src, &value );
return value;
}
static FORCEINLINE void WriteRelease( LONG volatile *dest, LONG value )
{
__WINE_ATOMIC_STORE_RELEASE( dest, &value );

View File

@ -52,6 +52,12 @@ coclass CResamplerMediaObject {}
]
coclass CMSH264DecoderMFT {}
[
threading(both),
uuid(6ca50344-051a-4ded-9779-a43305165e35)
]
coclass CMSH264EncoderMFT {}
[
uuid(2d709e52-123f-49b5-9cbc-9af5cde28fb9)
]

View File

@ -153,7 +153,7 @@ static struct
{' ',' '}
};
static DIRECTORY_STACK *WCMD_dir_stack_create(const WCHAR *dir, const WCHAR *file)
DIRECTORY_STACK *WCMD_dir_stack_create(const WCHAR *dir, const WCHAR *file)
{
DIRECTORY_STACK *new = xalloc(sizeof(DIRECTORY_STACK));
@ -177,7 +177,7 @@ static DIRECTORY_STACK *WCMD_dir_stack_create(const WCHAR *dir, const WCHAR *fil
return new;
}
static DIRECTORY_STACK *WCMD_dir_stack_free(DIRECTORY_STACK *dir)
DIRECTORY_STACK *WCMD_dir_stack_free(DIRECTORY_STACK *dir)
{
DIRECTORY_STACK *next;
@ -228,7 +228,7 @@ static BOOL WCMD_ask_confirm (const WCHAR *message, BOOL showSureText,
if (showSureText)
WCMD_output_asis (confirm);
WCMD_output_asis (options);
if (!WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, ARRAY_SIZE(answer), &count))
if (!WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, ARRAY_SIZE(answer), &count) || !count)
return FALSE;
answer[0] = towupper(answer[0]);
if (answer[0] == Ybuffer[0])
@ -1673,110 +1673,6 @@ void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
}
}
static BOOL option_equals(WCHAR **haystack, const WCHAR *needle)
{
int len = wcslen(needle);
if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
*haystack, len, needle, len) == CSTR_EQUAL) {
*haystack += len;
return TRUE;
}
return FALSE;
}
/*****************************************************************************
* WCMD_parse_forf_options
*
* Parses the for /f 'options', extracting the values and validating the
* keywords. Note all keywords are optional.
* Parameters:
* options [I] The unparsed parameter string
* eol [O] Set to the comment character (eol=x)
* skip [O] Set to the number of lines to skip (skip=xx)
* delims [O] Set to the token delimiters (delims=)
* tokens [O] Set to the requested tokens, as provided (tokens=)
* usebackq [O] Set to TRUE if usebackq found
*
* Returns TRUE on success, FALSE on syntax error
*
*/
static BOOL WCMD_parse_forf_options(WCHAR *options, WCHAR *eol, int *skip,
WCHAR *delims, WCHAR *tokens, BOOL *usebackq)
{
WCHAR *pos = options;
int len = lstrlenW(pos);
/* Initialize to defaults */
lstrcpyW(delims, L" \t");
lstrcpyW(tokens, L"1");
*eol = 0;
*skip = 0;
*usebackq = FALSE;
/* Strip (optional) leading and trailing quotes */
if ((*pos == '"') && (pos[len-1] == '"')) {
pos[len-1] = 0;
pos++;
}
/* Process each keyword */
while (pos && *pos) {
if (*pos == ' ' || *pos == '\t') {
pos++;
/* Save End of line character (Ignore line if first token (based on delims) starts with it) */
} else if (option_equals(&pos, L"eol=")) {
*eol = *pos++;
WINE_TRACE("Found eol as %c(%x)\n", *eol, *eol);
/* Save number of lines to skip (Can be in base 10, hex (0x...) or octal (0xx) */
} else if (option_equals(&pos, L"skip=")) {
WCHAR *nextchar = NULL;
*skip = wcstoul(pos, &nextchar, 0);
WINE_TRACE("Found skip as %d lines\n", *skip);
pos = nextchar;
/* Save if usebackq semantics are in effect */
} else if (option_equals(&pos, L"usebackq")) {
*usebackq = TRUE;
WINE_TRACE("Found usebackq\n");
/* Save the supplied delims. Slightly odd as space can be a delimiter but only
if you finish the optionsroot string with delims= otherwise the space is
just a token delimiter! */
} else if (option_equals(&pos, L"delims=")) {
int i=0;
while (*pos && *pos != ' ') {
delims[i++] = *pos;
pos++;
}
if (*pos==' ' && *(pos+1)==0) delims[i++] = *pos;
delims[i++] = 0; /* Null terminate the delims */
WINE_TRACE("Found delims as '%s'\n", wine_dbgstr_w(delims));
/* Save the tokens being requested */
} else if (option_equals(&pos, L"tokens=")) {
int i=0;
while (*pos && *pos != ' ') {
tokens[i++] = *pos;
pos++;
}
tokens[i++] = 0; /* Null terminate the tokens */
WINE_TRACE("Found tokens as '%s'\n", wine_dbgstr_w(tokens));
} else {
WINE_WARN("Unexpected data in optionsroot: '%s'\n", wine_dbgstr_w(pos));
return FALSE;
}
}
return TRUE;
}
/*****************************************************************************
* WCMD_add_dirstowalk
*
@ -1790,7 +1686,7 @@ static BOOL WCMD_parse_forf_options(WCHAR *options, WCHAR *eol, int *skip,
* processed, and any other directory still to be processed, mimicking what
* Windows does
*/
static void WCMD_add_dirstowalk(DIRECTORY_STACK *dirsToWalk)
void WCMD_add_dirstowalk(DIRECTORY_STACK *dirsToWalk)
{
DIRECTORY_STACK *remainingDirs = dirsToWalk;
WCHAR fullitem[MAX_PATH];
@ -1953,177 +1849,6 @@ int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
return nexttoken;
}
/**************************************************************************
* WCMD_parse_line
*
* When parsing file or string contents (for /f), once the string to parse
* has been identified, handle the various options and call the do part
* if appropriate.
*
* Parameters:
* cmdStart [I] - Identifies the list of commands making up the
* for loop body (especially if brackets in use)
* firstCmd [I] - The textual start of the command after the DO
* which is within the first item of cmdStart
* cmdEnd [O] - Identifies where to continue after the DO
* variable [I] - The variable identified on the for line
* buffer [I] - The string to parse
* doExecuted [O] - Set to TRUE if the DO is ever executed once
* forf_skip [I/O] - How many lines to skip first
* forf_eol [I] - The 'end of line' (comment) character
* forf_delims [I] - The delimiters to use when breaking the string apart
* forf_tokens [I] - The tokens to use when breaking the string apart
*/
static void WCMD_parse_line(CMD_NODE *cmdStart,
const WCHAR *firstCmd,
CMD_NODE **cmdEnd,
int varidx,
WCHAR *buffer,
BOOL *doExecuted,
int *forf_skip,
WCHAR forf_eol,
WCHAR *forf_delims,
WCHAR *forf_tokens) {
WCHAR *parm;
int varoffset;
int nexttoken, lasttoken = -1;
BOOL starfound = FALSE;
BOOL thisduplicate = FALSE;
BOOL anyduplicates = FALSE;
int totalfound;
static WCHAR emptyW[] = L"";
/* Skip lines if requested */
if (*forf_skip) {
(*forf_skip)--;
return;
}
/* Save away any existing for variable context (e.g. nested for loops) */
WCMD_save_for_loop_context(FALSE);
/* Extract the parameters based on the tokens= value (There will always
be some value, as if it is not supplied, it defaults to tokens=1).
Rough logic:
Count how many tokens are named in the line, identify the lowest
Empty (set to null terminated string) that number of named variables
While lasttoken != nextlowest
%letter = parameter number 'nextlowest'
letter++ (if >26 or >52 abort)
Go through token= string finding next lowest number
If token ends in * set %letter = raw position of token(nextnumber+1)
*/
lasttoken = -1;
nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, &totalfound,
&starfound, &thisduplicate);
/* Empty out variables */
for (varoffset=0;
varidx >= 0 && varoffset<totalfound && for_var_index_in_range(varidx, varoffset);
varoffset++) {
WCMD_set_for_loop_variable(varidx + varoffset, emptyW);
}
/* Loop extracting the tokens
Note: nexttoken of 0 means there were no tokens requested, to handle
the special case of tokens=* */
varoffset = 0;
WINE_TRACE("Parsing buffer into tokens: '%s'\n", wine_dbgstr_w(buffer));
while (varidx >= 0 && (nexttoken > 0 && (nexttoken > lasttoken))) {
anyduplicates |= thisduplicate;
if (!for_var_index_in_range(varidx, varoffset)) break;
/* Extract the token number requested and set into the next variable context */
parm = WCMD_parameter_with_delims(buffer, (nexttoken-1), NULL, TRUE, FALSE, forf_delims);
WINE_TRACE("Parsed token %d(%d) as parameter %s\n", nexttoken,
varidx + varoffset, wine_dbgstr_w(parm));
if (varidx >=0) {
if (parm)
WCMD_set_for_loop_variable(varidx + varoffset, parm);
varoffset++;
}
/* Find the next token */
lasttoken = nexttoken;
nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, NULL,
&starfound, &thisduplicate);
}
/* If all the rest of the tokens were requested, and there is still space in
the variable range, write them now */
if (!anyduplicates && starfound && varidx >= 0 && for_var_index_in_range(varidx, varoffset)) {
nexttoken++;
WCMD_parameter_with_delims(buffer, (nexttoken-1), &parm, FALSE, FALSE, forf_delims);
WINE_TRACE("Parsed allremaining tokens (%d) as parameter %s\n",
varidx + varoffset, wine_dbgstr_w(parm));
if (parm)
WCMD_set_for_loop_variable(varidx + varoffset, parm);
}
/* Execute the body of the foor loop with these values */
if (varidx >= 0 && forloopcontext->variable[varidx] && forloopcontext->variable[varidx][0] != forf_eol) {
CMD_NODE *thisCmdStart = cmdStart;
*doExecuted = TRUE;
WCMD_part_execute(&thisCmdStart, firstCmd, FALSE, TRUE);
*cmdEnd = thisCmdStart;
}
WCMD_restore_for_loop_context();
}
/**************************************************************************
* WCMD_forf_getinput
*
* Return a FILE* which can be used for reading the input lines,
* either to a specific file (which may be quote delimited as we have to
* read the parameters in raw mode) or to a command which we need to
* execute. The command being executed runs in its own shell and stores
* its data in a temporary file.
*
* Parameters:
* usebackq [I] - Indicates whether usebackq is in effect or not
* itemStr [I] - The item to be handled, either a filename or
* whole command string to execute
* iscmd [I] - Identifies whether this is a command or not
*
* Returns a file handle which can be used to read the input lines from.
*/
static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd)
{
WCHAR *trimmed = NULL;
FILE* ret;
/* Remove leading and trailing character (but there may be trailing whitespace too) */
if ((iscmd && (itemstr[0] == '`' && usebackq)) ||
(iscmd && (itemstr[0] == '\'' && !usebackq)) ||
(!iscmd && (itemstr[0] == '"' && usebackq)))
{
trimmed = WCMD_strtrim(itemstr);
if (trimmed)
itemstr = trimmed;
itemstr[lstrlenW(itemstr)-1] = 0x00;
itemstr++;
}
if (iscmd)
{
WCHAR temp_cmd[MAXSTRING];
wsprintfW(temp_cmd, L"CMD.EXE /C %s", itemstr);
WINE_TRACE("Reading output of '%s'\n", wine_dbgstr_w(temp_cmd));
ret = _wpopen(temp_cmd, L"rt,ccs=unicode");
}
else
{
/* Open the file, read line by line and process */
WINE_TRACE("Reading input to parse from '%s'\n", wine_dbgstr_w(itemstr));
ret = _wfopen(itemstr, L"rt,ccs=unicode");
}
free(trimmed);
return ret;
}
/**************************************************************************
* WCMD_for
*
@ -2136,411 +1861,6 @@ static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd)
*
*/
static void WCMD_for_OLD (WCHAR *p, CMD_NODE **cmdList) {
WIN32_FIND_DATAW fd;
HANDLE hff;
int i;
const int in_len = lstrlenW(L"in");
CMD_NODE *setStart, *thisSet, *cmdStart, *cmdEnd;
WCHAR variable[4];
int varidx = -1;
WCHAR *firstCmd;
int thisDepth;
WCHAR optionsRoot[MAX_PATH];
DIRECTORY_STACK *dirsToWalk = NULL;
BOOL expandDirs = FALSE;
BOOL useNumbers = FALSE;
BOOL doFileset = FALSE;
BOOL doRecurse = FALSE;
BOOL doExecuted = FALSE; /* Has the 'do' part been executed */
LONG numbers[3] = {0,0,0}; /* Defaults to 0 in native */
int itemNum;
CMD_NODE *thisCmdStart;
int parameterNo = 0;
WCHAR forf_eol = 0;
int forf_skip = 0;
WCHAR forf_delims[256];
WCHAR forf_tokens[MAXSTRING];
BOOL forf_usebackq = FALSE;
/* Handle optional qualifiers (multiple are allowed) */
WCHAR *thisArg = WCMD_parameter(p, parameterNo++, NULL, FALSE, FALSE);
optionsRoot[0] = 0;
while (thisArg && *thisArg == '/') {
WINE_TRACE("Processing qualifier at %s\n", wine_dbgstr_w(thisArg));
thisArg++;
switch (towupper(*thisArg)) {
case 'D': expandDirs = TRUE; break;
case 'L': useNumbers = TRUE; break;
/* Recursive is special case - /R can have an optional path following it */
/* filenamesets are another special case - /F can have an optional options following it */
case 'R':
case 'F':
{
/* When recursing directories, use current directory as the starting point unless
subsequently overridden */
doRecurse = (towupper(*thisArg) == 'R');
if (doRecurse) GetCurrentDirectoryW(ARRAY_SIZE(optionsRoot), optionsRoot);
doFileset = (towupper(*thisArg) == 'F');
/* Retrieve next parameter to see if is root/options (raw form required
with for /f, or unquoted in for /r) */
thisArg = WCMD_parameter(p, parameterNo, NULL, doFileset, FALSE);
/* Next parm is either qualifier, path/options or variable -
only care about it if it is the path/options */
if (thisArg && *thisArg != '/' && *thisArg != '%') {
parameterNo++;
lstrcpyW(optionsRoot, thisArg);
}
break;
}
default:
WINE_FIXME("for qualifier '%c' unhandled\n", *thisArg);
}
/* Step to next token */
thisArg = WCMD_parameter(p, parameterNo++, NULL, FALSE, FALSE);
}
/* Ensure line continues with variable */
if (*thisArg != '%') {
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
return;
}
/* With for /f parse the options if provided */
if (doFileset) {
if (!WCMD_parse_forf_options(optionsRoot, &forf_eol, &forf_skip,
forf_delims, forf_tokens, &forf_usebackq))
{
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
return;
}
/* Set up the list of directories to recurse if we are going to */
} else if (doRecurse) {
/* Allocate memory, add to list */
dirsToWalk = WCMD_dir_stack_create(optionsRoot, NULL);
TRACE("Starting with root directory %s\n", wine_dbgstr_w(dirsToWalk->dirName));
}
/* Variable should follow */
lstrcpyW(variable, thisArg);
WINE_TRACE("Variable identified as %s\n", wine_dbgstr_w(variable));
varidx = for_var_char_to_index(variable[1]);
/* Ensure line continues with IN */
thisArg = WCMD_parameter(p, parameterNo++, NULL, FALSE, FALSE);
if (!thisArg
|| !(CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
thisArg, in_len, L"in", in_len) == CSTR_EQUAL)) {
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
return;
}
/* Save away where the set of data starts and the variable */
thisDepth = CMD_node_get_depth(*cmdList);
*cmdList = CMD_node_next(*cmdList);
setStart = (*cmdList);
/* Skip until the close bracket */
WINE_TRACE("Searching %p as the set\n", *cmdList);
while (*cmdList &&
CMD_node_get_command(*cmdList)->command != NULL &&
CMD_node_get_depth(*cmdList) > thisDepth) {
WINE_TRACE("Skipping %p which is part of the set\n", *cmdList);
*cmdList = CMD_node_next(*cmdList);
}
/* Skip the close bracket, if there is one */
if (*cmdList) *cmdList = CMD_node_next(*cmdList);
/* Syntax error if missing close bracket, or nothing following it
and once we have the complete set, we expect a DO */
WINE_TRACE("Looking for 'do ' in %p\n", *cmdList);
if ((*cmdList == NULL) || !WCMD_keyword_ws_found(L"do", CMD_node_get_command(*cmdList)->command)) {
WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
return;
}
cmdEnd = *cmdList;
/* Loop repeatedly per-directory we are potentially walking, when in for /r
mode, or once for the rest of the time. */
do {
/* Save away the starting position for the commands (and offset for the
first one) */
cmdStart = *cmdList;
firstCmd = CMD_node_get_command(*cmdList)->command + 3; /* Skip 'do ' */
itemNum = 0;
/* If we are recursing directories (ie /R), add all sub directories now, then
prefix the root when searching for the item */
if (dirsToWalk) WCMD_add_dirstowalk(dirsToWalk);
thisSet = setStart;
/* Loop through all set entries */
while (thisSet &&
CMD_node_get_command(thisSet)->command != NULL &&
CMD_node_get_depth(thisSet) >= thisDepth) {
/* Loop through all entries on the same line */
WCHAR *staticitem;
WCHAR *itemStart;
WCHAR buffer[MAXSTRING];
WINE_TRACE("Processing for set %p\n", thisSet);
i = 0;
while (*(staticitem = WCMD_parameter (CMD_node_get_command(thisSet)->command, i, &itemStart, TRUE, FALSE))) {
/*
* If the parameter within the set has a wildcard then search for matching files
* otherwise do a literal substitution.
*/
/* Take a copy of the item returned from WCMD_parameter as it is held in a
static buffer which can be overwritten during parsing of the for body */
WCHAR item[MAXSTRING];
lstrcpyW(item, staticitem);
thisCmdStart = cmdStart;
itemNum++;
WINE_TRACE("Processing for item %d '%s'\n", itemNum, wine_dbgstr_w(item));
if (!useNumbers && !doFileset) {
WCHAR fullitem[MAX_PATH];
int prefixlen = 0;
/* Now build the item to use / search for in the specified directory,
as it is fully qualified in the /R case */
if (dirsToWalk) {
lstrcpyW(fullitem, dirsToWalk->dirName);
lstrcatW(fullitem, L"\\");
lstrcatW(fullitem, item);
} else {
WCHAR *prefix = wcsrchr(item, '\\');
if (prefix) prefixlen = (prefix - item) + 1;
lstrcpyW(fullitem, item);
}
if (wcspbrk(fullitem, L"*?")) {
hff = FindFirstFileW(fullitem, &fd);
if (hff != INVALID_HANDLE_VALUE) {
do {
BOOL isDirectory = FALSE;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) isDirectory = TRUE;
/* Handle as files or dirs appropriately, but ignore . and .. */
if (isDirectory == expandDirs &&
(lstrcmpW(fd.cFileName, L"..") != 0) && (lstrcmpW(fd.cFileName, L".") != 0))
{
thisCmdStart = cmdStart;
WINE_TRACE("Processing FOR filename %s\n", wine_dbgstr_w(fd.cFileName));
if (doRecurse) {
if (wcslen(dirsToWalk->dirName) + 1 + wcslen(fd.cFileName) >= MAX_PATH)
{
WINE_TRACE("Skipping too long path %s\\%s\n",
debugstr_w(dirsToWalk->dirName), debugstr_w(fd.cFileName));
continue;
}
lstrcpyW(fullitem, dirsToWalk->dirName);
lstrcatW(fullitem, L"\\");
lstrcatW(fullitem, fd.cFileName);
} else {
if (prefixlen) lstrcpynW(fullitem, item, prefixlen + 1);
fullitem[prefixlen] = 0x00;
lstrcatW(fullitem, fd.cFileName);
}
doExecuted = TRUE;
WCMD_save_for_loop_context(FALSE);
/* Save away any existing for variable context (e.g. nested for loops)
and restore it after executing the body of this for loop */
if (varidx >= 0)
WCMD_set_for_loop_variable(varidx, fullitem);
WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE);
WCMD_restore_for_loop_context();
cmdEnd = thisCmdStart;
}
} while (FindNextFileW(hff, &fd) != 0);
FindClose (hff);
}
} else {
doExecuted = TRUE;
WCMD_save_for_loop_context(FALSE);
/* Save away any existing for variable context (e.g. nested for loops)
and restore it after executing the body of this for loop */
if (varidx >= 0)
WCMD_set_for_loop_variable(varidx, fullitem);
WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE);
WCMD_restore_for_loop_context();
cmdEnd = thisCmdStart;
}
} else if (useNumbers) {
/* Convert the first 3 numbers to signed longs and save */
if (itemNum <=3) numbers[itemNum-1] = wcstol(item, NULL, 10);
/* else ignore them! */
/* Filesets - either a list of files, or a command to run and parse the output */
} else if (doFileset && ((!forf_usebackq && *itemStart != '"') ||
(forf_usebackq && *itemStart != '\''))) {
FILE *input;
WCHAR *itemparm;
WINE_TRACE("Processing for filespec from item %d '%s'\n", itemNum,
wine_dbgstr_w(item));
/* If backquote or single quote, we need to launch that command
and parse the results - use a temporary file */
if ((forf_usebackq && *itemStart == '`') ||
(!forf_usebackq && *itemStart == '\'')) {
/* Use itemstart because the command is the whole set, not just the first token */
itemparm = itemStart;
} else {
/* Use item because the file to process is just the first item in the set */
itemparm = item;
}
input = WCMD_forf_getinput(forf_usebackq, itemparm, (itemparm==itemStart));
/* Process the input file */
if (!input) {
WCMD_print_error ();
WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), item);
errorlevel = 1;
return; /* FOR loop aborts at first failure here */
} else {
/* Read line by line until end of file */
while (fgetws(buffer, ARRAY_SIZE(buffer), input)) {
size_t len = wcslen(buffer);
/* Either our buffer isn't large enough to fit a full line, or there's a stray
* '\0' in the buffer.
*/
if (!feof(input) && (len == 0 || (buffer[len - 1] != '\n' && buffer[len - 1] != '\r')))
break;
while (len && (buffer[len - 1] == '\n' || buffer[len - 1] == '\r'))
buffer[--len] = L'\0';
WCMD_parse_line(cmdStart, firstCmd, &cmdEnd, for_var_char_to_index(variable[1]), buffer, &doExecuted,
&forf_skip, forf_eol, forf_delims, forf_tokens);
buffer[0] = 0;
}
fclose (input);
}
/* When we have processed the item as a whole command, abort future set processing */
if (itemparm==itemStart) {
thisSet = NULL;
break;
}
/* Filesets - A string literal */
} else if (doFileset && ((!forf_usebackq && *itemStart == '"') ||
(forf_usebackq && *itemStart == '\''))) {
/* Remove leading and trailing character, ready to parse with delims= delimiters
Note that the last quote is removed from the set and the string terminates
there to mimic windows */
WCHAR *strend = wcsrchr(itemStart, forf_usebackq?'\'':'"');
if (strend) {
*strend = 0x00;
itemStart++;
}
/* Copy the item away from the global buffer used by WCMD_parameter */
lstrcpyW(buffer, itemStart);
WCMD_parse_line(cmdStart, firstCmd, &cmdEnd, for_var_char_to_index(variable[1]), buffer, &doExecuted,
&forf_skip, forf_eol, forf_delims, forf_tokens);
/* Only one string can be supplied in the whole set, abort future set processing */
thisSet = NULL;
break;
}
WINE_TRACE("Post-command, cmdEnd = %p\n", cmdEnd);
i++;
}
/* Move onto the next set line */
if (thisSet) thisSet = CMD_node_next(thisSet);
}
/* If /L is provided, now run the for loop */
if (useNumbers) {
WCHAR thisNum[20];
WINE_TRACE("FOR /L provided range from %ld to %ld step %ld\n",
numbers[0], numbers[2], numbers[1]);
for (i=numbers[0];
(numbers[1]<0)? i>=numbers[2] : i<=numbers[2];
i=i + numbers[1]) {
swprintf(thisNum, ARRAY_SIZE(thisNum), L"%d", i);
WINE_TRACE("Processing FOR number %s\n", wine_dbgstr_w(thisNum));
thisCmdStart = cmdStart;
doExecuted = TRUE;
/* Save away any existing for variable context (e.g. nested for loops)
and restore it after executing the body of this for loop */
if (varidx >= 0)
{
WCMD_save_for_loop_context(FALSE);
WCMD_set_for_loop_variable(varidx, thisNum);
}
WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE);
if (varidx >= 0)
WCMD_restore_for_loop_context();
}
cmdEnd = thisCmdStart;
}
/* If we are walking directories, move on to any which remain */
if (dirsToWalk != NULL) {
dirsToWalk = WCMD_dir_stack_free(dirsToWalk);
if (dirsToWalk) WINE_TRACE("Moving to next directory to iterate: %s\n",
wine_dbgstr_w(dirsToWalk->dirName));
else WINE_TRACE("Finished all directories.\n");
}
} while (dirsToWalk != NULL);
/* Now skip over the do part if we did not perform the for loop so far.
We store in cmdEnd the next command after the do block, but we only
know this if something was run. If it has not been, we need to calculate
it. */
if (!doExecuted) {
thisCmdStart = cmdStart;
WINE_TRACE("Skipping for loop commands due to no valid iterations\n");
WCMD_part_execute(&thisCmdStart, firstCmd, FALSE, FALSE);
cmdEnd = thisCmdStart;
}
/* When the loop ends, either something like a GOTO or EXIT /b has terminated
all processing, OR it should be pointing to the end of && processing OR
it should be pointing at the NULL end of bracket for the DO. The return
value needs to be the NEXT command to execute, which it either is, or
we need to step over the closing bracket */
*cmdList = cmdEnd;
if (cmdEnd && CMD_node_get_command(cmdEnd)->command == NULL) *cmdList = CMD_node_next(cmdEnd);
}
void WCMD_for(WCHAR *p, CMD_NODE **cmdList)
{
CMD_FOR_CONTROL *for_ctrl;
@ -2548,8 +1868,7 @@ void WCMD_for(WCHAR *p, CMD_NODE **cmdList)
for_ctrl = for_control_parse(p);
if (!for_ctrl)
{
/* temporary code: use OLD code for non migrated FOR constructs */
WCMD_for_OLD(p, cmdList);
*cmdList = NULL;
return;
}

View File

@ -610,8 +610,8 @@ N
''
'.eh'@or_broken@''
"foo bar"
@todo_wine@foo
@todo_wine@bar
foo
bar
--- in digit variables
a %1 %2
b %1 %2

View File

@ -83,16 +83,20 @@ typedef struct _CMD_IF_CONDITION
};
} CMD_IF_CONDITION;
#define CMD_FOR_FLAG_TREE_RECURSE (1u << 0)
#define CMD_FOR_FLAG_TREE_INCLUDE_FILES (1u << 1)
#define CMD_FOR_FLAG_TREE_INCLUDE_DIRECTORIES (1u << 2)
typedef struct _CMD_FOR_CONTROL
{
enum for_control_operator {
CMD_FOR_FILE_SET /* /F */,
enum for_control_operator {CMD_FOR_FILETREE, CMD_FOR_FILE_SET /* /F */,
CMD_FOR_NUMBERS /* /L */} operator;
unsigned flags; /* |-ed CMD_FOR_FLAG_* */
int variable_index;
const WCHAR *set;
union
{
const WCHAR *root_dir; /* for CMD_FOR_FILETREE */
struct /* for CMD_FOR_FILE_SET */
{
WCHAR eol;
@ -164,6 +168,10 @@ int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
BOOL *duplicates);
void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
BOOL isIF, BOOL executecmds);
struct _DIRECTORY_STACK;
void WCMD_add_dirstowalk(struct _DIRECTORY_STACK *dirsToWalk);
struct _DIRECTORY_STACK *WCMD_dir_stack_create(const WCHAR *dir, const WCHAR *file);
struct _DIRECTORY_STACK *WCMD_dir_stack_free(struct _DIRECTORY_STACK *dir);
void WCMD_assoc (const WCHAR *, BOOL);
void WCMD_batch (WCHAR *, WCHAR *, BOOL, WCHAR *, HANDLE);

View File

@ -1000,6 +1000,9 @@ void for_control_dispose(CMD_FOR_CONTROL *for_ctrl)
free((void*)for_ctrl->delims);
free((void*)for_ctrl->tokens);
break;
case CMD_FOR_FILETREE:
free((void*)for_ctrl->root_dir);
break;
default:
break;
}
@ -1007,7 +1010,7 @@ void for_control_dispose(CMD_FOR_CONTROL *for_ctrl)
const char *debugstr_for_control(const CMD_FOR_CONTROL *for_ctrl)
{
static const char* for_ctrl_strings[] = {"file", "numbers"};
static const char* for_ctrl_strings[] = {"tree", "file", "numbers"};
const char *flags, *options;
if (for_ctrl->operator >= ARRAY_SIZE(for_ctrl_strings))
@ -1016,9 +1019,18 @@ const char *debugstr_for_control(const CMD_FOR_CONTROL *for_ctrl)
return wine_dbg_sprintf("<<%u>>", for_ctrl->operator);
}
flags = "";
if (for_ctrl->flags)
flags = wine_dbg_sprintf("flags=%s%s%s ",
(for_ctrl->flags & CMD_FOR_FLAG_TREE_RECURSE) ? "~recurse" : "",
(for_ctrl->flags & CMD_FOR_FLAG_TREE_INCLUDE_FILES) ? "~+files" : "",
(for_ctrl->flags & CMD_FOR_FLAG_TREE_INCLUDE_DIRECTORIES) ? "~+dirs" : "");
else
flags = "";
switch (for_ctrl->operator)
{
case CMD_FOR_FILETREE:
options = wine_dbg_sprintf("root=(%ls) ", for_ctrl->root_dir);
break;
case CMD_FOR_FILE_SET:
{
WCHAR eol_buf[4] = {L'\'', for_ctrl->eol, L'\'', L'\0'};
@ -1045,6 +1057,9 @@ void for_control_create(enum for_control_operator for_op, unsigned flags, const
for_ctrl->set = NULL;
switch (for_ctrl->operator)
{
case CMD_FOR_FILETREE:
for_ctrl->root_dir = options && *options ? xstrdupW(options) : NULL;
break;
default:
break;
}
@ -2239,6 +2254,22 @@ CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var)
}
switch (mode)
{
case L' ':
for_op = CMD_FOR_FILETREE;
flags = CMD_FOR_FLAG_TREE_INCLUDE_FILES;
break;
case L'D':
for_op = CMD_FOR_FILETREE;
flags = CMD_FOR_FLAG_TREE_INCLUDE_DIRECTORIES;
break;
case L'X':
for_op = CMD_FOR_FILETREE;
flags = CMD_FOR_FLAG_TREE_INCLUDE_DIRECTORIES | CMD_FOR_FLAG_TREE_RECURSE;
break;
case L'R':
for_op = CMD_FOR_FILETREE;
flags = CMD_FOR_FLAG_TREE_INCLUDE_FILES | /*CMD_FOR_FLAG_TREE_INCLUDE_DIRECTORIES | */CMD_FOR_FLAG_TREE_RECURSE;
break;
case L'L':
for_op = CMD_FOR_NUMBERS;
break;
@ -2246,10 +2277,11 @@ CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var)
for_op = CMD_FOR_FILE_SET;
break;
default:
FIXME("Unexpected situation\n");
return NULL;
}
if (mode == L'F')
if (mode == L'F' || mode == L'R')
{
/* Retrieve next parameter to see if is root/options (raw form required
* with for /f, or unquoted in for /r)
@ -3205,6 +3237,109 @@ static CMD_NODE *for_control_execute_fileset(CMD_FOR_CONTROL *for_ctrl, CMD_NODE
return body;
}
static CMD_NODE *for_control_execute_set(CMD_FOR_CONTROL *for_ctrl, const WCHAR *from_dir, size_t ref_len, CMD_NODE *cmdList)
{
CMD_NODE *body = NULL;
size_t len;
WCHAR set[MAXSTRING];
WCHAR buffer[MAX_PATH];
int i;
if (from_dir)
{
len = wcslen(from_dir) + 1;
if (len >= ARRAY_SIZE(buffer)) return NULL;
wcscpy(buffer, from_dir);
wcscat(buffer, L"\\");
}
else
len = 0;
wcscpy(set, for_ctrl->set);
handleExpansion(set, context != NULL, delayedsubst);
for (i = 0; ; i++)
{
WCHAR *element = WCMD_parameter(set, i, NULL, TRUE, FALSE);
if (!element || !*element) break;
if (len + wcslen(element) + 1 >= ARRAY_SIZE(buffer)) continue;
wcscpy(&buffer[len], element);
TRACE("Doing set element %ls\n", buffer);
if (wcspbrk(element, L"?*"))
{
WIN32_FIND_DATAW fd;
HANDLE hff = FindFirstFileW(buffer, &fd);
size_t insert_pos = (wcsrchr(buffer, L'\\') ? wcsrchr(buffer, L'\\') + 1 - buffer : 0);
if (hff == INVALID_HANDLE_VALUE)
{
TRACE("Couldn't FindFirstFile on %ls\n", buffer);
continue;
}
do
{
TRACE("Considering %ls\n", fd.cFileName);
if (!lstrcmpW(fd.cFileName, L"..") || !lstrcmpW(fd.cFileName, L".")) continue;
if (!(for_ctrl->flags & CMD_FOR_FLAG_TREE_INCLUDE_FILES) &&
!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
continue;
if (!(for_ctrl->flags & CMD_FOR_FLAG_TREE_INCLUDE_DIRECTORIES) &&
(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
continue;
if (insert_pos + wcslen(fd.cFileName) + 1 >= ARRAY_SIZE(buffer)) continue;
wcscpy(&buffer[insert_pos], fd.cFileName);
body = cmdList;
WCMD_set_for_loop_variable(for_ctrl->variable_index, buffer);
WCMD_part_execute(&body, CMD_node_get_command(body)->command + 3, FALSE, TRUE);
} while (FindNextFileW(hff, &fd) != 0);
FindClose(hff);
}
else
{
body = cmdList;
WCMD_set_for_loop_variable(for_ctrl->variable_index, buffer);
WCMD_part_execute(&body, CMD_node_get_command(body)->command + 3, FALSE, TRUE);
}
}
return body;
}
static CMD_NODE *for_control_execute_walk_files(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *cmdList)
{
DIRECTORY_STACK *dirs_to_walk;
size_t ref_len;
CMD_NODE *body = NULL;
if (for_ctrl->root_dir)
{
WCHAR buffer[MAXSTRING];
wcscpy(buffer, for_ctrl->root_dir);
handleExpansion(buffer, context != NULL, delayedsubst);
dirs_to_walk = WCMD_dir_stack_create(buffer, NULL);
}
else dirs_to_walk = WCMD_dir_stack_create(NULL, NULL);
ref_len = wcslen(dirs_to_walk->dirName);
while (dirs_to_walk)
{
TRACE("About to walk %p %ls for %s\n", dirs_to_walk, dirs_to_walk->dirName, debugstr_for_control(for_ctrl));
if (for_ctrl->flags & CMD_FOR_FLAG_TREE_RECURSE)
WCMD_add_dirstowalk(dirs_to_walk);
body = for_control_execute_set(for_ctrl, dirs_to_walk->dirName, ref_len, cmdList);
/* If we are walking directories, move on to any which remain */
dirs_to_walk = WCMD_dir_stack_free(dirs_to_walk);
}
TRACE("Finished all directories.\n");
return body;
}
static CMD_NODE *for_control_execute_numbers(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *cmdList)
{
WCHAR set[MAXSTRING];
@ -3250,6 +3385,12 @@ void for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE **cmdList)
switch (for_ctrl->operator)
{
case CMD_FOR_FILETREE:
if (for_ctrl->flags & CMD_FOR_FLAG_TREE_RECURSE)
last = for_control_execute_walk_files(for_ctrl, *cmdList);
else
last = for_control_execute_set(for_ctrl, NULL, 0, *cmdList);
break;
case CMD_FOR_FILE_SET:
last = for_control_execute_fileset(for_ctrl, *cmdList);
break;

View File

@ -439,11 +439,14 @@ void init_directories( struct fd *intl_fd )
/* mappings */
static const WCHAR intlW[] = {'N','l','s','S','e','c','t','i','o','n','L','A','N','G','_','I','N','T','L'};
static const WCHAR user_dataW[] = {'_','_','w','i','n','e','_','u','s','e','r','_','s','h','a','r','e','d','_','d','a','t','a'};
static const WCHAR sessionW[] = {'_','_','w','i','n','e','_','s','e','s','s','i','o','n'};
static const struct unicode_str intl_str = {intlW, sizeof(intlW)};
static const struct unicode_str user_data_str = {user_dataW, sizeof(user_dataW)};
static const struct unicode_str session_str = {sessionW, sizeof(sessionW)};
struct directory *dir_driver, *dir_device, *dir_global, *dir_kernel, *dir_nls;
struct object *named_pipe_device, *mailslot_device, *null_device;
struct mapping *session_mapping;
unsigned int i;
root_directory = create_directory( NULL, NULL, OBJ_PERMANENT, HASH_SIZE, NULL );
@ -491,6 +494,10 @@ void init_directories( struct fd *intl_fd )
release_object( create_user_data_mapping( &dir_kernel->obj, &user_data_str, OBJ_PERMANENT, NULL ));
release_object( intl_fd );
session_mapping = create_session_mapping( &dir_kernel->obj, &session_str, OBJ_PERMANENT, NULL );
set_session_mapping( session_mapping );
release_object( session_mapping );
release_object( named_pipe_device );
release_object( mailslot_device );
release_object( null_device );

View File

@ -188,6 +188,29 @@ extern struct mapping *create_fd_mapping( struct object *root, const struct unic
unsigned int attr, const struct security_descriptor *sd );
extern struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd );
extern struct mapping *create_session_mapping( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd );
extern void set_session_mapping( struct mapping *mapping );
extern const volatile void *alloc_shared_object(void);
extern void free_shared_object( const volatile void *object_shm );
extern obj_locator_t get_shared_object_locator( const volatile void *object_shm );
#define SHARED_WRITE_BEGIN( object_shm, type ) \
do { \
const type *__shared = (object_shm); \
type *shared = (type *)__shared; \
shared_object_t *__obj = CONTAINING_RECORD( shared, shared_object_t, shm ); \
LONG64 __seq = __obj->seq + 1, __end = __seq + 1; \
assert( (__seq & 1) != 0 ); \
__WINE_ATOMIC_STORE_RELEASE( &__obj->seq, &__seq ); \
do
#define SHARED_WRITE_END \
while(0); \
assert( __seq == __obj->seq ); \
__WINE_ATOMIC_STORE_RELEASE( &__obj->seq, &__end ); \
} while(0)
/* device functions */

View File

@ -225,6 +225,36 @@ static const mem_size_t granularity_mask = 0xffff;
static struct addr_range ranges32;
static struct addr_range ranges64;
struct session_block
{
struct list entry; /* entry in the session block list */
const char *data; /* base pointer for the mmaped data */
mem_size_t offset; /* offset of data in the session shared mapping */
mem_size_t used_size; /* used size for previously allocated objects */
mem_size_t block_size; /* total size of the block */
};
struct session_object
{
struct list entry; /* entry in the session free object list */
mem_size_t offset; /* offset of obj in the session shared mapping */
shared_object_t obj; /* object actually shared with the client */
};
struct session
{
struct list blocks;
struct list free_objects;
object_id_t last_object_id;
};
static struct mapping *session_mapping;
static struct session session =
{
.blocks = LIST_INIT(session.blocks),
.free_objects = LIST_INIT(session.free_objects),
};
#define ROUND_SIZE(size) (((size) + page_mask) & ~page_mask)
void init_memory(void)
@ -1256,6 +1286,134 @@ int get_page_size(void)
return page_mask + 1;
}
struct mapping *create_session_mapping( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd )
{
static const unsigned int access = FILE_READ_DATA | FILE_WRITE_DATA;
mem_size_t size = max( sizeof(shared_object_t) * 512, 0x10000 );
return create_mapping( root, name, attr, size, SEC_COMMIT, 0, access, sd );
}
void set_session_mapping( struct mapping *mapping )
{
int unix_fd = get_unix_fd( mapping->fd );
mem_size_t size = mapping->size;
struct session_block *block;
void *tmp;
if (!(block = mem_alloc( sizeof(*block) ))) return;
if ((tmp = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, unix_fd, 0 )) == MAP_FAILED)
{
free( block );
return;
}
block->data = tmp;
block->offset = 0;
block->used_size = 0;
block->block_size = size;
session_mapping = mapping;
list_add_tail( &session.blocks, &block->entry );
}
static struct session_block *grow_session_mapping( mem_size_t needed )
{
mem_size_t old_size = session_mapping->size, new_size;
struct session_block *block;
int unix_fd;
void *tmp;
new_size = max( old_size * 3 / 2, old_size + max( needed, 0x10000 ) );
new_size = (new_size + page_mask) & ~((mem_size_t)page_mask);
assert( new_size > old_size );
unix_fd = get_unix_fd( session_mapping->fd );
if (!grow_file( unix_fd, new_size )) return NULL;
if (!(block = mem_alloc( sizeof(*block) ))) return NULL;
if ((tmp = mmap( NULL, new_size - old_size, PROT_READ | PROT_WRITE, MAP_SHARED, unix_fd, old_size )) == MAP_FAILED)
{
file_set_error();
free( block );
return NULL;
}
block->data = tmp;
block->offset = old_size;
block->used_size = 0;
block->block_size = new_size - old_size;
session_mapping->size = new_size;
list_add_tail( &session.blocks, &block->entry );
return block;
}
static struct session_block *find_free_session_block( mem_size_t size )
{
struct session_block *block;
LIST_FOR_EACH_ENTRY( block, &session.blocks, struct session_block, entry )
if (size < block->block_size && block->used_size < block->block_size - size) return block;
return grow_session_mapping( size );
}
const volatile void *alloc_shared_object(void)
{
struct session_object *object;
struct list *ptr;
if ((ptr = list_head( &session.free_objects )))
{
object = CONTAINING_RECORD( ptr, struct session_object, entry );
list_remove( &object->entry );
}
else
{
mem_size_t size = sizeof(*object);
struct session_block *block;
if (!(block = find_free_session_block( size ))) return NULL;
object = (struct session_object *)(block->data + block->used_size);
object->offset = (char *)&object->obj - block->data;
block->used_size += size;
}
SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t )
{
/* mark the object data as uninitialized */
mark_block_uninitialized( (void *)shared, sizeof(*shared) );
CONTAINING_RECORD( shared, shared_object_t, shm )->id = ++session.last_object_id;
}
SHARED_WRITE_END;
return &object->obj.shm;
}
void free_shared_object( const volatile void *object_shm )
{
struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm );
SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t )
{
mark_block_noaccess( (void *)shared, sizeof(*shared) );
CONTAINING_RECORD( shared, shared_object_t, shm )->id = 0;
}
SHARED_WRITE_END;
list_add_tail( &session.free_objects, &object->entry );
}
obj_locator_t get_shared_object_locator( const volatile void *object_shm )
{
struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm );
obj_locator_t locator = {.offset = object->offset, .id = object->obj.id};
return locator;
}
struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd )
{

View File

@ -102,8 +102,19 @@ void close_objects(void)
/*****************************************************************/
/* mark a block of memory as not accessible for debugging purposes */
void mark_block_noaccess( void *ptr, size_t size )
{
memset( ptr, 0xfe, size );
#if defined(VALGRIND_MAKE_MEM_NOACCESS)
VALGRIND_DISCARD( VALGRIND_MAKE_MEM_NOACCESS( ptr, size ) );
#elif defined(VALGRIND_MAKE_NOACCESS)
VALGRIND_DISCARD( VALGRIND_MAKE_NOACCESS( ptr, size ) );
#endif
}
/* mark a block of memory as uninitialized for debugging purposes */
static inline void mark_block_uninitialized( void *ptr, size_t size )
void mark_block_uninitialized( void *ptr, size_t size )
{
memset( ptr, 0x55, size );
#if defined(VALGRIND_MAKE_MEM_UNDEFINED)

View File

@ -139,6 +139,8 @@ struct wait_queue_entry
struct thread_wait *wait;
};
extern void mark_block_noaccess( void *ptr, size_t size );
extern void mark_block_uninitialized( void *ptr, size_t size );
extern void *mem_alloc( size_t size ) __WINE_ALLOC_SIZE(1) __WINE_DEALLOC(free) __WINE_MALLOC;
extern void *memdup( const void *data, size_t len ) __WINE_ALLOC_SIZE(2) __WINE_DEALLOC(free);
extern void *alloc_object( const struct object_ops *ops );

View File

@ -45,6 +45,7 @@ typedef unsigned __int64 mem_size_t;
typedef unsigned __int64 file_pos_t;
typedef unsigned __int64 client_ptr_t;
typedef unsigned __int64 affinity_t;
typedef unsigned __int64 object_id_t;
typedef client_ptr_t mod_handle_t;
struct request_header
@ -895,6 +896,39 @@ struct directory_entry
/* VARARG(type,unicode_str,type_len); */
};
/****************************************************************/
/* shared session mapping structures */
struct shared_cursor
{
int x; /* cursor position */
int y;
unsigned int last_change; /* time of last position change */
};
typedef volatile struct
{
struct shared_cursor cursor; /* global cursor information */
} desktop_shm_t;
typedef volatile union
{
desktop_shm_t desktop;
} object_shm_t;
typedef volatile struct
{
LONG64 seq; /* sequence number - server updating if (seq & 1) != 0 */
object_id_t id; /* object unique id, object data is valid if != 0 */
object_shm_t shm; /* object shared data */
} shared_object_t;
typedef struct
{
object_id_t id; /* object unique id, object data is valid if != 0 */
mem_size_t offset; /* offset of the object in session shared memory */
} obj_locator_t;
/****************************************************************/
/* Request declarations */
@ -2792,13 +2826,16 @@ enum coords_relative
@REQ(get_thread_desktop)
thread_id_t tid; /* thread id */
@REPLY
obj_handle_t handle; /* handle to the desktop */
obj_locator_t locator; /* locator for the shared session object */
obj_handle_t handle; /* handle to the desktop */
@END
/* Set the thread current desktop */
@REQ(set_thread_desktop)
obj_handle_t handle; /* handle to the desktop */
@REPLY
obj_locator_t locator; /* locator for the shared session object */
@END

View File

@ -419,6 +419,7 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un
lparam_t wparam, lparam_t lparam )
{
static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM };
const desktop_shm_t *desktop_shm = desktop->shared;
struct thread_input *input;
struct message *msg;
@ -427,8 +428,8 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un
msg->msg = message;
msg->wparam = wparam;
msg->lparam = lparam;
msg->x = desktop->cursor.x;
msg->y = desktop->cursor.y;
msg->x = desktop_shm->cursor.x;
msg->y = desktop_shm->cursor.y;
if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->active;
queue_hardware_message( desktop, msg, 1 );
}
@ -466,14 +467,21 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t
static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y )
{
const desktop_shm_t *desktop_shm = desktop->shared;
int updated;
unsigned int time = get_tick_count();
x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left );
y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top );
updated = (desktop->cursor.x != x || desktop->cursor.y != y);
desktop->cursor.x = x;
desktop->cursor.y = y;
desktop->cursor.last_change = get_tick_count();
SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t )
{
updated = shared->cursor.x != x || shared->cursor.y != y;
shared->cursor.x = x;
shared->cursor.y = y;
shared->cursor.last_change = time;
}
SHARED_WRITE_END;
if (!win || !is_window_visible( win ) || is_window_transparent( win ))
win = shallow_window_from_point( desktop, x, y );
@ -518,15 +526,17 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y )
static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time )
{
struct desktop *desktop = queue->input->desktop;
const desktop_shm_t *desktop_shm = desktop->shared;
*x = desktop->cursor.x;
*y = desktop->cursor.y;
*x = desktop_shm->cursor.x;
*y = desktop_shm->cursor.y;
*time = get_tick_count();
}
/* set the cursor clip rectangle */
void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset )
{
const desktop_shm_t *desktop_shm = desktop->shared;
rectangle_t top_rect;
unsigned int old_flags;
int x, y;
@ -548,9 +558,9 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsig
desktop->cursor.clip_flags = flags;
/* warp the mouse to be inside the clip rect */
x = max( min( desktop->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left );
y = max( min( desktop->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top );
if (x != desktop->cursor.x || y != desktop->cursor.y) set_cursor_pos( desktop, x, y );
x = max( min( desktop_shm->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left );
y = max( min( desktop_shm->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top );
if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y );
/* request clip cursor rectangle reset to the desktop thread */
if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE );
@ -1672,6 +1682,7 @@ static unsigned int get_rawinput_device_flags( struct process *process, struct m
/* queue a hardware message into a given thread input */
static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue )
{
const desktop_shm_t *desktop_shm = desktop->shared;
user_handle_t win;
struct thread *thread;
struct thread_input *input;
@ -1705,8 +1716,8 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg
if (desktop->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2;
break;
}
msg->x = desktop->cursor.x;
msg->y = desktop->cursor.y;
msg->x = desktop_shm->cursor.x;
msg->y = desktop_shm->cursor.y;
if (msg->win && (thread = get_window_thread( msg->win )))
{
@ -1982,11 +1993,12 @@ static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_
static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input,
unsigned int origin, struct msg_queue *sender )
{
const desktop_shm_t *desktop_shm = desktop->shared;
struct hardware_msg_data *msg_data;
struct rawinput_message raw_msg;
struct message *msg;
struct thread *foreground;
unsigned int i, time, flags;
unsigned int i, time = get_tick_count(), flags;
struct hw_msg_source source = { IMDT_MOUSE, origin };
lparam_t wparam = input->mouse.data << 16;
int wait = 0, x, y;
@ -2008,10 +2020,15 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
WM_MOUSEHWHEEL /* 0x1000 = MOUSEEVENTF_HWHEEL */
};
desktop->cursor.last_change = get_tick_count();
SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t )
{
shared->cursor.last_change = time;
}
SHARED_WRITE_END;
flags = input->mouse.flags;
time = input->mouse.time;
if (!time) time = desktop->cursor.last_change;
if (!time) time = desktop_shm->cursor.last_change;
if (flags & MOUSEEVENTF_MOVE)
{
@ -2020,19 +2037,19 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
x = input->mouse.x;
y = input->mouse.y;
if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) &&
x == desktop->cursor.x && y == desktop->cursor.y)
x == desktop_shm->cursor.x && y == desktop_shm->cursor.y)
flags &= ~MOUSEEVENTF_MOVE;
}
else
{
x = desktop->cursor.x + input->mouse.x;
y = desktop->cursor.y + input->mouse.y;
x = desktop_shm->cursor.x + input->mouse.x;
y = desktop_shm->cursor.y + input->mouse.y;
}
}
else
{
x = desktop->cursor.x;
y = desktop->cursor.y;
x = desktop_shm->cursor.x;
y = desktop_shm->cursor.y;
}
if ((foreground = get_foreground_thread( desktop, win )))
@ -2043,7 +2060,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
raw_msg.time = time;
raw_msg.message = WM_INPUT;
raw_msg.flags = flags;
rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop->cursor.x, y - desktop->cursor.y,
rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop_shm->cursor.x, y - desktop_shm->cursor.y,
raw_msg.flags, input->mouse.data, input->mouse.info );
dispatch_rawinput_message( desktop, &raw_msg );
@ -2293,6 +2310,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;
unsigned int i, wparam = input->hw.wparam;
timeout_t time = get_tick_count();
@ -2315,8 +2333,8 @@ static void queue_pointer_message( struct pointer *pointer, int repeated )
msg->msg = messages[input->hw.msg - WM_POINTERUPDATE][i];
msg->wparam = wparam;
msg->lparam = MAKELONG(x, y);
msg->x = desktop->cursor.x;
msg->y = desktop->cursor.y;
msg->x = desktop_shm->cursor.x;
msg->y = desktop_shm->cursor.y;
queue_hardware_message( desktop, msg, 1 );
}
@ -2371,6 +2389,7 @@ static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned i
static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win,
unsigned int origin, const hw_input_t *input )
{
const desktop_shm_t *desktop_shm = desktop->shared;
struct hw_msg_source source = { IMDT_UNAVAILABLE, origin };
struct thread *foreground;
struct pointer *pointer;
@ -2415,8 +2434,8 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_
msg->msg = input->hw.msg;
msg->wparam = input->hw.wparam;
msg->lparam = input->hw.lparam;
msg->x = desktop->cursor.x;
msg->y = desktop->cursor.y;
msg->x = desktop_shm->cursor.x;
msg->y = desktop_shm->cursor.y;
queue_hardware_message( desktop, msg, 1 );
}
@ -2964,6 +2983,7 @@ DECL_HANDLER(send_hardware_message)
struct desktop *desktop;
unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE);
struct msg_queue *sender = req->flags & SEND_HWMSG_INJECTED ? get_current_queue() : NULL;
const desktop_shm_t *desktop_shm;
int wait = 0;
if (!(desktop = get_hardware_input_desktop( req->win ))) return;
@ -2974,9 +2994,10 @@ DECL_HANDLER(send_hardware_message)
set_error( STATUS_ACCESS_DENIED );
return;
}
desktop_shm = desktop->shared;
reply->prev_x = desktop->cursor.x;
reply->prev_y = desktop->cursor.y;
reply->prev_x = desktop_shm->cursor.x;
reply->prev_y = desktop_shm->cursor.y;
switch (req->input.type)
{
@ -2994,8 +3015,8 @@ DECL_HANDLER(send_hardware_message)
}
reply->wait = sender ? wait : 0;
reply->new_x = desktop->cursor.x;
reply->new_y = desktop->cursor.y;
reply->new_x = desktop_shm->cursor.x;
reply->new_y = desktop_shm->cursor.y;
release_object( desktop );
}
@ -3688,16 +3709,18 @@ DECL_HANDLER(set_cursor)
user_handle_t prev_cursor, new_cursor;
struct thread_input *input;
struct desktop *desktop;
const desktop_shm_t *desktop_shm;
if (!queue) return;
input = queue->input;
desktop = input->desktop;
desktop_shm = desktop->shared;
prev_cursor = input->cursor_count < 0 ? 0 : input->cursor;
reply->prev_handle = input->cursor;
reply->prev_count = input->cursor_count;
reply->prev_x = desktop->cursor.x;
reply->prev_y = desktop->cursor.y;
reply->prev_x = desktop_shm->cursor.x;
reply->prev_y = desktop_shm->cursor.y;
if (req->flags & SET_CURSOR_HANDLE)
{
@ -3720,10 +3743,10 @@ DECL_HANDLER(set_cursor)
new_cursor = input->cursor_count < 0 ? 0 : input->cursor;
if (prev_cursor != new_cursor) update_desktop_cursor_handle( desktop, input, new_cursor );
reply->new_x = desktop->cursor.x;
reply->new_y = desktop->cursor.y;
reply->new_x = desktop_shm->cursor.x;
reply->new_y = desktop_shm->cursor.y;
reply->new_clip = desktop->cursor.clip;
reply->last_change = desktop->cursor.last_change;
reply->last_change = desktop_shm->cursor.last_change;
}
/* Get the history of the 64 last cursor positions */

View File

@ -721,6 +721,8 @@ C_ASSERT( sizeof(mem_size_t) == 8 );
C_ASSERT( sizeof(message_data_t) == 48 );
C_ASSERT( sizeof(mod_handle_t) == 8 );
C_ASSERT( sizeof(obj_handle_t) == 4 );
C_ASSERT( sizeof(obj_locator_t) == 16 );
C_ASSERT( sizeof(object_id_t) == 8 );
C_ASSERT( sizeof(pe_image_info_t) == 88 );
C_ASSERT( sizeof(process_id_t) == 4 );
C_ASSERT( sizeof(property_data_t) == 16 );
@ -1744,10 +1746,13 @@ C_ASSERT( FIELD_OFFSET(struct close_desktop_request, handle) == 12 );
C_ASSERT( sizeof(struct close_desktop_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_thread_desktop_request, tid) == 12 );
C_ASSERT( sizeof(struct get_thread_desktop_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_thread_desktop_reply, handle) == 8 );
C_ASSERT( sizeof(struct get_thread_desktop_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_thread_desktop_reply, locator) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_thread_desktop_reply, handle) == 24 );
C_ASSERT( sizeof(struct get_thread_desktop_reply) == 32 );
C_ASSERT( FIELD_OFFSET(struct set_thread_desktop_request, handle) == 12 );
C_ASSERT( sizeof(struct set_thread_desktop_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_thread_desktop_reply, locator) == 8 );
C_ASSERT( sizeof(struct set_thread_desktop_reply) == 24 );
C_ASSERT( FIELD_OFFSET(struct enum_desktop_request, winstation) == 12 );
C_ASSERT( FIELD_OFFSET(struct enum_desktop_request, index) == 16 );
C_ASSERT( sizeof(struct enum_desktop_request) == 24 );

View File

@ -467,6 +467,14 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input )
}
}
static void dump_obj_locator( const char *prefix, const obj_locator_t *locator )
{
fprintf( stderr, "%s{", prefix );
dump_uint64( "id=", &locator->id );
dump_uint64( ",offset=", &locator->offset );
fprintf( stderr, "}" );
}
static void dump_luid( const char *prefix, const struct luid *luid )
{
fprintf( stderr, "%s%d.%u", prefix, luid->high_part, luid->low_part );
@ -3426,7 +3434,8 @@ static void dump_get_thread_desktop_request( const struct get_thread_desktop_req
static void dump_get_thread_desktop_reply( const struct get_thread_desktop_reply *req )
{
fprintf( stderr, " handle=%04x", req->handle );
dump_obj_locator( " locator=", &req->locator );
fprintf( stderr, ", handle=%04x", req->handle );
}
static void dump_set_thread_desktop_request( const struct set_thread_desktop_request *req )
@ -3434,6 +3443,11 @@ static void dump_set_thread_desktop_request( const struct set_thread_desktop_req
fprintf( stderr, " handle=%04x", req->handle );
}
static void dump_set_thread_desktop_reply( const struct set_thread_desktop_reply *req )
{
dump_obj_locator( " locator=", &req->locator );
}
static void dump_enum_desktop_request( const struct enum_desktop_request *req )
{
fprintf( stderr, " winstation=%04x", req->winstation );
@ -5101,7 +5115,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
NULL,
NULL,
(dump_func)dump_get_thread_desktop_reply,
NULL,
(dump_func)dump_set_thread_desktop_reply,
(dump_func)dump_enum_desktop_reply,
(dump_func)dump_set_user_object_info_reply,
(dump_func)dump_register_hotkey_reply,

View File

@ -56,11 +56,8 @@ struct winstation
struct global_cursor
{
int x; /* cursor position */
int y;
rectangle_t clip; /* cursor clip rectangle */
unsigned int clip_flags; /* last cursor clip flags */
unsigned int last_change; /* time of last position change */
user_handle_t win; /* window that contains the cursor */
};
@ -93,6 +90,7 @@ struct desktop
struct global_cursor cursor; /* global cursor information */
unsigned char keystate[256]; /* asynchronous key state */
struct key_repeat key_repeat; /* key auto-repeat */
const desktop_shm_t *shared; /* desktop session shared memory */
};
/* user handles functions */

View File

@ -298,6 +298,20 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned
list_add_tail( &winstation->desktops, &desktop->entry );
list_init( &desktop->hotkeys );
list_init( &desktop->pointers );
if (!(desktop->shared = alloc_shared_object()))
{
release_object( desktop );
return NULL;
}
SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t )
{
shared->cursor.x = 0;
shared->cursor.y = 0;
shared->cursor.last_change = 0;
}
SHARED_WRITE_END;
}
else
{
@ -368,6 +382,7 @@ static void desktop_destroy( struct object *obj )
if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout );
if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout );
release_object( desktop->winstation );
if (desktop->shared) free_shared_object( desktop->shared );
}
/* retrieve the thread desktop, checking the handle access rights */
@ -735,10 +750,19 @@ DECL_HANDLER(close_desktop)
/* get the thread current desktop */
DECL_HANDLER(get_thread_desktop)
{
struct desktop *desktop;
struct thread *thread;
if (!(thread = get_thread_from_id( req->tid ))) return;
reply->handle = thread->desktop;
if (!(desktop = get_thread_desktop( thread, 0 ))) clear_error();
else
{
if (desktop->shared) reply->locator = get_shared_object_locator( desktop->shared );
release_object( desktop );
}
release_object( thread );
}
@ -781,6 +805,7 @@ DECL_HANDLER(set_thread_desktop)
if (old_desktop) remove_desktop_thread( old_desktop, current );
add_desktop_thread( new_desktop, current );
}
reply->locator = get_shared_object_locator( new_desktop->shared );
}
if (!current->process->desktop)

View File

@ -42,6 +42,7 @@ my %formats =
"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" ],
@ -52,6 +53,7 @@ my %formats =
"generic_map_t" => [ 16, 4, "&dump_generic_map" ],
"ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ],
"hw_input_t" => [ 40, 8, "&dump_hw_input" ],
"obj_locator_t" => [ 16, 8, "&dump_obj_locator" ],
# varargs-only structures
"apc_call_t" => [ 64, 8 ],
"context_t" => [ 1728, 8 ],