diff --git a/configure.ac b/configure.ac
index 8e4462b1d4c..22229880023 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1994,6 +1994,7 @@ AC_CHECK_FUNCS(\
getrandom \
kqueue \
mach_continuous_time \
+ memfd_create \
pipe2 \
port_create \
posix_fadvise \
@@ -3579,6 +3580,7 @@ WINE_CONFIG_MAKEFILE(po)
WINE_CONFIG_MAKEFILE(programs/arp)
WINE_CONFIG_MAKEFILE(programs/aspnet_regiis)
WINE_CONFIG_MAKEFILE(programs/attrib)
+WINE_CONFIG_MAKEFILE(programs/belauncher)
WINE_CONFIG_MAKEFILE(programs/cabarc)
WINE_CONFIG_MAKEFILE(programs/cacls)
WINE_CONFIG_MAKEFILE(programs/chcp.com)
diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h
index 20fef455f00..9b521de75b8 100644
--- a/dlls/amd_ags_x64/amd_ags.h
+++ b/dlls/amd_ags_x64/amd_ags.h
@@ -1506,8 +1506,10 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* con
/// \param [in] minDepth The near depth range to clip against.
/// \param [in] maxDepth The far depth range to clip against.
///
-AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds_520( AGSContext* context, bool enabled, float minDepth, float maxDepth );
-AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth );
+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, bool enabled, float minDepth, float maxDepth );
+
+/* Since 5.3.0 */
+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds_530( AGSContext* context, ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth );
/// @}
diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec
index ebb026da35e..3d9800469a1 100644
--- a/dlls/amd_ags_x64/amd_ags_x64.spec
+++ b/dlls/amd_ags_x64/amd_ags_x64.spec
@@ -3,14 +3,14 @@
@ stdcall agsCheckDriverVersion(ptr long)
@ stub agsDriverExtensionsDX11_BeginUAVOverlap
@ stub agsDriverExtensionsDX11_CreateBuffer
-@ stub agsDriverExtensionsDX11_CreateDevice
+@ stdcall agsDriverExtensionsDX11_CreateDevice(ptr ptr ptr ptr)
@ stub agsDriverExtensionsDX11_CreateFromDevice
@ stub agsDriverExtensionsDX11_CreateTexture1D
@ stub agsDriverExtensionsDX11_CreateTexture2D
@ stub agsDriverExtensionsDX11_CreateTexture3D
@ stub agsDriverExtensionsDX11_DeInit
@ stub agsDriverExtensionsDX11_Destroy
-@ stub agsDriverExtensionsDX11_DestroyDevice
+@ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_DestroyDevice()
@ stub agsDriverExtensionsDX11_EndUAVOverlap
@ stub agsDriverExtensionsDX11_GetMaxClipRects
@ stub agsDriverExtensionsDX11_IASetPrimitiveTopology
@@ -24,7 +24,7 @@
@ stub agsDriverExtensionsDX11_NotifyResourceEndWrites
@ stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs
@ stub agsDriverExtensionsDX11_SetClipRects
-@ stub agsDriverExtensionsDX11_SetDepthBounds
+@ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_SetDepthBounds() DX11_SetDepthBounds_impl
@ stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled
@ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount
@ stub agsDriverExtensionsDX11_SetViewBroadcastMasks
diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c
index 24b16021acf..b58926c928c 100644
--- a/dlls/amd_ags_x64/amd_ags_x64_main.c
+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c
@@ -8,6 +8,7 @@
#include "wine/heap.h"
#include "wine/vulkan.h"
+#include "wine/asm.h"
#define COBJMACROS
#include "d3d11.h"
@@ -38,18 +39,19 @@ static const struct
int minor;
int patch;
unsigned int device_size;
+ unsigned int dx11_returned_params_size;
}
amd_ags_info[AMD_AGS_VERSION_COUNT] =
{
- {5, 1, 1, sizeof(AGSDeviceInfo_511)},
- {5, 2, 0, sizeof(AGSDeviceInfo_520)},
- {5, 2, 1, sizeof(AGSDeviceInfo_520)},
- {5, 3, 0, sizeof(AGSDeviceInfo_520)},
- {5, 4, 0, sizeof(AGSDeviceInfo_540)},
- {5, 4, 1, sizeof(AGSDeviceInfo_541)},
- {5, 4, 2, sizeof(AGSDeviceInfo_542)},
- {6, 0, 0, sizeof(AGSDeviceInfo_600)},
- {6, 0, 1, sizeof(AGSDeviceInfo_600)},
+ {5, 1, 1, sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511)},
+ {5, 2, 0, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520)},
+ {5, 2, 1, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520)},
+ {5, 3, 0, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520)},
+ {5, 4, 0, sizeof(AGSDeviceInfo_540), sizeof(AGSDX11ReturnedParams_520)},
+ {5, 4, 1, sizeof(AGSDeviceInfo_541), sizeof(AGSDX11ReturnedParams_520)},
+ {5, 4, 2, sizeof(AGSDeviceInfo_542), sizeof(AGSDX11ReturnedParams_520)},
+ {6, 0, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)},
+ {6, 0, 1, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)},
};
#define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \
@@ -117,8 +119,10 @@ struct AGSContext
VkPhysicalDeviceMemoryProperties *memory_properties;
};
-static HMODULE hd3d12;
+static HMODULE hd3d11, hd3d12;
static typeof(D3D12CreateDevice) *pD3D12CreateDevice;
+static typeof(D3D11CreateDevice) *pD3D11CreateDevice;
+static typeof(D3D11CreateDeviceAndSwapChain) *pD3D11CreateDeviceAndSwapChain;
static BOOL load_d3d12_functions(void)
{
@@ -132,6 +136,19 @@ static BOOL load_d3d12_functions(void)
return TRUE;
}
+static BOOL load_d3d11_functions(void)
+{
+ if (hd3d11)
+ return TRUE;
+
+ if (!(hd3d11 = LoadLibraryA("d3d11.dll")))
+ return FALSE;
+
+ pD3D11CreateDevice = (void *)GetProcAddress(hd3d11, "D3D11CreateDevice");
+ pD3D11CreateDeviceAndSwapChain = (void *)GetProcAddress(hd3d11, "D3D11CreateDeviceAndSwapChain");
+ return TRUE;
+}
+
static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count,
VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory)
{
@@ -605,6 +622,76 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count
return AGS_SUCCESS;
}
+AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context,
+ const AGSDX11DeviceCreationParams* creation_params, const AGSDX11ExtensionParams* extension_params,
+ AGSDX11ReturnedParams* returned_params )
+{
+ ID3D11DeviceContext *device_context;
+ IDXGISwapChain *swapchain = NULL;
+ D3D_FEATURE_LEVEL feature_level;
+ ID3D11Device *device;
+ HRESULT hr;
+
+ TRACE("feature levels %u, pSwapChainDesc %p, app %s, engine %s %#x %#x.\n", creation_params->FeatureLevels,
+ creation_params->pSwapChainDesc,
+ debugstr_w(extension_params->agsDX11ExtensionParams511.pAppName),
+ debugstr_w(extension_params->agsDX11ExtensionParams511.pEngineName),
+ extension_params->agsDX11ExtensionParams511.appVersion,
+ extension_params->agsDX11ExtensionParams511.engineVersion);
+
+ if (!load_d3d11_functions())
+ {
+ ERR("Could not load d3d11.dll.\n");
+ return AGS_MISSING_D3D_DLL;
+ }
+ memset( returned_params, 0, amd_ags_info[context->version].dx11_returned_params_size );
+ if (creation_params->pSwapChainDesc)
+ {
+ hr = pD3D11CreateDeviceAndSwapChain(creation_params->pAdapter, creation_params->DriverType,
+ creation_params->Software, creation_params->Flags, creation_params->pFeatureLevels,
+ creation_params->FeatureLevels, creation_params->SDKVersion, creation_params->pSwapChainDesc,
+ &swapchain, &device, &feature_level, &device_context);
+ }
+ else
+ {
+ hr = pD3D11CreateDevice(creation_params->pAdapter, creation_params->DriverType,
+ creation_params->Software, creation_params->Flags, creation_params->pFeatureLevels,
+ creation_params->FeatureLevels, creation_params->SDKVersion,
+ &device, &feature_level, &device_context);
+ }
+ if (FAILED(hr))
+ {
+ ERR("Device creation failed, hr %#x.\n", hr);
+ return AGS_DX_FAILURE;
+ }
+ if (context->version < AMD_AGS_VERSION_5_2_0)
+ {
+ AGSDX11ReturnedParams_511 *r = &returned_params->agsDX11ReturnedParams511;
+ r->pDevice = device;
+ r->pImmediateContext = device_context;
+ r->pSwapChain = swapchain;
+ r->FeatureLevel = feature_level;
+ }
+ else if (context->version < AMD_AGS_VERSION_6_0_0)
+ {
+ AGSDX11ReturnedParams_520 *r = &returned_params->agsDX11ReturnedParams520;
+ r->pDevice = device;
+ r->pImmediateContext = device_context;
+ r->pSwapChain = swapchain;
+ r->FeatureLevel = feature_level;
+ }
+ else
+ {
+ AGSDX11ReturnedParams_600 *r = &returned_params->agsDX11ReturnedParams600;
+ r->pDevice = device;
+ r->pImmediateContext = device_context;
+ r->pSwapChain = swapchain;
+ r->featureLevel = feature_level;
+ }
+
+ return AGS_SUCCESS;
+}
+
AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context,
const AGSDX12DeviceCreationParams *creation_params, const AGSDX12ExtensionParams *extension_params,
AGSDX12ReturnedParams *returned_params)
@@ -684,3 +771,71 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
return TRUE;
}
+
+#ifdef __x86_64__
+AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds(AGSContext* context, bool enabled,
+ float minDepth, float maxDepth )
+{
+ static int once;
+
+ if (!once++)
+ FIXME("context %p, enabled %#x, minDepth %f, maxDepth %f stub.\n", context, enabled, minDepth, maxDepth);
+ return AGS_EXTENSION_NOT_SUPPORTED;
+}
+
+AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds_530(AGSContext* context,
+ ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth )
+{
+ static int once;
+
+ if (!once++)
+ FIXME("context %p, enabled %#x, minDepth %f, maxDepth %f stub.\n", context, enabled, minDepth, maxDepth);
+ return AGS_EXTENSION_NOT_SUPPORTED;
+}
+
+__ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl,
+ "mov (%rcx),%eax\n\t" /* version */
+ "cmp $3,%eax\n\t"
+ "jge 1f\n\t"
+ "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t"
+ "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") )
+
+AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_520(AGSContext *context, ID3D11Device* device,
+ unsigned int *device_ref, ID3D11DeviceContext *device_context,
+ unsigned int *context_ref)
+{
+ ULONG ref;
+
+ TRACE("context %p, device %p, device_ref %p, device_context %p, context_ref %p.\n",
+ context, device, device_ref, device_context, context_ref);
+
+ if (!device)
+ return AGS_SUCCESS;
+
+ ref = ID3D11Device_Release(device);
+ if (device_ref)
+ *device_ref = ref;
+
+ if (!device_context)
+ return AGS_SUCCESS;
+
+ ref = ID3D11DeviceContext_Release(device_context);
+ if (context_ref)
+ *context_ref = ref;
+ return AGS_SUCCESS;
+}
+
+AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_511(AGSContext *context, ID3D11Device *device,
+ unsigned int *references )
+{
+ TRACE("context %p, device %p, references %p.\n", context, device, references);
+
+ return agsDriverExtensionsDX11_DestroyDevice_520(context, device, references, NULL, NULL);
+}
+__ASM_GLOBAL_FUNC( agsDriverExtensionsDX11_DestroyDevice,
+ "mov (%rcx),%eax\n\t" /* version */
+ "cmp $1,%eax\n\t"
+ "jge 1f\n\t"
+ "jmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_511") "\n\t"
+ "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_520") )
+#endif
diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c
index fd02404b7af..507217ffdda 100644
--- a/dlls/evr/presenter.c
+++ b/dlls/evr/presenter.c
@@ -65,6 +65,7 @@ struct sample_queue
unsigned int used;
unsigned int front;
unsigned int back;
+ IMFSample *last_presented;
};
struct streaming_thread
@@ -120,6 +121,7 @@ struct video_presenter
struct
{
int presented;
+ LONGLONG sampletime;
} frame_stats;
CRITICAL_SECTION cs;
@@ -507,6 +509,13 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM
IDirect3DSwapChain9_Present(presenter->swapchain, NULL, NULL, NULL, NULL, 0);
presenter->frame_stats.presented++;
+ EnterCriticalSection(&presenter->cs);
+ if (presenter->thread.queue.last_presented)
+ IMFSample_Release(presenter->thread.queue.last_presented);
+ presenter->thread.queue.last_presented = sample;
+ IMFSample_AddRef(presenter->thread.queue.last_presented);
+ LeaveCriticalSection(&presenter->cs);
+
IDirect3DDevice9_Release(device);
IDirect3DSurface9_Release(backbuffer);
IDirect3DSurface9_Release(surface);
@@ -739,6 +748,8 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter)
TRACE("Terminated streaming thread tid %#x.\n", presenter->thread.tid);
+ if (presenter->thread.queue.last_presented)
+ IMFSample_Release(presenter->thread.queue.last_presented);
memset(&presenter->thread, 0, sizeof(presenter->thread));
video_presenter_set_allocator_callback(presenter, NULL);
@@ -1461,9 +1472,88 @@ static HRESULT WINAPI video_presenter_control_RepaintVideo(IMFVideoDisplayContro
static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayControl *iface, BITMAPINFOHEADER *header,
BYTE **dib, DWORD *dib_size, LONGLONG *timestamp)
{
- FIXME("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp);
+ struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface);
+ IDirect3DSurface9 *readback = NULL, *surface;
+ D3DSURFACE_DESC surface_desc;
+ D3DLOCKED_RECT mapped_rect;
+ IDirect3DDevice9 *device;
+ IMFSample *sample;
+ LONG stride;
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp);
+
+ EnterCriticalSection(&presenter->cs);
+
+ sample = presenter->thread.queue.last_presented;
+ presenter->thread.queue.last_presented = NULL;
+
+ if (!presenter->swapchain || !sample)
+ {
+ hr = MF_E_INVALIDREQUEST;
+ }
+ else if (SUCCEEDED(hr = video_presenter_get_sample_surface(sample, &surface)))
+ {
+ IDirect3DSwapChain9_GetDevice(presenter->swapchain, &device);
+ IDirect3DSurface9_GetDesc(surface, &surface_desc);
+
+ if (surface_desc.Format != D3DFMT_X8R8G8B8)
+ {
+ FIXME("Unexpected surface format %d.\n", surface_desc.Format);
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (FAILED(hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, surface_desc.Width,
+ surface_desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &readback, NULL)))
+ {
+ WARN("Failed to create readback surface, hr %#x.\n", hr);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IDirect3DDevice9_GetRenderTargetData(device, surface, readback);
+
+ if (SUCCEEDED(hr))
+ {
+ MFGetStrideForBitmapInfoHeader(D3DFMT_X8R8G8B8, surface_desc.Width, &stride);
+ *dib_size = abs(stride) * surface_desc.Height;
+ if (!(*dib = CoTaskMemAlloc(*dib_size)))
+ hr = E_OUTOFMEMORY;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(readback, &mapped_rect, NULL, D3DLOCK_READONLY)))
+ {
+ memcpy(*dib, mapped_rect.pBits, *dib_size);
+ IDirect3DSurface9_UnlockRect(readback);
+ }
+ }
+
+ memset(header, 0, sizeof(*header));
+ header->biSize = sizeof(*header);
+ header->biWidth = surface_desc.Width;
+ header->biHeight = surface_desc.Height;
+ header->biPlanes = 1;
+ header->biBitCount = 32;
+ header->biSizeImage = *dib_size;
+ IMFSample_GetSampleTime(sample, timestamp);
+
+ if (readback)
+ IDirect3DSurface9_Release(readback);
+ IDirect3DSurface9_Release(surface);
+
+ IDirect3DDevice9_Release(device);
+ }
+
+ if (sample)
+ IMFSample_Release(sample);
+
+ LeaveCriticalSection(&presenter->cs);
+
+ return hr;
}
static HRESULT WINAPI video_presenter_control_SetBorderColor(IMFVideoDisplayControl *iface, COLORREF color)
diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in
index 0a4cb8dd334..0ff7c511eb4 100644
--- a/dlls/hnetcfg/Makefile.in
+++ b/dlls/hnetcfg/Makefile.in
@@ -1,6 +1,6 @@
MODULE = hnetcfg.dll
IMPORTS = oleaut32 ole32 advapi32 mpr uuid
-
+DELAYIMPORTS = ws2_32 winhttp shcore xmllite
EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \
diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c
index b6447cf4d63..9f0b30cd28a 100644
--- a/dlls/hnetcfg/apps.c
+++ b/dlls/hnetcfg/apps.c
@@ -29,7 +29,6 @@
#include "natupnp.h"
#include "wine/debug.h"
-#include "wine/heap.h"
#include "hnetcfg_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg);
@@ -62,7 +61,7 @@ static ULONG WINAPI fw_app_Release(
{
TRACE("destroying %p\n", fw_app);
SysFreeString( fw_app->filename );
- HeapFree( GetProcessHeap(), 0, fw_app );
+ free( fw_app );
}
return refs;
}
@@ -115,7 +114,9 @@ static REFIID tid_id[] =
&IID_INetFwPolicy,
&IID_INetFwPolicy2,
&IID_INetFwProfile,
- &IID_IUPnPNAT
+ &IID_IUPnPNAT,
+ &IID_IStaticPortMappingCollection,
+ &IID_IStaticPortMapping,
};
HRESULT get_typeinfo( enum type_id tid, ITypeInfo **ret )
@@ -269,7 +270,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName(
fw_app *This = impl_from_INetFwAuthorizedApplication( iface );
UNIVERSAL_NAME_INFOW *info;
DWORD sz, longsz;
- WCHAR *path;
+ WCHAR *path, *new_path;
DWORD res;
FIXME("%p, %s\n", This, debugstr_w(image));
@@ -281,7 +282,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName(
res = WNetGetUniversalNameW(image, UNIVERSAL_NAME_INFO_LEVEL, NULL, &sz);
if (res == WN_MORE_DATA)
{
- if (!(path = heap_alloc(sz)))
+ if (!(path = malloc(sz)))
return E_OUTOFMEMORY;
info = (UNIVERSAL_NAME_INFOW *)&path;
@@ -291,29 +292,30 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName(
SysFreeString(This->filename);
This->filename = SysAllocString(info->lpUniversalName);
}
- heap_free(path);
+ free(path);
return HRESULT_FROM_WIN32(res);
}
sz = GetFullPathNameW(image, 0, NULL, NULL);
- if (!(path = heap_alloc(++sz * sizeof(WCHAR))))
+ if (!(path = malloc(++sz * sizeof(WCHAR))))
return E_OUTOFMEMORY;
GetFullPathNameW(image, sz, path, NULL);
longsz = GetLongPathNameW(path, path, sz);
if (longsz > sz)
{
- if (!(path = heap_realloc(path, longsz * sizeof(WCHAR))))
+ if (!(new_path = realloc(path, longsz * sizeof(WCHAR))))
{
- heap_free(path);
+ free(path);
return E_OUTOFMEMORY;
}
+ path = new_path;
GetLongPathNameW(path, path, longsz);
}
SysFreeString( This->filename );
This->filename = SysAllocString(path);
- heap_free(path);
+ free(path);
return This->filename ? S_OK : E_OUTOFMEMORY;
}
@@ -432,7 +434,7 @@ HRESULT NetFwAuthorizedApplication_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fa = HeapAlloc( GetProcessHeap(), 0, sizeof(*fa) );
+ fa = malloc( sizeof(*fa) );
if (!fa) return E_OUTOFMEMORY;
fa->INetFwAuthorizedApplication_iface.lpVtbl = &fw_app_vtbl;
@@ -470,7 +472,7 @@ static ULONG WINAPI fw_apps_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_apps);
- HeapFree( GetProcessHeap(), 0, fw_apps );
+ free( fw_apps );
}
return refs;
}
@@ -645,7 +647,7 @@ HRESULT NetFwAuthorizedApplications_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fa = HeapAlloc( GetProcessHeap(), 0, sizeof(*fa) );
+ fa = malloc( sizeof(*fa) );
if (!fa) return E_OUTOFMEMORY;
fa->INetFwAuthorizedApplications_iface.lpVtbl = &fw_apps_vtbl;
diff --git a/dlls/hnetcfg/hnetcfg_private.h b/dlls/hnetcfg/hnetcfg_private.h
index be2d0f3c7c6..9e6c4ec9618 100644
--- a/dlls/hnetcfg/hnetcfg_private.h
+++ b/dlls/hnetcfg/hnetcfg_private.h
@@ -28,6 +28,8 @@ enum type_id
INetFwProfile_tid,
INetFwRules_tid,
IUPnPNAT_tid,
+ IStaticPortMappingCollection_tid,
+ IStaticPortMapping_tid,
last_tid
};
diff --git a/dlls/hnetcfg/manager.c b/dlls/hnetcfg/manager.c
index 2c0790a73b5..fda69729901 100644
--- a/dlls/hnetcfg/manager.c
+++ b/dlls/hnetcfg/manager.c
@@ -58,7 +58,7 @@ static ULONG WINAPI fw_manager_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_manager);
- HeapFree( GetProcessHeap(), 0, fw_manager );
+ free( fw_manager );
}
return refs;
}
@@ -244,7 +244,7 @@ HRESULT NetFwMgr_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fm = HeapAlloc( GetProcessHeap(), 0, sizeof(*fm) );
+ fm = malloc( sizeof(*fm) );
if (!fm) return E_OUTOFMEMORY;
fm->INetFwMgr_iface.lpVtbl = &fw_manager_vtbl;
diff --git a/dlls/hnetcfg/policy.c b/dlls/hnetcfg/policy.c
index 1f5b0daa568..7bdc1563d90 100644
--- a/dlls/hnetcfg/policy.c
+++ b/dlls/hnetcfg/policy.c
@@ -105,7 +105,7 @@ static ULONG WINAPI netfw_rules_Release(
if (!refs)
{
TRACE("destroying %p\n", This);
- HeapFree( GetProcessHeap(), 0, This );
+ free( This );
}
return refs;
}
@@ -265,7 +265,7 @@ static HRESULT create_INetFwRules(INetFwRules **object)
TRACE("(%p)\n", object);
- rules = HeapAlloc( GetProcessHeap(), 0, sizeof(*rules) );
+ rules = malloc( sizeof(*rules) );
if (!rules) return E_OUTOFMEMORY;
rules->INetFwRules_iface.lpVtbl = &fw_rules_vtbl;
@@ -292,7 +292,7 @@ static ULONG WINAPI fw_policy_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_policy);
- HeapFree( GetProcessHeap(), 0, fw_policy );
+ free( fw_policy );
}
return refs;
}
@@ -435,7 +435,7 @@ HRESULT NetFwPolicy_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwPolicy_iface.lpVtbl = &fw_policy_vtbl;
@@ -487,7 +487,7 @@ static ULONG WINAPI fwpolicy2_Release(INetFwPolicy2 *iface)
{
INetFwRules_Release(fw_policy->fw_policy2_rules);
TRACE("destroying %p\n", fw_policy);
- HeapFree( GetProcessHeap(), 0, fw_policy );
+ free( fw_policy );
}
return refs;
}
@@ -768,7 +768,7 @@ HRESULT NetFwPolicy2_create( IUnknown *outer, void **obj )
TRACE("(%p,%p)\n", outer, obj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwPolicy2_iface.lpVtbl = &fw_policy2_vtbl;
@@ -778,7 +778,7 @@ HRESULT NetFwPolicy2_create( IUnknown *outer, void **obj )
if (FAILED(create_INetFwRules(&fp->fw_policy2_rules)))
{
- HeapFree( GetProcessHeap(), 0, fp );
+ free( fp );
return E_OUTOFMEMORY;
}
diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c
index fd4ac4977d3..47bfc16be79 100644
--- a/dlls/hnetcfg/port.c
+++ b/dlls/hnetcfg/port.c
@@ -24,16 +24,1571 @@
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
+#include "string.h"
+#include "initguid.h"
+#include "assert.h"
+#include "winsock2.h"
+#include "winhttp.h"
+#include "shlwapi.h"
+#include "xmllite.h"
#include "ole2.h"
#include "netfw.h"
#include "natupnp.h"
-#include "wine/heap.h"
#include "wine/debug.h"
#include "hnetcfg_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg);
+struct port_mapping
+{
+ BSTR external_ip;
+ LONG external;
+ BSTR protocol;
+ LONG internal;
+ BSTR client;
+ VARIANT_BOOL enabled;
+ BSTR descr;
+};
+
+struct xml_value_desc
+{
+ const WCHAR *name;
+ BSTR value;
+};
+
+static struct
+{
+ LONG refs;
+ BOOL winsock_initialized;
+ WCHAR locationW[256];
+ HINTERNET session, connection;
+ WCHAR desc_urlpath[128];
+ WCHAR control_url[256];
+ unsigned int version;
+ struct port_mapping *mappings;
+ unsigned int mapping_count;
+}
+upnp_gateway_connection;
+
+static SRWLOCK upnp_gateway_connection_lock = SRWLOCK_INIT;
+
+static void free_port_mapping( struct port_mapping *mapping )
+{
+ SysFreeString( mapping->external_ip );
+ SysFreeString( mapping->protocol );
+ SysFreeString( mapping->client );
+ SysFreeString( mapping->descr );
+}
+
+static void free_mappings(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < upnp_gateway_connection.mapping_count; ++i)
+ free_port_mapping( &upnp_gateway_connection.mappings[i] );
+ free( upnp_gateway_connection.mappings );
+ upnp_gateway_connection.mappings = NULL;
+ upnp_gateway_connection.mapping_count = 0;
+}
+
+static BOOL copy_port_mapping( struct port_mapping *dst, const struct port_mapping *src )
+{
+ memset( dst, 0, sizeof(*dst) );
+
+#define COPY_BSTR_CHECK(name) if (src->name && !(dst->name = SysAllocString( src->name ))) \
+ { \
+ free_port_mapping( dst ); \
+ return FALSE; \
+ }
+
+ COPY_BSTR_CHECK( external_ip );
+ COPY_BSTR_CHECK( protocol );
+ COPY_BSTR_CHECK( client );
+ COPY_BSTR_CHECK( descr );
+#undef COPY_BSTR_CHECK
+
+ dst->external = src->external;
+ dst->internal = src->internal;
+ dst->enabled = src->enabled;
+ return TRUE;
+}
+
+static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned int location_size )
+{
+ char *saveptr = NULL, *tok, *tok2;
+ unsigned int status;
+
+ tok = strtok_s( response, "\n", &saveptr );
+ if (!tok) return FALSE;
+
+ /* HTTP/1.1 200 OK */
+ tok2 = strtok( tok, " " );
+ if (!tok2) return FALSE;
+ tok2 = strtok( NULL, " " );
+ if (!tok2) return FALSE;
+ status = atoi( tok2 );
+ if (status != HTTP_STATUS_OK)
+ {
+ WARN( "status %u.\n", status );
+ return FALSE;
+ }
+ while ((tok = strtok_s( NULL, "\n", &saveptr )))
+ {
+ tok2 = strtok( tok, " " );
+ if (!tok2) continue;
+ if (!stricmp( tok2, "LOCATION:" ))
+ {
+ tok2 = strtok( NULL, " \r" );
+ if (!tok2)
+ {
+ WARN( "Error parsing location.\n" );
+ return FALSE;
+ }
+ return !!MultiByteToWideChar( CP_UTF8, 0, tok2, -1, locationW, location_size / 2 );
+ }
+ }
+ return FALSE;
+}
+
+static BOOL parse_desc_xml( const char *desc_xml )
+{
+ static const WCHAR urn_wanipconnection[] = L"urn:schemas-upnp-org:service:WANIPConnection:";
+ WCHAR control_url[ARRAY_SIZE(upnp_gateway_connection.control_url)];
+ BOOL service_type_matches, control_url_found, found = FALSE;
+ unsigned int version = 0;
+ XmlNodeType node_type;
+ IXmlReader *reader;
+ const WCHAR *value;
+ BOOL ret = FALSE;
+ IStream *stream;
+ HRESULT hr;
+
+ if (!(stream = SHCreateMemStream( (BYTE *)desc_xml, strlen( desc_xml ) + 1 ))) return FALSE;
+ if (FAILED(hr = CreateXmlReader( &IID_IXmlReader, (void **)&reader, NULL )))
+ {
+ IStream_Release( stream );
+ return FALSE;
+ }
+ if (FAILED(hr = IXmlReader_SetInput( reader, (IUnknown*)stream ))) goto done;
+
+ while (SUCCEEDED(IXmlReader_Read( reader, &node_type )) && node_type != XmlNodeType_None)
+ {
+ if (node_type != XmlNodeType_Element) continue;
+
+ if (FAILED(IXmlReader_GetLocalName( reader, &value, NULL ))) goto done;
+ if (wcsicmp( value, L"service" )) continue;
+ control_url_found = service_type_matches = FALSE;
+ while (SUCCEEDED(IXmlReader_Read( reader, &node_type )))
+ {
+ if (node_type != XmlNodeType_Element && node_type != XmlNodeType_EndElement) continue;
+ if (FAILED(IXmlReader_GetLocalName( reader, &value, NULL )))
+ {
+ WARN( "IXmlReader_GetLocalName failed.\n" );
+ goto done;
+ }
+ if (node_type == XmlNodeType_EndElement)
+ {
+ if (!wcsicmp( value, L"service" )) break;
+ continue;
+ }
+ if (!wcsicmp( value, L"serviceType" ))
+ {
+ if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done;
+ if (node_type != XmlNodeType_Text) goto done;
+ if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done;
+ if (wcsnicmp( value, urn_wanipconnection, ARRAY_SIZE(urn_wanipconnection) - 1 )) break;
+ version = _wtoi( value + ARRAY_SIZE(urn_wanipconnection) - 1 );
+ service_type_matches = version >= 1;
+ }
+ else if (!wcsicmp( value, L"controlURL" ))
+ {
+ if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done;
+ if (node_type != XmlNodeType_Text) goto done;
+ if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done;
+ if (wcslen( value ) + 1 > ARRAY_SIZE(control_url)) goto done;
+ wcscpy( control_url, value );
+ control_url_found = TRUE;
+ }
+ }
+ if (service_type_matches && control_url_found)
+ {
+ if (found)
+ {
+ FIXME( "Found another WANIPConnection service, ignoring.\n" );
+ continue;
+ }
+ found = TRUE;
+ wcscpy( upnp_gateway_connection.control_url, control_url );
+ upnp_gateway_connection.version = version;
+ }
+ }
+
+ ret = found;
+done:
+ IXmlReader_Release( reader );
+ IStream_Release( stream );
+ return ret;
+}
+
+static BOOL get_xml_elements( const char *desc_xml, struct xml_value_desc *values, unsigned int value_count )
+{
+ XmlNodeType node_type;
+ IXmlReader *reader;
+ const WCHAR *value;
+ BOOL ret = FALSE;
+ IStream *stream;
+ unsigned int i;
+ HRESULT hr;
+
+ for (i = 0; i < value_count; ++i) assert( !values[i].value );
+
+ if (!(stream = SHCreateMemStream( (BYTE *)desc_xml, strlen( desc_xml ) + 1 ))) return FALSE;
+ if (FAILED(hr = CreateXmlReader( &IID_IXmlReader, (void **)&reader, NULL )))
+ {
+ IStream_Release( stream );
+ return FALSE;
+ }
+ if (FAILED(hr = IXmlReader_SetInput( reader, (IUnknown*)stream ))) goto done;
+
+ while (SUCCEEDED(IXmlReader_Read( reader, &node_type )) && node_type != XmlNodeType_None)
+ {
+ if (node_type != XmlNodeType_Element) continue;
+
+ if (FAILED(IXmlReader_GetQualifiedName( reader, &value, NULL ))) goto done;
+ for (i = 0; i < value_count; ++i)
+ if (!wcsicmp( value, values[i].name )) break;
+ if (i == value_count) continue;
+ if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done;
+ if (node_type != XmlNodeType_Text)
+ {
+ if (node_type == XmlNodeType_EndElement) value = L"";
+ else goto done;
+ }
+ else
+ {
+ if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done;
+ }
+ if (values[i].value)
+ {
+ WARN( "Duplicate value %s.\n", debugstr_w(values[i].name) );
+ goto done;
+ }
+ if (!(values[i].value = SysAllocString( value ))) goto done;
+ }
+ ret = TRUE;
+
+done:
+ if (!ret)
+ {
+ for (i = 0; i < value_count; ++i)
+ {
+ SysFreeString( values[i].value );
+ values[i].value = NULL;
+ }
+ }
+ IXmlReader_Release( reader );
+ IStream_Release( stream );
+ return ret;
+}
+
+static BOOL open_gateway_connection(void)
+{
+ static const int timeout = 3000;
+
+ WCHAR hostname[64];
+ URL_COMPONENTS url;
+
+ memset( &url, 0, sizeof(url) );
+ url.dwStructSize = sizeof(url);
+ url.lpszHostName = hostname;
+ url.dwHostNameLength = ARRAY_SIZE(hostname);
+ url.lpszUrlPath = upnp_gateway_connection.desc_urlpath;
+ url.dwUrlPathLength = ARRAY_SIZE(upnp_gateway_connection.desc_urlpath);
+
+ if (!WinHttpCrackUrl( upnp_gateway_connection.locationW, 0, 0, &url )) return FALSE;
+
+ upnp_gateway_connection.session = WinHttpOpen( L"hnetcfg", WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 );
+ if (!upnp_gateway_connection.session) return FALSE;
+ if (!WinHttpSetTimeouts( upnp_gateway_connection.session, timeout, timeout, timeout, timeout ))
+ return FALSE;
+
+ TRACE( "hostname %s, urlpath %s, port %u.\n",
+ debugstr_w(hostname), debugstr_w(upnp_gateway_connection.desc_urlpath), url.nPort );
+ upnp_gateway_connection.connection = WinHttpConnect ( upnp_gateway_connection.session, hostname, url.nPort, 0 );
+ if (!upnp_gateway_connection.connection)
+ {
+ WARN( "WinHttpConnect error %u.\n", GetLastError() );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL get_control_url(void)
+{
+ static const WCHAR *accept_types[] =
+ {
+ L"text/xml",
+ NULL
+ };
+ unsigned int desc_xml_size, offset;
+ DWORD size, status = 0;
+ HINTERNET request;
+ char *desc_xml;
+ BOOL ret;
+
+ request = WinHttpOpenRequest( upnp_gateway_connection.connection, NULL, upnp_gateway_connection.desc_urlpath, NULL,
+ WINHTTP_NO_REFERER, accept_types, 0 );
+ if (!request) return FALSE;
+
+ if (!WinHttpSendRequest( request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0 ))
+ {
+ WARN( "Error sending request %u.\n", GetLastError() );
+ WinHttpCloseHandle( request );
+ return FALSE;
+ }
+ if (!WinHttpReceiveResponse(request, NULL))
+ {
+ WARN( "Error receiving response %u.\n", GetLastError() );
+ WinHttpCloseHandle( request );
+ return FALSE;
+ }
+ size = sizeof(status);
+ if (!WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+ NULL, &status, &size, NULL) || status != HTTP_STATUS_OK )
+ {
+ WARN( "Error response from server, error %u, http status %u.\n", GetLastError(), status );
+ WinHttpCloseHandle( request );
+ return FALSE;
+ }
+ desc_xml_size = 1024;
+ desc_xml = malloc( desc_xml_size );
+ offset = 0;
+ while (WinHttpReadData( request, desc_xml + offset, desc_xml_size - offset - 1, &size ) && size)
+ {
+ offset += size;
+ if (offset + 1 == desc_xml_size)
+ {
+ char *new;
+
+ desc_xml_size *= 2;
+ if (!(new = realloc( desc_xml, desc_xml_size )))
+ {
+ ERR( "No memory.\n" );
+ break;
+ }
+ desc_xml = new;
+ }
+ }
+ desc_xml[offset] = 0;
+ WinHttpCloseHandle( request );
+ ret = parse_desc_xml( desc_xml );
+ free( desc_xml );
+ return ret;
+}
+
+static void gateway_connection_cleanup(void)
+{
+ TRACE( ".\n" );
+ free_mappings();
+ WinHttpCloseHandle( upnp_gateway_connection.connection );
+ WinHttpCloseHandle( upnp_gateway_connection.session );
+ if (upnp_gateway_connection.winsock_initialized) WSACleanup();
+ memset( &upnp_gateway_connection, 0, sizeof(upnp_gateway_connection) );
+}
+
+static BOOL request_service( const WCHAR *function, const struct xml_value_desc *request_param,
+ unsigned int request_param_count, struct xml_value_desc *result,
+ unsigned int result_count, DWORD *http_status, BSTR *server_error_code_str )
+{
+ static const char request_template_header[] =
+ "\r\n"
+ "\r\n"
+ " \r\n"
+ " \r\n";
+ static const char request_template_footer[] =
+ " \r\n"
+ " \r\n"
+ "\r\n";
+
+ unsigned int request_data_size, request_len, offset, i, reply_buffer_size;
+ char *request_data, *reply_buffer = NULL, *ptr;
+ struct xml_value_desc error_value_desc;
+ WCHAR request_headers[1024];
+ HINTERNET request = NULL;
+ BOOL ret = FALSE;
+ DWORD size;
+
+ *server_error_code_str = NULL;
+ request_data_size = strlen(request_template_header) + strlen(request_template_footer) + 2 * wcslen( function )
+ + 9 /* version + zero terminator */;
+ for (i = 0; i < request_param_count; ++i)
+ {
+ request_data_size += 13 + 2 * wcslen( request_param[i].name ) + wcslen( request_param[i].value );
+ }
+ if (!(request_data = malloc( request_data_size ))) return FALSE;
+
+ request = WinHttpOpenRequest( upnp_gateway_connection.connection, L"POST", upnp_gateway_connection.control_url,
+ NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0 );
+ if (!request) goto done;
+
+ ptr = request_data;
+ snprintf( ptr, request_data_size, request_template_header, function, upnp_gateway_connection.version );
+ offset = strlen( ptr );
+ ptr += offset;
+ request_data_size -= offset;
+ for (i = 0; i < request_param_count; ++i)
+ {
+ snprintf( ptr, request_data_size, " <%S>%S%S>\r\n",
+ request_param[i].name, request_param[i].value, request_param[i].name);
+ offset = strlen( ptr );
+ ptr += offset;
+ request_data_size -= offset;
+ }
+ snprintf( ptr, request_data_size, request_template_footer, function );
+
+ request_len = strlen( request_data );
+ swprintf( request_headers, ARRAY_SIZE(request_headers),
+ L"SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:%u#%s\"\r\n"
+ L"Content-Type: text/xml",
+ upnp_gateway_connection.version, function );
+ if (!WinHttpSendRequest( request, request_headers, -1, request_data, request_len, request_len, 0 ))
+ {
+ WARN( "Error sending request %u.\n", GetLastError() );
+ goto done;
+ }
+ if (!WinHttpReceiveResponse(request, NULL))
+ {
+ WARN( "Error receiving response %u.\n", GetLastError() );
+ goto done;
+ }
+ size = sizeof(*http_status);
+ if (!WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+ NULL, http_status, &size, NULL) || *http_status != HTTP_STATUS_OK )
+ {
+ if (*http_status != HTTP_STATUS_SERVER_ERROR)
+ {
+ ret = TRUE;
+ goto done;
+ }
+ }
+
+ offset = 0;
+ reply_buffer_size = 1024;
+ if (!(reply_buffer = malloc( reply_buffer_size ))) goto done;
+ while ((ret = WinHttpReadData( request, reply_buffer + offset, reply_buffer_size - offset - 1, &size )) && size)
+ {
+ offset += size;
+ if (offset + 1 == reply_buffer_size)
+ {
+ char *new;
+
+ reply_buffer_size *= 2;
+ if (!(new = realloc( reply_buffer, reply_buffer_size ))) goto done;
+ reply_buffer = new;
+ }
+ }
+ reply_buffer[offset] = 0;
+
+ if (*http_status == HTTP_STATUS_OK) ret = get_xml_elements( reply_buffer, result, result_count );
+ else
+ {
+ error_value_desc.name = L"errorCode";
+ error_value_desc.value = NULL;
+ if ((ret = get_xml_elements( reply_buffer, &error_value_desc, 1 )))
+ *server_error_code_str = error_value_desc.value;
+ }
+
+done:
+ free( reply_buffer );
+ free( request_data );
+ WinHttpCloseHandle( request );
+ return ret;
+}
+
+enum port_mapping_parameter
+{
+ PM_EXTERNAL_IP,
+ PM_EXTERNAL,
+ PM_PROTOCOL,
+ PM_INTERNAL,
+ PM_CLIENT,
+ PM_ENABLED,
+ PM_DESC,
+ PM_LEASE_DURATION,
+ PM_LAST,
+ PM_REMOVE_PORT_LAST = PM_INTERNAL,
+};
+
+static struct xml_value_desc port_mapping_template[] =
+{
+ { L"NewRemoteHost" },
+ { L"NewExternalPort" },
+ { L"NewProtocol" },
+ { L"NewInternalPort" },
+ { L"NewInternalClient" },
+ { L"NewEnabled" },
+ { L"NewPortMappingDescription" },
+ { L"NewLeaseDuration" },
+};
+
+static LONG long_from_bstr( BSTR s )
+{
+ if (!s) return 0;
+ return _wtoi( s );
+}
+
+static BSTR mapping_move_bstr( BSTR *s )
+{
+ BSTR ret;
+
+ if (*s)
+ {
+ ret = *s;
+ *s = NULL;
+ }
+ else if (!(ret = SysAllocString( L"" )))
+ {
+ ERR( "No memory.\n" );
+ }
+ return ret;
+}
+
+static void update_mapping_list(void)
+{
+ struct xml_value_desc mapping_desc[ARRAY_SIZE(port_mapping_template)];
+ struct xml_value_desc index_param;
+ struct port_mapping *new_mappings;
+ unsigned int i, index;
+ WCHAR index_str[9];
+ BSTR error_str;
+ DWORD status;
+ BOOL ret;
+
+ free_mappings();
+
+ index_param.name = L"NewPortMappingIndex";
+
+ index = 0;
+ while (1)
+ {
+ new_mappings = realloc( upnp_gateway_connection.mappings, (index + 1) * sizeof(*new_mappings) );
+ if (!new_mappings) break;
+ upnp_gateway_connection.mappings = new_mappings;
+
+ memcpy( mapping_desc, port_mapping_template, sizeof(mapping_desc) );
+ swprintf( index_str, ARRAY_SIZE(index_str), L"%u", index );
+ index_param.value = SysAllocString( index_str );
+ ret = request_service( L"GetGenericPortMappingEntry", &index_param, 1,
+ mapping_desc, ARRAY_SIZE(mapping_desc), &status, &error_str );
+ SysFreeString( index_param.value );
+ if (!ret) break;
+ if (status != HTTP_STATUS_OK)
+ {
+ if (error_str)
+ {
+ if (long_from_bstr( error_str ) != 713)
+ WARN( "Server returned error %s.\n", debugstr_w(error_str) );
+ SysFreeString( error_str );
+ }
+ break;
+ }
+ new_mappings[index].external_ip = mapping_move_bstr( &mapping_desc[PM_EXTERNAL_IP].value );
+ new_mappings[index].external = long_from_bstr( mapping_desc[PM_EXTERNAL].value );
+ new_mappings[index].protocol = mapping_move_bstr( &mapping_desc[PM_PROTOCOL].value );
+ new_mappings[index].internal = long_from_bstr( mapping_desc[PM_INTERNAL].value );
+ new_mappings[index].client = mapping_move_bstr( &mapping_desc[PM_CLIENT].value );
+ if (mapping_desc[PM_ENABLED].value && (!wcsicmp( mapping_desc[PM_ENABLED].value, L"true" )
+ || long_from_bstr( mapping_desc[PM_ENABLED].value )))
+ new_mappings[index].enabled = VARIANT_TRUE;
+ else
+ new_mappings[index].enabled = VARIANT_FALSE;
+ new_mappings[index].descr = mapping_move_bstr( &mapping_desc[PM_DESC].value );
+
+ TRACE( "%s %s %s:%u -> %s:%u, enabled %d.\n", debugstr_w(new_mappings[index].descr),
+ debugstr_w(new_mappings[index].protocol), debugstr_w(new_mappings[index].external_ip),
+ new_mappings[index].external, debugstr_w(new_mappings[index].client),
+ new_mappings[index].internal, new_mappings[index].enabled );
+
+ for (i = 0; i < ARRAY_SIZE(mapping_desc); ++i)
+ SysFreeString( mapping_desc[i].value );
+ upnp_gateway_connection.mappings = new_mappings;
+ upnp_gateway_connection.mapping_count = ++index;
+ }
+}
+
+static BOOL remove_port_mapping( LONG port, BSTR protocol )
+{
+ struct xml_value_desc mapping_desc[PM_REMOVE_PORT_LAST];
+ DWORD status = 0;
+ BSTR error_str;
+ WCHAR portW[6];
+ BOOL ret;
+
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ memcpy( mapping_desc, port_mapping_template, sizeof(mapping_desc) );
+ swprintf( portW, ARRAY_SIZE(portW), L"%u", port );
+ mapping_desc[PM_EXTERNAL_IP].value = SysAllocString( L"" );
+ mapping_desc[PM_EXTERNAL].value = SysAllocString( portW );
+ mapping_desc[PM_PROTOCOL].value = protocol;
+
+ ret = request_service( L"DeletePortMapping", mapping_desc, PM_REMOVE_PORT_LAST,
+ NULL, 0, &status, &error_str );
+ if (ret && status != HTTP_STATUS_OK)
+ {
+ WARN( "status %u, server returned error %s.\n", status, debugstr_w(error_str) );
+ SysFreeString( error_str );
+ ret = FALSE;
+ }
+ else if (!ret)
+ {
+ WARN( "Request failed.\n" );
+ }
+ update_mapping_list();
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+
+ SysFreeString( mapping_desc[PM_EXTERNAL_IP].value );
+ SysFreeString( mapping_desc[PM_EXTERNAL].value );
+ return ret;
+}
+
+static BOOL add_port_mapping( LONG external, BSTR protocol, LONG internal, BSTR client,
+ VARIANT_BOOL enabled, BSTR description )
+{
+ struct xml_value_desc mapping_desc[PM_LAST];
+ WCHAR externalW[6], internalW[6];
+ DWORD status = 0;
+ BSTR error_str;
+ BOOL ret;
+
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ memcpy( mapping_desc, port_mapping_template, sizeof(mapping_desc) );
+ swprintf( externalW, ARRAY_SIZE(externalW), L"%u", external );
+ swprintf( internalW, ARRAY_SIZE(internalW), L"%u", internal );
+ mapping_desc[PM_EXTERNAL_IP].value = SysAllocString( L"" );
+ mapping_desc[PM_EXTERNAL].value = SysAllocString( externalW );
+ mapping_desc[PM_PROTOCOL].value = protocol;
+ mapping_desc[PM_INTERNAL].value = SysAllocString( internalW );
+ mapping_desc[PM_CLIENT].value = client;
+ mapping_desc[PM_ENABLED].value = SysAllocString( enabled ? L"1" : L"0" );
+ mapping_desc[PM_DESC].value = description;
+ mapping_desc[PM_LEASE_DURATION].value = SysAllocString( L"0" );
+
+ ret = request_service( L"AddPortMapping", mapping_desc, PM_LAST,
+ NULL, 0, &status, &error_str );
+ if (ret && status != HTTP_STATUS_OK)
+ {
+ WARN( "status %u, server returned error %s.\n", status, debugstr_w(error_str) );
+ SysFreeString( error_str );
+ ret = FALSE;
+ }
+ else if (!ret)
+ {
+ WARN( "Request failed.\n" );
+ }
+ update_mapping_list();
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+
+ SysFreeString( mapping_desc[PM_EXTERNAL_IP].value );
+ SysFreeString( mapping_desc[PM_EXTERNAL].value );
+ SysFreeString( mapping_desc[PM_INTERNAL].value );
+ SysFreeString( mapping_desc[PM_ENABLED].value );
+ SysFreeString( mapping_desc[PM_LEASE_DURATION].value );
+ return ret;
+}
+
+static BOOL init_gateway_connection(void)
+{
+ static const char upnp_search_request[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "HOST:239.255.255.250:1900\r\n"
+ "ST:upnp:rootdevice\r\n"
+ "MX:2\r\n"
+ "MAN:\"ssdp:discover\"\r\n"
+ "\r\n";
+
+ const DWORD timeout = 1000;
+ int len, address_len;
+ char buffer[2048];
+ SOCKADDR_IN addr;
+ WSADATA wsa_data;
+ unsigned int i;
+ SOCKET s;
+
+ upnp_gateway_connection.winsock_initialized = WSAStartup( MAKEWORD( 2, 2 ), &wsa_data );
+ if ((s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP )) == -1)
+ {
+ ERR( "Failed to create socket, error %u.\n", WSAGetLastError() );
+ return FALSE;
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) == SOCKET_ERROR)
+ {
+ ERR( "setsockopt(SO_RCVTIME0) failed, error %u.\n", WSAGetLastError() );
+ closesocket( s );
+ return FALSE;
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons( 1900 );
+ addr.sin_addr.S_un.S_addr = inet_addr( "239.255.255.250" );
+ if (sendto( s, upnp_search_request, strlen( upnp_search_request ), 0, (SOCKADDR *)&addr, sizeof(addr) )
+ == SOCKET_ERROR)
+ {
+ ERR( "sendto failed, error %u\n", WSAGetLastError() );
+ closesocket( s );
+ return FALSE;
+ }
+ /* Windows has a dedicated SSDP discovery service which maintains gateway device info and does
+ * not usually delay in get_StaticPortMappingCollection(). Although it may still delay depending
+ * on network connection state and always delays in IUPnPNAT_get_NATEventManager(). */
+ FIXME( "Waiting for reply from router.\n" );
+ for (i = 0; i < 2; ++i)
+ {
+ address_len = sizeof(addr);
+ len = recvfrom( s, buffer, sizeof(buffer) - 1, 0, (SOCKADDR *)&addr, &address_len );
+ if (len == -1)
+ {
+ if (WSAGetLastError() != WSAETIMEDOUT)
+ {
+ WARN( "recvfrom error %u.\n", WSAGetLastError() );
+ closesocket( s );
+ return FALSE;
+ }
+ }
+ else break;
+ }
+ closesocket( s );
+ if (i == 2)
+ {
+ TRACE( "No reply from router.\n" );
+ return FALSE;
+ }
+ TRACE( "Received reply from gateway, len %d.\n", len );
+ buffer[len] = 0;
+ if (!parse_search_response( buffer, upnp_gateway_connection.locationW, sizeof(upnp_gateway_connection.locationW) ))
+ {
+ WARN( "Error parsing response.\n" );
+ return FALSE;
+ }
+ TRACE( "Gateway description location %s.\n", debugstr_w(upnp_gateway_connection.locationW) );
+ if (!open_gateway_connection())
+ {
+ WARN( "Error opening gateway connection.\n" );
+ return FALSE;
+ }
+ TRACE( "Opened gateway connection.\n" );
+ if (!get_control_url())
+ {
+ WARN( "Could not get_control URL.\n" );
+ gateway_connection_cleanup();
+ return FALSE;
+ }
+ TRACE( "control_url %s, version %u.\n", debugstr_w(upnp_gateway_connection.control_url),
+ upnp_gateway_connection.version );
+
+ update_mapping_list();
+ return TRUE;
+}
+
+static BOOL grab_gateway_connection(void)
+{
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ if (!upnp_gateway_connection.refs && !init_gateway_connection())
+ {
+ gateway_connection_cleanup();
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+ return FALSE;
+ }
+ ++upnp_gateway_connection.refs;
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+ return TRUE;
+}
+
+static void release_gateway_connection(void)
+{
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ assert( upnp_gateway_connection.refs );
+ if (!--upnp_gateway_connection.refs)
+ gateway_connection_cleanup();
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+}
+
+static BOOL find_port_mapping( LONG port, BSTR protocol, struct port_mapping *ret )
+{
+ unsigned int i;
+ BOOL found;
+
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ for (i = 0; i < upnp_gateway_connection.mapping_count; ++i)
+ {
+ if (upnp_gateway_connection.mappings[i].external == port
+ && !wcscmp( upnp_gateway_connection.mappings[i].protocol, protocol ))
+ break;
+ }
+ found = i < upnp_gateway_connection.mapping_count;
+ if (found) copy_port_mapping( ret, &upnp_gateway_connection.mappings[i] );
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+ return found;
+}
+
+static unsigned int get_port_mapping_range( unsigned int index, unsigned int count, struct port_mapping *ret )
+{
+ unsigned int i;
+
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ for (i = 0; i < count && index + i < upnp_gateway_connection.mapping_count; ++i)
+ if (!copy_port_mapping( &ret[i], &upnp_gateway_connection.mappings[index + i] ))
+ {
+ ERR( "No memory.\n" );
+ break;
+ }
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+
+ return i;
+}
+
+static unsigned int get_port_mapping_count(void)
+{
+ unsigned int ret;
+
+ AcquireSRWLockExclusive( &upnp_gateway_connection_lock );
+ ret = upnp_gateway_connection.mapping_count;
+ ReleaseSRWLockExclusive( &upnp_gateway_connection_lock );
+ return ret;
+}
+
+static BOOL is_valid_protocol( BSTR protocol )
+{
+ if (!protocol) return FALSE;
+ return !wcscmp( protocol, L"UDP" ) || !wcscmp( protocol, L"TCP" );
+}
+
+struct static_port_mapping
+{
+ IStaticPortMapping IStaticPortMapping_iface;
+ LONG refs;
+ struct port_mapping data;
+};
+
+static inline struct static_port_mapping *impl_from_IStaticPortMapping( IStaticPortMapping *iface )
+{
+ return CONTAINING_RECORD(iface, struct static_port_mapping, IStaticPortMapping_iface);
+}
+
+static ULONG WINAPI static_port_mapping_AddRef(
+ IStaticPortMapping *iface )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+ return InterlockedIncrement( &mapping->refs );
+}
+
+static ULONG WINAPI static_port_mapping_Release(
+ IStaticPortMapping *iface )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+ LONG refs = InterlockedDecrement( &mapping->refs );
+ if (!refs)
+ {
+ TRACE("destroying %p\n", mapping);
+ free_port_mapping( &mapping->data );
+ free( mapping );
+ }
+ return refs;
+}
+
+static HRESULT WINAPI static_port_mapping_QueryInterface(
+ IStaticPortMapping *iface,
+ REFIID riid,
+ void **ppvObject )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE("%p %s %p\n", mapping, debugstr_guid( riid ), ppvObject );
+
+ if ( IsEqualGUID( riid, &IID_IStaticPortMapping ) ||
+ IsEqualGUID( riid, &IID_IDispatch ) ||
+ IsEqualGUID( riid, &IID_IUnknown ) )
+ {
+ *ppvObject = iface;
+ }
+ else
+ {
+ FIXME("interface %s not implemented\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+ }
+ IStaticPortMapping_AddRef( iface );
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_GetTypeInfoCount(
+ IStaticPortMapping *iface,
+ UINT *pctinfo )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE("%p %p\n", mapping, pctinfo);
+ *pctinfo = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_GetTypeInfo(
+ IStaticPortMapping *iface,
+ UINT iTInfo,
+ LCID lcid,
+ ITypeInfo **ppTInfo )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE("%p %u %u %p\n", mapping, iTInfo, lcid, ppTInfo);
+ return get_typeinfo( IStaticPortMapping_tid, ppTInfo );
+}
+
+static HRESULT WINAPI static_port_mapping_GetIDsOfNames(
+ IStaticPortMapping *iface,
+ REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgDispId )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("%p %s %p %u %u %p\n", mapping, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+ hr = get_typeinfo( IStaticPortMapping_tid, &typeinfo );
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_GetIDsOfNames( typeinfo, rgszNames, cNames, rgDispId );
+ ITypeInfo_Release( typeinfo );
+ }
+ return hr;
+}
+
+static HRESULT WINAPI static_port_mapping_Invoke(
+ IStaticPortMapping *iface,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("%p %d %s %d %d %p %p %p %p\n", mapping, dispIdMember, debugstr_guid(riid),
+ lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+ hr = get_typeinfo( IStaticPortMapping_tid, &typeinfo );
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_Invoke( typeinfo, &mapping->IStaticPortMapping_iface, dispIdMember,
+ wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
+ ITypeInfo_Release( typeinfo );
+ }
+ return hr;
+}
+
+static HRESULT WINAPI static_port_mapping_get_ExternalIPAddress(
+ IStaticPortMapping *iface,
+ BSTR *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = SysAllocString( mapping->data.external_ip );
+ if (mapping->data.external_ip && !*value) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_get_ExternalPort(
+ IStaticPortMapping *iface,
+ LONG *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = mapping->data.external;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_get_InternalPort(
+ IStaticPortMapping *iface,
+ LONG *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = mapping->data.internal;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_get_Protocol(
+ IStaticPortMapping *iface,
+ BSTR *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = SysAllocString( mapping->data.protocol );
+ if (mapping->data.protocol && !*value) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_get_InternalClient(
+ IStaticPortMapping *iface,
+ BSTR *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = SysAllocString( mapping->data.client );
+ if (mapping->data.client && !*value) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_get_Enabled(
+ IStaticPortMapping *iface,
+ VARIANT_BOOL *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = mapping->data.enabled;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_get_Description(
+ IStaticPortMapping *iface,
+ BSTR *value )
+{
+ struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface );
+
+ TRACE( "iface %p, value %p.\n", iface, value );
+
+ if (!value) return E_POINTER;
+ *value = SysAllocString( mapping->data.descr );
+ if (mapping->data.descr && !*value) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_port_mapping_EditInternalClient(
+ IStaticPortMapping *iface,
+ BSTR value )
+{
+ FIXME( "iface %p, value %s stub.\n", iface, debugstr_w(value) );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI static_port_mapping_Enable(
+ IStaticPortMapping *iface,
+ VARIANT_BOOL value )
+{
+ FIXME( "iface %p, value %d stub.\n", iface, value );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI static_port_mapping_EditDescription(
+ IStaticPortMapping *iface,
+ BSTR value )
+{
+ FIXME( "iface %p, value %s stub.\n", iface, debugstr_w(value) );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI static_port_mapping_EditInternalPort(
+ IStaticPortMapping *iface,
+ LONG value )
+{
+ FIXME( "iface %p, value %d stub.\n", iface, value );
+
+ return E_NOTIMPL;
+}
+
+static const IStaticPortMappingVtbl static_port_mapping_vtbl =
+{
+ static_port_mapping_QueryInterface,
+ static_port_mapping_AddRef,
+ static_port_mapping_Release,
+ static_port_mapping_GetTypeInfoCount,
+ static_port_mapping_GetTypeInfo,
+ static_port_mapping_GetIDsOfNames,
+ static_port_mapping_Invoke,
+ static_port_mapping_get_ExternalIPAddress,
+ static_port_mapping_get_ExternalPort,
+ static_port_mapping_get_InternalPort,
+ static_port_mapping_get_Protocol,
+ static_port_mapping_get_InternalClient,
+ static_port_mapping_get_Enabled,
+ static_port_mapping_get_Description,
+ static_port_mapping_EditInternalClient,
+ static_port_mapping_Enable,
+ static_port_mapping_EditDescription,
+ static_port_mapping_EditInternalPort,
+};
+
+static HRESULT static_port_mapping_create( const struct port_mapping *mapping_data, IStaticPortMapping **ret )
+{
+ struct static_port_mapping *mapping;
+
+ if (!(mapping = calloc( 1, sizeof(*mapping) ))) return E_OUTOFMEMORY;
+
+ mapping->refs = 1;
+ mapping->IStaticPortMapping_iface.lpVtbl = &static_port_mapping_vtbl;
+ mapping->data = *mapping_data;
+ *ret = &mapping->IStaticPortMapping_iface;
+ return S_OK;
+}
+
+struct port_mapping_enum
+{
+ IEnumVARIANT IEnumVARIANT_iface;
+ LONG refs;
+ unsigned int index;
+};
+
+static inline struct port_mapping_enum *impl_from_IEnumVARIANT( IEnumVARIANT *iface )
+{
+ return CONTAINING_RECORD(iface, struct port_mapping_enum, IEnumVARIANT_iface);
+}
+
+static ULONG WINAPI port_mapping_enum_AddRef(
+ IEnumVARIANT *iface )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+ return InterlockedIncrement( &mapping_enum->refs );
+}
+
+static ULONG WINAPI port_mapping_enum_Release(
+ IEnumVARIANT *iface )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+ LONG refs = InterlockedDecrement( &mapping_enum->refs );
+ if (!refs)
+ {
+ TRACE("destroying %p\n", mapping_enum);
+ free( mapping_enum );
+ release_gateway_connection();
+ }
+ return refs;
+}
+
+static HRESULT WINAPI port_mapping_enum_QueryInterface(
+ IEnumVARIANT *iface,
+ REFIID riid,
+ void **ppvObject )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+
+ TRACE("%p %s %p\n", mapping_enum, debugstr_guid( riid ), ppvObject );
+
+ if ( IsEqualGUID( riid, &IID_IEnumVARIANT ) ||
+ IsEqualGUID( riid, &IID_IUnknown ) )
+ {
+ *ppvObject = iface;
+ }
+ else
+ {
+ FIXME("interface %s not implemented\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+ }
+ IEnumVARIANT_AddRef( iface );
+ return S_OK;
+}
+
+static HRESULT WINAPI port_mapping_enum_Next( IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+ struct port_mapping *data;
+ IStaticPortMapping *pm;
+ unsigned int i, count;
+ HRESULT ret;
+
+ TRACE( "iface %p, celt %u, var %p, fetched %p.\n", iface, celt, var, fetched );
+
+ if (fetched) *fetched = 0;
+ if (!celt) return S_OK;
+ if (!var) return E_POINTER;
+
+ if (!(data = calloc( 1, celt * sizeof(*data) ))) return E_OUTOFMEMORY;
+ count = get_port_mapping_range( mapping_enum->index, celt, data );
+ TRACE( "count %u.\n", count );
+ for (i = 0; i < count; ++i)
+ {
+ if (FAILED(static_port_mapping_create( &data[i], &pm ))) break;
+
+ V_VT(&var[i]) = VT_DISPATCH;
+ V_DISPATCH(&var[i]) = (IDispatch *)pm;
+ }
+ mapping_enum->index += i;
+ if (fetched) *fetched = i;
+ ret = (i < celt) ? S_FALSE : S_OK;
+ for ( ; i < count; ++i)
+ {
+ free_port_mapping( &data[i] );
+ VariantInit( &var[i] );
+ }
+ for ( ; i < celt; ++i)
+ VariantInit( &var[i] );
+
+ free( data );
+ return ret;
+}
+
+static HRESULT WINAPI port_mapping_enum_Skip( IEnumVARIANT *iface, ULONG celt )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+ unsigned int count = get_port_mapping_count();
+
+ TRACE( "iface %p, celt %u.\n", iface, celt );
+
+ mapping_enum->index += celt;
+ return mapping_enum->index <= count ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI port_mapping_enum_Reset( IEnumVARIANT *iface )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+
+ TRACE( "iface %p.\n", iface );
+
+ mapping_enum->index = 0;
+ return S_OK;
+}
+
+static HRESULT create_port_mapping_enum( IUnknown **ret );
+
+static HRESULT WINAPI port_mapping_enum_Clone( IEnumVARIANT *iface, IEnumVARIANT **ret )
+{
+ struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface );
+ HRESULT hr;
+
+ TRACE( "iface %p, ret %p.\n", iface, ret );
+
+ if (!ret) return E_POINTER;
+ *ret = NULL;
+ if (FAILED(hr = create_port_mapping_enum( (IUnknown **)ret ))) return hr;
+ impl_from_IEnumVARIANT( *ret )->index = mapping_enum->index;
+ return S_OK;
+}
+
+static const IEnumVARIANTVtbl port_mapping_enum_vtbl =
+{
+ port_mapping_enum_QueryInterface,
+ port_mapping_enum_AddRef,
+ port_mapping_enum_Release,
+ port_mapping_enum_Next,
+ port_mapping_enum_Skip,
+ port_mapping_enum_Reset,
+ port_mapping_enum_Clone,
+};
+
+static HRESULT create_port_mapping_enum( IUnknown **ret )
+{
+ struct port_mapping_enum *mapping_enum;
+
+ if (!(mapping_enum = calloc( 1, sizeof(*mapping_enum) ))) return E_OUTOFMEMORY;
+
+ grab_gateway_connection();
+
+ mapping_enum->refs = 1;
+ mapping_enum->IEnumVARIANT_iface.lpVtbl = &port_mapping_enum_vtbl;
+ mapping_enum->index = 0;
+ *ret = (IUnknown *)&mapping_enum->IEnumVARIANT_iface;
+ return S_OK;
+}
+
+struct static_port_mapping_collection
+{
+ IStaticPortMappingCollection IStaticPortMappingCollection_iface;
+ LONG refs;
+};
+
+static inline struct static_port_mapping_collection *impl_from_IStaticPortMappingCollection
+ ( IStaticPortMappingCollection *iface )
+{
+ return CONTAINING_RECORD(iface, struct static_port_mapping_collection, IStaticPortMappingCollection_iface);
+}
+
+static ULONG WINAPI static_ports_AddRef(
+ IStaticPortMappingCollection *iface )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+ return InterlockedIncrement( &ports->refs );
+}
+
+static ULONG WINAPI static_ports_Release(
+ IStaticPortMappingCollection *iface )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+ LONG refs = InterlockedDecrement( &ports->refs );
+ if (!refs)
+ {
+ TRACE("destroying %p\n", ports);
+ release_gateway_connection();
+ free( ports );
+ }
+ return refs;
+}
+
+static HRESULT WINAPI static_ports_QueryInterface(
+ IStaticPortMappingCollection *iface,
+ REFIID riid,
+ void **ppvObject )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+
+ TRACE("%p %s %p\n", ports, debugstr_guid( riid ), ppvObject );
+
+ if ( IsEqualGUID( riid, &IID_IStaticPortMappingCollection ) ||
+ IsEqualGUID( riid, &IID_IDispatch ) ||
+ IsEqualGUID( riid, &IID_IUnknown ) )
+ {
+ *ppvObject = iface;
+ }
+ else
+ {
+ FIXME("interface %s not implemented\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+ }
+ IStaticPortMappingCollection_AddRef( iface );
+ return S_OK;
+}
+
+static HRESULT WINAPI static_ports_GetTypeInfoCount(
+ IStaticPortMappingCollection *iface,
+ UINT *pctinfo )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+
+ TRACE("%p %p\n", ports, pctinfo);
+ *pctinfo = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI static_ports_GetTypeInfo(
+ IStaticPortMappingCollection *iface,
+ UINT iTInfo,
+ LCID lcid,
+ ITypeInfo **ppTInfo )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+
+ TRACE("%p %u %u %p\n", ports, iTInfo, lcid, ppTInfo);
+ return get_typeinfo( IStaticPortMappingCollection_tid, ppTInfo );
+}
+
+static HRESULT WINAPI static_ports_GetIDsOfNames(
+ IStaticPortMappingCollection *iface,
+ REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgDispId )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("%p %s %p %u %u %p\n", ports, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+
+ hr = get_typeinfo( IStaticPortMappingCollection_tid, &typeinfo );
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_GetIDsOfNames( typeinfo, rgszNames, cNames, rgDispId );
+ ITypeInfo_Release( typeinfo );
+ }
+ return hr;
+}
+
+static HRESULT WINAPI static_ports_Invoke(
+ IStaticPortMappingCollection *iface,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr )
+{
+ struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface );
+ ITypeInfo *typeinfo;
+ HRESULT hr;
+
+ TRACE("%p %d %s %d %d %p %p %p %p\n", ports, dispIdMember, debugstr_guid(riid),
+ lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+ hr = get_typeinfo( IStaticPortMappingCollection_tid, &typeinfo );
+ if (SUCCEEDED(hr))
+ {
+ hr = ITypeInfo_Invoke( typeinfo, &ports->IStaticPortMappingCollection_iface, dispIdMember,
+ wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
+ ITypeInfo_Release( typeinfo );
+ }
+ return hr;
+}
+
+static HRESULT WINAPI static_ports__NewEnum(
+ IStaticPortMappingCollection *iface,
+ IUnknown **ret )
+{
+ TRACE( "iface %p, ret %p.\n", iface, ret );
+
+ if (!ret) return E_POINTER;
+
+ *ret = NULL;
+ return create_port_mapping_enum( ret );
+}
+
+static HRESULT WINAPI static_ports_get_Item(
+ IStaticPortMappingCollection *iface,
+ LONG port,
+ BSTR protocol,
+ IStaticPortMapping **mapping )
+{
+ struct port_mapping mapping_data;
+ HRESULT ret;
+
+ TRACE( "iface %p, port %d, protocol %s.\n", iface, port, debugstr_w(protocol) );
+
+ if (!mapping) return E_POINTER;
+ *mapping = NULL;
+ if (!is_valid_protocol( protocol )) return E_INVALIDARG;
+ if (port < 0 || port > 65535) return E_INVALIDARG;
+
+ if (!find_port_mapping( port, protocol, &mapping_data )) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ if (FAILED(ret = static_port_mapping_create( &mapping_data, mapping ))) free_port_mapping( &mapping_data );
+ return ret;
+}
+
+static HRESULT WINAPI static_ports_get_Count(
+ IStaticPortMappingCollection *iface,
+ LONG *count )
+{
+ TRACE( "iface %p, count %p.\n", iface, count );
+
+ if (!count) return E_POINTER;
+ *count = get_port_mapping_count();
+ return S_OK;
+}
+
+static HRESULT WINAPI static_ports_Remove(
+ IStaticPortMappingCollection *iface,
+ LONG port,
+ BSTR protocol )
+{
+ TRACE( "iface %p, port %d, protocol %s.\n", iface, port, debugstr_w(protocol) );
+
+ if (!is_valid_protocol( protocol )) return E_INVALIDARG;
+ if (port < 0 || port > 65535) return E_INVALIDARG;
+
+ if (!remove_port_mapping( port, protocol )) return E_FAIL;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI static_ports_Add(
+ IStaticPortMappingCollection *iface,
+ LONG external,
+ BSTR protocol,
+ LONG internal,
+ BSTR client,
+ VARIANT_BOOL enabled,
+ BSTR description,
+ IStaticPortMapping **mapping )
+{
+ struct port_mapping mapping_data;
+ HRESULT ret;
+
+ TRACE( "iface %p, external %d, protocol %s, internal %d, client %s, enabled %d, descritption %s, mapping %p.\n",
+ iface, external, debugstr_w(protocol), internal, debugstr_w(client), enabled, debugstr_w(description),
+ mapping );
+
+ if (!mapping) return E_POINTER;
+ *mapping = NULL;
+
+ if (!is_valid_protocol( protocol )) return E_INVALIDARG;
+ if (external < 0 || external > 65535) return E_INVALIDARG;
+ if (internal < 0 || internal > 65535) return E_INVALIDARG;
+ if (!client || !description) return E_INVALIDARG;
+
+ if (!add_port_mapping( external, protocol, internal, client, enabled, description )) return E_FAIL;
+
+ mapping_data.external_ip = NULL;
+ mapping_data.external = external;
+ mapping_data.protocol = SysAllocString( protocol );
+ mapping_data.internal = internal;
+ mapping_data.client = SysAllocString( client );
+ mapping_data.enabled = enabled;
+ mapping_data.descr = SysAllocString( description );
+ if (!mapping_data.protocol || !mapping_data.client || !mapping_data.descr)
+ {
+ free_port_mapping( &mapping_data );
+ return E_OUTOFMEMORY;
+ }
+ if (FAILED(ret = static_port_mapping_create( &mapping_data, mapping ))) free_port_mapping( &mapping_data );
+ return ret;
+}
+
+static const IStaticPortMappingCollectionVtbl static_ports_vtbl =
+{
+ static_ports_QueryInterface,
+ static_ports_AddRef,
+ static_ports_Release,
+ static_ports_GetTypeInfoCount,
+ static_ports_GetTypeInfo,
+ static_ports_GetIDsOfNames,
+ static_ports_Invoke,
+ static_ports__NewEnum,
+ static_ports_get_Item,
+ static_ports_get_Count,
+ static_ports_Remove,
+ static_ports_Add,
+};
+
+static HRESULT static_port_mapping_collection_create(IStaticPortMappingCollection **object)
+{
+ struct static_port_mapping_collection *ports;
+
+ if (!object) return E_POINTER;
+ if (!grab_gateway_connection())
+ {
+ *object = NULL;
+ return S_OK;
+ }
+ if (!(ports = calloc( 1, sizeof(*ports) )))
+ {
+ release_gateway_connection();
+ return E_OUTOFMEMORY;
+ }
+ ports->refs = 1;
+ ports->IStaticPortMappingCollection_iface.lpVtbl = &static_ports_vtbl;
+ *object = &ports->IStaticPortMappingCollection_iface;
+ return S_OK;
+}
+
typedef struct fw_port
{
INetFwOpenPort INetFwOpenPort_iface;
@@ -64,7 +1619,7 @@ static ULONG WINAPI fw_port_Release(
{
TRACE("destroying %p\n", fw_port);
SysFreeString( fw_port->name );
- HeapFree( GetProcessHeap(), 0, fw_port );
+ free( fw_port );
}
return refs;
}
@@ -363,7 +1918,7 @@ HRESULT NetFwOpenPort_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwOpenPort_iface.lpVtbl = &fw_port_vtbl;
@@ -404,7 +1959,7 @@ static ULONG WINAPI fw_ports_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_ports);
- HeapFree( GetProcessHeap(), 0, fw_ports );
+ free( fw_ports );
}
return refs;
}
@@ -592,7 +2147,7 @@ HRESULT NetFwOpenPorts_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwOpenPorts_iface.lpVtbl = &fw_ports_vtbl;
@@ -653,7 +2208,7 @@ static ULONG WINAPI upnpnat_Release(IUPnPNAT *iface)
LONG refs = InterlockedDecrement( &This->ref );
if (!refs)
{
- heap_free( This );
+ free( This );
}
return refs;
}
@@ -717,10 +2272,10 @@ static HRESULT WINAPI upnpnat_Invoke(IUPnPNAT *iface, DISPID dispIdMember, REFII
static HRESULT WINAPI upnpnat_get_StaticPortMappingCollection(IUPnPNAT *iface, IStaticPortMappingCollection **collection)
{
upnpnat *This = impl_from_IUPnPNAT( iface );
- FIXME("%p, %p\n", This, collection);
- if(collection)
- *collection = NULL;
- return S_OK;
+
+ TRACE("%p, %p\n", This, collection);
+
+ return static_port_mapping_collection_create( collection );
}
static HRESULT WINAPI upnpnat_get_DynamicPortMappingCollection(IUPnPNAT *iface, IDynamicPortMappingCollection **collection)
@@ -762,7 +2317,7 @@ HRESULT IUPnPNAT_create(IUnknown *outer, void **object)
TRACE("(%p,%p)\n", outer, object);
- nat = heap_alloc( sizeof(*nat) );
+ nat = malloc( sizeof(*nat) );
if (!nat) return E_OUTOFMEMORY;
nat->IUPnPNAT_iface.lpVtbl = &upnpnat_vtbl;
diff --git a/dlls/hnetcfg/profile.c b/dlls/hnetcfg/profile.c
index d0e9f48dab4..63f6d0cc7ed 100644
--- a/dlls/hnetcfg/profile.c
+++ b/dlls/hnetcfg/profile.c
@@ -58,7 +58,7 @@ static ULONG WINAPI fw_profile_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_profile);
- HeapFree( GetProcessHeap(), 0, fw_profile );
+ free( fw_profile );
}
return refs;
}
@@ -334,7 +334,7 @@ HRESULT NetFwProfile_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwProfile_iface.lpVtbl = &fw_profile_vtbl;
diff --git a/dlls/hnetcfg/service.c b/dlls/hnetcfg/service.c
index 5bfeedaaedf..122d9797bab 100644
--- a/dlls/hnetcfg/service.c
+++ b/dlls/hnetcfg/service.c
@@ -58,7 +58,7 @@ static ULONG WINAPI fw_service_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_service);
- HeapFree( GetProcessHeap(), 0, fw_service );
+ free( fw_service );
}
return refs;
}
@@ -290,7 +290,7 @@ static HRESULT NetFwService_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwService_iface.lpVtbl = &fw_service_vtbl;
@@ -328,7 +328,7 @@ static ULONG WINAPI fw_services_Release(
if (!refs)
{
TRACE("destroying %p\n", fw_services);
- HeapFree( GetProcessHeap(), 0, fw_services );
+ free( fw_services );
}
return refs;
}
@@ -464,7 +464,7 @@ HRESULT NetFwServices_create( IUnknown *pUnkOuter, LPVOID *ppObj )
TRACE("(%p,%p)\n", pUnkOuter, ppObj);
- fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) );
+ fp = malloc( sizeof(*fp) );
if (!fp) return E_OUTOFMEMORY;
fp->INetFwServices_iface.lpVtbl = &fw_services_vtbl;
diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c
index e2606933079..3b614e6e05a 100644
--- a/dlls/hnetcfg/tests/policy.c
+++ b/dlls/hnetcfg/tests/policy.c
@@ -29,6 +29,12 @@
#include "netfw.h"
#include "natupnp.h"
+static ULONG get_refcount(IUnknown *unk)
+{
+ IUnknown_AddRef(unk);
+ return IUnknown_Release(unk);
+}
+
static void test_policy2_rules(INetFwPolicy2 *policy2)
{
HRESULT hr;
@@ -164,6 +170,120 @@ static void test_NetFwAuthorizedApplication(void)
INetFwAuthorizedApplication_Release(app);
}
+static void test_static_port_mapping_collection( IStaticPortMappingCollection *ports )
+{
+ LONG i, count, count2, expected_count, external_port;
+ IStaticPortMapping *pm, *pm2;
+ ULONG refcount, refcount2;
+ IEnumVARIANT *enum_ports;
+ IUnknown *unk;
+ ULONG fetched;
+ BSTR protocol;
+ VARIANT var;
+ HRESULT hr;
+
+ refcount = get_refcount((IUnknown *)ports);
+ hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ IUnknown_Release( unk );
+
+ refcount2 = get_refcount((IUnknown *)ports);
+ ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2);
+
+ hr = IEnumVARIANT_Reset(enum_ports);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ count = 0xdeadbeef;
+ hr = IStaticPortMappingCollection_get_Count(ports, &count);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"UDP", &pm);
+ if (SUCCEEDED(hr))
+ {
+ expected_count = count;
+ IStaticPortMapping_Release(pm);
+ }
+ else
+ {
+ expected_count = count + 1;
+ }
+
+ hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"udp", 12345, (BSTR)L"1.2.3.4",
+ VARIANT_TRUE, (BSTR)L"wine_test", &pm);
+ ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+ hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"UDP", 12345, (BSTR)L"1.2.3.4",
+ VARIANT_TRUE, (BSTR)L"wine_test", &pm);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Count(ports, &count2);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, 12345, NULL, &pm);
+ ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"UDP", NULL);
+ ok(hr == E_POINTER, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"udp", &pm);
+ ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, -1, (BSTR)L"UDP", &pm);
+ ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, 65536, (BSTR)L"UDP", &pm);
+ ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_get_Item(ports, 12346, (BSTR)L"UDP", &pm);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Got unexpected hr %#x.\n", hr);
+
+ hr = IEnumVARIANT_Reset(enum_ports);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < count2; ++i)
+ {
+ VariantInit(&var);
+
+ fetched = 0xdeadbeef;
+ hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(fetched == 1, "Got unexpected fetched %u.\n", fetched);
+ ok(V_VT(&var) == VT_DISPATCH, "Got unexpected variant type %u.\n", V_VT(&var));
+
+ hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IStaticPortMapping, (void **)&pm);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMapping_get_Protocol(pm, &protocol);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ external_port = 0xdeadbeef;
+ hr = IStaticPortMapping_get_ExternalPort(pm, &external_port);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ ok(!wcscmp(protocol, L"UDP") || !wcscmp(protocol, L"TCP"), "Got unexpected protocol %s.\n",
+ debugstr_w(protocol));
+ hr = IStaticPortMappingCollection_get_Item(ports, external_port, protocol, &pm2);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(pm2 != pm, "Got same interface.\n");
+
+ IStaticPortMapping_Release(pm);
+ IStaticPortMapping_Release(pm2);
+
+ SysFreeString(protocol);
+
+ VariantClear(&var);
+ }
+ hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched);
+ ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr);
+
+ hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP");
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ IEnumVARIANT_Release(enum_ports);
+}
+
static void test_IUPnPNAT(void)
{
IUPnPNAT *nat;
@@ -171,6 +291,7 @@ static void test_IUPnPNAT(void)
IDynamicPortMappingCollection *dync_ports;
INATEventManager *manager;
IProvideClassInfo *provider;
+ ULONG refcount, refcount2;
HRESULT hr;
hr = CoCreateInstance(&CLSID_UPnPNAT, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IUPnPNAT, (void**)&nat);
@@ -179,11 +300,21 @@ static void test_IUPnPNAT(void)
hr = IUPnPNAT_QueryInterface(nat, &IID_IProvideClassInfo, (void**)&provider);
ok(hr == E_NOINTERFACE, "got: %08x\n", hr);
+ refcount = get_refcount((IUnknown *)nat);
hr = IUPnPNAT_get_StaticPortMappingCollection(nat, &static_ports);
+
ok(hr == S_OK, "got: %08x\n", hr);
if(hr == S_OK && static_ports)
+ {
+ refcount2 = get_refcount((IUnknown *)nat);
+ ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2);
+ test_static_port_mapping_collection( static_ports );
IStaticPortMappingCollection_Release(static_ports);
-
+ }
+ else if (hr == S_OK)
+ {
+ skip( "UPNP gateway not found.\n" );
+ }
hr = IUPnPNAT_get_DynamicPortMappingCollection(nat, &dync_ports);
ok(hr == S_OK || hr == E_NOTIMPL /* Windows 8.1 */, "got: %08x\n", hr);
if(hr == S_OK && dync_ports)
diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c
index 22f9115011e..601164a82a8 100644
--- a/dlls/kernelbase/process.c
+++ b/dlls/kernelbase/process.c
@@ -489,18 +489,15 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char *
static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line)
{
- WCHAR full_path[MAX_PATH], config_path[MAX_PATH];
+ static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe";
+
+ WCHAR full_path[MAX_PATH];
WCHAR *p;
DWORD size;
void *block;
DWORD *translation;
char buf[100];
char *product_name;
- int launcher_exe_len, game_exe_len, arg_len;
- HANDLE launcher_cfg;
- LARGE_INTEGER launcher_cfg_size;
- char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL;
- BOOL wow64;
WCHAR *new_cmd_line;
if (!GetLongPathNameW( app_name, full_path, MAX_PATH )) lstrcpynW( full_path, app_name, MAX_PATH );
@@ -541,96 +538,15 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam
HeapFree( GetProcessHeap(), 0, block );
- TRACE("Detected launch of a BattlEye Launcher, attempting to launch game executable instead.\n");
-
- lstrcpynW(config_path, full_path, MAX_PATH);
-
- for (p = config_path + wcslen(config_path); p != config_path; --p)
- if (*p == '\\') break;
-
- if (*p == '\\')
- {
- *p = 0;
- launcher_exe_len = wcslen(p + 1);
- }
- else
- launcher_exe_len = wcslen(full_path);
-
- lstrcatW(config_path, L"\\BattlEye\\BELauncher.ini");
-
- launcher_cfg = CreateFileW(config_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (launcher_cfg == INVALID_HANDLE_VALUE)
- return 0;
-
- if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart)
- {
- CloseHandle(launcher_cfg);
- return 0;
- }
-
- configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart);
-
- if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart)
- {
- CloseHandle(launcher_cfg);
- HeapFree( GetProcessHeap(), 0, configs );
- return 0;
- }
-
- CloseHandle(launcher_cfg);
-
- config = configs;
- do
- {
- if (!strncmp(config, "32BitExe=", 9))
- arch_32_exe = config + 9;
-
- if (!strncmp(config, "64BitExe=", 9))
- arch_64_exe = config + 9;
-
- if (!strncmp(config, "BEArg=", 6))
- be_arg = config + 6;
- }
- while ((config = strchr(config, '\n')) && *(config++));
-
- if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)))
- game_exe = arch_64_exe;
- else if (arch_32_exe)
- game_exe = arch_32_exe;
- else
- {
- HeapFree( GetProcessHeap(), 0, configs );
- WARN("Failed to find game executable name from BattlEye config.\n");
- return 0;
- }
-
- if (strchr(game_exe, '\r'))
- *(strchr(game_exe, '\r')) = 0;
- if (strchr(game_exe, '\n'))
- *(strchr(game_exe, '\n')) = 0;
- game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1;
-
- if (be_arg)
- {
- if (strchr(be_arg, '\r'))
- *(strchr(be_arg, '\r')) = 0;
- if (strchr(be_arg, '\n'))
- *(strchr(be_arg, '\n')) = 0;
- arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1;
- }
-
- TRACE("Launching game executable %s for BattlEye.\n", game_exe);
+ TRACE("Detected launch of a BattlEye Launcher, redirecting to Proton version.\n");
- if ((wcslen(app_name) - launcher_exe_len) + game_exe_len + 1 > new_name_len)
+ if (new_name_len < wcslen(belauncherW) + 1)
{
- HeapFree( GetProcessHeap(), 0, configs );
WARN("Game executable path doesn't fit in buffer.\n");
return 0;
}
- wcscpy(new_name, app_name);
- p = new_name + wcslen(new_name) - launcher_exe_len;
- MultiByteToWideChar(CP_ACP, 0, game_exe, -1, p, game_exe_len + 1);
+ wcscpy(new_name, belauncherW);
/* find and replace executable name in command line, and add BE argument */
p = *cmd_line;
@@ -638,43 +554,23 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam
p++;
if (!wcsncmp(p, app_name, wcslen(app_name)))
- p += wcslen(app_name) - launcher_exe_len;
- else
- p = NULL;
-
- if (p || be_arg)
{
- size = wcslen(*cmd_line) + 1;
- if (p)
- size += game_exe_len - launcher_exe_len;
- if (be_arg)
- size += 1 /* space */ + arg_len;
- size *= sizeof(WCHAR);
+ new_cmd_line = HeapAlloc( GetProcessHeap(), 0, ( wcslen(*cmd_line) + wcslen(belauncherW) + 1 - wcslen(app_name) ) * sizeof(WCHAR) );
- /* freed by parent function */
- new_cmd_line = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
+ wcscpy(new_cmd_line, *cmd_line);
+ p = new_cmd_line;
+ if (p[0] == '\"')
+ p++;
- if (p)
- {
- lstrcpynW(new_cmd_line, *cmd_line, p - *cmd_line);
- MultiByteToWideChar(CP_ACP, 0, game_exe, -1, new_cmd_line + wcslen(new_cmd_line), game_exe_len + 1);
- wcscat(new_cmd_line, p + launcher_exe_len);
- }
- else
- {
- wcscpy(new_cmd_line, *cmd_line);
- }
+ memmove( p + wcslen(belauncherW), p + wcslen(app_name), (wcslen(p) - wcslen(belauncherW)) * sizeof(WCHAR) );
+ memcpy( p, belauncherW, wcslen(belauncherW) * sizeof(WCHAR) );
- if (be_arg)
- {
- wcscat(new_cmd_line, L" ");
- MultiByteToWideChar(CP_ACP, 0, be_arg, -1, new_cmd_line + wcslen(new_cmd_line), arg_len + 1);
- }
+ TRACE("old command line %s.\n", debugstr_w(*cmd_line));
+ TRACE("new command line %s.\n", debugstr_w(new_cmd_line));
*cmd_line = new_cmd_line;
}
- HeapFree( GetProcessHeap(), 0, configs );
return 1;
}
@@ -690,6 +586,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd )
{L"UplayWebCore.exe", L" --use-gl=swiftshader"},
{L"Paradox Launcher.exe", L" --use-gl=swiftshader --in-process-gpu"},
{L"UnrealCEFSubProcess.exe", L" --use-gl=swiftshader"},
+ {L"SocialClubHelper.exe", L" --use-gl=swiftshader --in-process-gpu"},
};
unsigned int i;
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index c8ec1b5c33f..f2fe2a83ff6 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -1577,6 +1577,8 @@ static void session_set_topology(struct media_session *session, DWORD flags, IMF
{
hr = session_bind_output_nodes(topology);
+ IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE);
+
if (SUCCEEDED(hr))
hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */);
@@ -2321,6 +2323,8 @@ static enum object_state session_get_object_state_for_event(MediaEventType event
{
switch (event)
{
+ case MESourceSeeked:
+ case MEStreamSeeked:
case MESourceStarted:
case MEStreamStarted:
case MEStreamSinkStarted:
@@ -2497,6 +2501,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
switch (event_type)
{
+ case MESourceSeeked:
case MESourceStarted:
case MESourcePaused:
case MESourceStopped:
@@ -2511,6 +2516,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn
}
}
break;
+ case MEStreamSeeked:
case MEStreamStarted:
case MEStreamPaused:
case MEStreamStopped:
@@ -3197,6 +3203,10 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM
switch (event_type)
{
+ case MESourceSeeked:
+ case MEStreamSeeked:
+ FIXME("Source/stream seeking, semi-stub!\n");
+ /* fallthrough */
case MESourceStarted:
case MESourcePaused:
case MESourceStopped:
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 207bd61b8dc..1b1c8e90da6 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -942,6 +942,44 @@ todo_wine
video_stream = (IMFMediaStream *)var.punkVal;
}
+ hr = IMFMediaSource_Pause(mediasource);
+ ok(hr == S_OK, "Failed to pause media source, hr %#x.\n", hr);
+ if (get_event((IMFMediaEventGenerator *)mediasource, MESourcePaused, &var))
+ ok(var.vt == VT_EMPTY, "Unexpected value type.\n");
+
+ var.vt = VT_EMPTY;
+ hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
+ ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
+
+ if (get_event((IMFMediaEventGenerator *)mediasource, MESourceStarted, &var))
+ ok(var.vt == VT_EMPTY, "Unexpected value type.\n");
+
+ hr = IMFMediaSource_Pause(mediasource);
+ ok(hr == S_OK, "Failed to pause media source, hr %#x.\n", hr);
+ if (get_event((IMFMediaEventGenerator *)mediasource, MESourcePaused, &var))
+ ok(var.vt == VT_EMPTY, "Unexpected value type.\n");
+
+ var.vt = VT_I8;
+ var.uhVal.QuadPart = 0;
+ hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
+ ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
+
+ if (get_event((IMFMediaEventGenerator *)mediasource, MESourceSeeked, &var))
+ ok(var.vt == VT_I8, "Unexpected value type.\n");
+
+ hr = IMFMediaSource_Stop(mediasource);
+ ok(hr == S_OK, "Failed to pause media source, hr %#x.\n", hr);
+ if (get_event((IMFMediaEventGenerator *)mediasource, MESourceStopped, &var))
+ ok(var.vt == VT_EMPTY, "Unexpected value type.\n");
+
+ var.vt = VT_I8;
+ var.uhVal.QuadPart = 0;
+ hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var);
+ ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr);
+
+ if (get_event((IMFMediaEventGenerator *)mediasource, MESourceStarted, &var))
+ ok(var.vt == VT_I8, "Unexpected value type.\n");
+
sample_count = 10;
for (i = 0; i < sample_count; ++i)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
index 0cc3b3c9c54..de6784ecac1 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -72,6 +72,7 @@ enum media_stream_flags
STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */
STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */
+ STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */
};
struct stream_transform
@@ -154,6 +155,7 @@ struct source_reader
IMFAsyncCallback stream_events_callback;
IMFAsyncCallback async_commands_callback;
LONG refcount;
+ LONG public_refcount;
IMFMediaSource *source;
IMFPresentationDescriptor *descriptor;
IMFSourceReaderCallback *async_callback;
@@ -171,6 +173,7 @@ struct source_reader
CRITICAL_SECTION cs;
CONDITION_VARIABLE sample_event;
CONDITION_VARIABLE state_event;
+ CONDITION_VARIABLE stop_event;
};
static inline struct source_reader *impl_from_IMFSourceReader(IMFSourceReader *iface)
@@ -203,6 +206,51 @@ static struct media_stream *impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVi
return CONTAINING_RECORD(iface, struct media_stream, notify_cb);
}
+static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream);
+
+static ULONG source_reader_addref(struct source_reader *reader)
+{
+ return InterlockedIncrement(&reader->refcount);
+}
+
+static ULONG source_reader_release(struct source_reader *reader)
+{
+ ULONG refcount = InterlockedDecrement(&reader->refcount);
+ unsigned int i;
+
+ if (!refcount)
+ {
+ if (reader->async_callback)
+ IMFSourceReaderCallback_Release(reader->async_callback);
+ if (reader->descriptor)
+ IMFPresentationDescriptor_Release(reader->descriptor);
+ if (reader->attributes)
+ IMFAttributes_Release(reader->attributes);
+ IMFMediaSource_Release(reader->source);
+
+ for (i = 0; i < reader->stream_count; ++i)
+ {
+ struct media_stream *stream = &reader->streams[i];
+
+ if (stream->stream)
+ IMFMediaStream_Release(stream->stream);
+ if (stream->current)
+ IMFMediaType_Release(stream->current);
+ if (stream->decoder.transform)
+ IMFTransform_Release(stream->decoder.transform);
+ if (stream->allocator)
+ IMFVideoSampleAllocatorEx_Release(stream->allocator);
+ }
+ source_reader_release_responses(reader, NULL);
+ free(reader->streams);
+ MFUnlockWorkQueue(reader->queue);
+ DeleteCriticalSection(&reader->cs);
+ free(reader);
+ }
+
+ return refcount;
+}
+
static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
{
if (IsEqualIID(riid, &IID_IUnknown))
@@ -325,13 +373,13 @@ static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *if
static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface)
{
struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
- return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
+ return source_reader_addref(reader);
}
static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface)
{
struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface);
- return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
+ return source_reader_release(reader);
}
static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface,
@@ -539,6 +587,8 @@ static HRESULT source_reader_source_state_handler(struct source_reader *reader,
LeaveCriticalSection(&reader->cs);
WakeAllConditionVariable(&reader->state_event);
+ if (event_type == MESourceStopped)
+ WakeAllConditionVariable(&reader->stop_event);
return S_OK;
}
@@ -594,7 +644,8 @@ static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallba
IMFMediaEvent_Release(event);
- IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
+ if (event_type != MESourceStopped)
+ IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
return S_OK;
}
@@ -611,13 +662,13 @@ static const IMFAsyncCallbackVtbl source_events_callback_vtbl =
static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface)
{
struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
- return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
+ return source_reader_addref(reader);
}
static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface)
{
struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface);
- return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
+ return source_reader_release(reader);
}
static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream)
@@ -810,6 +861,9 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re
case MEStreamStarted:
stream->state = STREAM_STATE_READY;
break;
+ case MEStreamStopped:
+ stream->flags |= STREAM_FLAG_STOPPED;
+ break;
case MEStreamTick:
value.vt = VT_EMPTY;
hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED;
@@ -829,6 +883,9 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re
LeaveCriticalSection(&reader->cs);
+ if (event_type == MEStreamStopped)
+ WakeAllConditionVariable(&reader->stop_event);
+
return S_OK;
}
@@ -858,6 +915,7 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba
break;
case MEStreamSeeked:
case MEStreamStarted:
+ case MEStreamStopped:
case MEStreamTick:
case MEEndOfStream:
hr = source_reader_media_stream_state_handler(reader, stream, event);
@@ -871,7 +929,8 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba
IMFMediaEvent_Release(event);
- IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
+ if (event_type != MEStreamStopped)
+ IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
return S_OK;
}
@@ -888,13 +947,13 @@ static const IMFAsyncCallbackVtbl stream_events_callback_vtbl =
static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface)
{
struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
- return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface);
+ return source_reader_addref(reader);
}
static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface)
{
struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface);
- return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
+ return source_reader_release(reader);
}
static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response)
@@ -1326,51 +1385,52 @@ static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID r
static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface)
{
struct source_reader *reader = impl_from_IMFSourceReader(iface);
- ULONG refcount = InterlockedIncrement(&reader->refcount);
+ ULONG refcount = InterlockedIncrement(&reader->public_refcount);
TRACE("%p, refcount %u.\n", iface, refcount);
return refcount;
}
+static BOOL source_reader_is_source_stopped(const struct source_reader *reader)
+{
+ unsigned int i;
+
+ if (reader->source_state != SOURCE_STATE_STOPPED)
+ return FALSE;
+
+ for (i = 0; i < reader->stream_count; ++i)
+ {
+ if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static ULONG WINAPI src_reader_Release(IMFSourceReader *iface)
{
struct source_reader *reader = impl_from_IMFSourceReader(iface);
- ULONG refcount = InterlockedDecrement(&reader->refcount);
- unsigned int i;
+ ULONG refcount = InterlockedDecrement(&reader->public_refcount);
TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount)
{
- if (reader->async_callback)
- IMFSourceReaderCallback_Release(reader->async_callback);
if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE)
IMFMediaSource_Shutdown(reader->source);
- if (reader->descriptor)
- IMFPresentationDescriptor_Release(reader->descriptor);
- if (reader->attributes)
- IMFAttributes_Release(reader->attributes);
- IMFMediaSource_Release(reader->source);
-
- for (i = 0; i < reader->stream_count; ++i)
+ else if (SUCCEEDED(IMFMediaSource_Stop(reader->source)))
{
- struct media_stream *stream = &reader->streams[i];
+ EnterCriticalSection(&reader->cs);
- if (stream->stream)
- IMFMediaStream_Release(stream->stream);
- if (stream->current)
- IMFMediaType_Release(stream->current);
- if (stream->decoder.transform)
- IMFTransform_Release(stream->decoder.transform);
- if (stream->allocator)
- IMFVideoSampleAllocatorEx_Release(stream->allocator);
+ while (!source_reader_is_source_stopped(reader))
+ {
+ SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE);
+ }
+
+ LeaveCriticalSection(&reader->cs);
}
- source_reader_release_responses(reader, NULL);
- free(reader->streams);
- MFUnlockWorkQueue(reader->queue);
- DeleteCriticalSection(&reader->cs);
- free(reader);
+ source_reader_release(reader);
}
return refcount;
@@ -2277,6 +2337,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri
object->source_events_callback.lpVtbl = &source_events_callback_vtbl;
object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl;
object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl;
+ object->public_refcount = 1;
object->refcount = 1;
list_init(&object->responses);
if (shutdown_on_release)
@@ -2286,6 +2347,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri
InitializeCriticalSection(&object->cs);
InitializeConditionVariable(&object->sample_event);
InitializeConditionVariable(&object->state_event);
+ InitializeConditionVariable(&object->stop_event);
if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
goto failed;
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c
index e3ff7f6e7aa..aec7d7456ca 100644
--- a/dlls/mfreadwrite/tests/mfplat.c
+++ b/dlls/mfreadwrite/tests/mfplat.c
@@ -865,7 +865,8 @@ todo_wine
hr = IMFSourceReader_Flush(reader, MF_SOURCE_READER_ALL_STREAMS);
ok(hr == S_OK, "Failed to flush all streams, hr %#x.\n", hr);
- IMFSourceReader_Release(reader);
+ refcount = IMFSourceReader_Release(reader);
+ ok(!refcount, "Unexpected refcount %u.\n", refcount);
/* Async mode. */
callback = create_async_callback();
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index 7ed1dfd2adc..1bfeeebd5a7 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -1685,15 +1685,33 @@ static HRESULT WINAPI DOMMouseEvent_get_pageY(IDOMMouseEvent *iface, LONG *p)
static HRESULT WINAPI DOMMouseEvent_get_layerX(IDOMMouseEvent *iface, LONG *p)
{
DOMEvent *This = impl_from_IDOMMouseEvent(iface);
- FIXME("(%p)->(%p)\n", This, p);
- return E_NOTIMPL;
+ nsresult nsres;
+ LONG r;
+
+ TRACE("(%p)->(%p)\n", This, p);
+
+ nsres = nsIDOMMouseEvent_GetLayerX(This->mouse_event, &r);
+ if(NS_FAILED(nsres))
+ return E_FAIL;
+
+ *p = r;
+ return S_OK;
}
static HRESULT WINAPI DOMMouseEvent_get_layerY(IDOMMouseEvent *iface, LONG *p)
{
DOMEvent *This = impl_from_IDOMMouseEvent(iface);
- FIXME("(%p)->(%p)\n", This, p);
- return E_NOTIMPL;
+ nsresult nsres;
+ LONG r;
+
+ TRACE("(%p)->(%p)\n", This, p);
+
+ nsres = nsIDOMMouseEvent_GetLayerY(This->mouse_event, &r);
+ if(NS_FAILED(nsres))
+ return E_FAIL;
+
+ *p = r;
+ return S_OK;
}
static HRESULT WINAPI DOMMouseEvent_get_which(IDOMMouseEvent *iface, USHORT *p)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index 14afad5fb45..28794d1c7b8 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include "msvcrt.h"
#include "winternl.h"
@@ -64,11 +65,23 @@ typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *);
static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL;
+BOOL erms_supported;
BOOL sse2_supported;
static BOOL sse2_enabled;
void msvcrt_init_math( void *module )
{
+#if defined(__i386__) || defined(__x86_64__)
+ int regs[4];
+
+ __cpuid(regs, 0);
+ if (regs[0] >= 7)
+ {
+ __cpuidex(regs, 7, 0);
+ erms_supported = ((regs[1] >> 9) & 1);
+ }
+#endif
+
sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE );
#if _MSVCR_VER <=71
sse2_enabled = FALSE;
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index e50f3e6991b..348eda2afbd 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -33,6 +33,7 @@
#undef strncpy
#undef wcsncpy
+extern BOOL erms_supported DECLSPEC_HIDDEN;
extern BOOL sse2_supported DECLSPEC_HIDDEN;
#define DBL80_MAX_10_EXP 4932
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index d92b7a38d12..01c10cd7e36 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -2941,6 +2941,13 @@ __ASM_GLOBAL_FUNC( sse2_memmove,
MEMMOVE_CLEANUP
"ret" )
+#undef MEMMOVE_INIT
+#undef MEMMOVE_CLEANUP
+#undef DEST_REG
+#undef SRC_REG
+#undef LEN_REG
+#undef TMP_REG
+
#endif
/*********************************************************************
@@ -3075,6 +3082,78 @@ void * __cdecl _memccpy(void *dst, const void *src, int c, size_t n)
return NULL;
}
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifdef __i386__
+#define DEST_REG "%edi"
+#define LEN_REG "%ecx"
+#define VAL_REG "%eax"
+
+#define MEMSET_INIT \
+ "movl " DEST_REG ", %edx\n\t" \
+ "movl 4(%esp), " DEST_REG "\n\t" \
+ "movl 8(%esp), " VAL_REG "\n\t" \
+ "movl 12(%esp), " LEN_REG "\n\t"
+
+#define MEMSET_RET \
+ "movl %edx, " DEST_REG "\n\t" \
+ "ret"
+
+#else
+
+#define DEST_REG "%rdi"
+#define LEN_REG "%rcx"
+#define VAL_REG "%eax"
+
+#define MEMSET_INIT \
+ "movq " DEST_REG ", %r9\n\t" \
+ "movq %rcx, " DEST_REG "\n\t" \
+ "movl %edx, " VAL_REG "\n\t" \
+ "movq %r8, " LEN_REG "\n\t"
+
+#define MEMSET_RET \
+ "movq %r9, " DEST_REG "\n\t" \
+ "ret"
+
+#endif
+
+void __cdecl erms_memset_aligned_32(unsigned char *d, unsigned int c, size_t n);
+__ASM_GLOBAL_FUNC( erms_memset_aligned_32,
+ MEMSET_INIT
+ "rep\n\t"
+ "stosb\n\t"
+ MEMSET_RET )
+
+void __cdecl sse2_memset_aligned_32(unsigned char *d, unsigned int c, size_t n);
+__ASM_GLOBAL_FUNC( sse2_memset_aligned_32,
+ MEMSET_INIT
+ "movd " VAL_REG ", %xmm0\n\t"
+ "pshufd $0, %xmm0, %xmm0\n\t"
+ "test $0x20, " LEN_REG "\n\t"
+ "je 1f\n\t"
+ "add $0x20, " DEST_REG "\n\t"
+ "sub $0x20, " LEN_REG "\n\t"
+ "movdqa %xmm0, -0x20(" DEST_REG ")\n\t"
+ "movdqa %xmm0, -0x10(" DEST_REG ")\n\t"
+ "je 2f\n\t"
+ "1:\n\t"
+ "add $0x40, " DEST_REG "\n\t"
+ "sub $0x40, " LEN_REG "\n\t"
+ "movdqa %xmm0, -0x40(" DEST_REG ")\n\t"
+ "movdqa %xmm0, -0x30(" DEST_REG ")\n\t"
+ "movdqa %xmm0, -0x20(" DEST_REG ")\n\t"
+ "movdqa %xmm0, -0x10(" DEST_REG ")\n\t"
+ "ja 1b\n\t"
+ "2:\n\t"
+ MEMSET_RET )
+
+#undef MEMSET_INIT
+#undef MEMSET_RET
+#undef DEST_REG
+#undef LEN_REG
+#undef VAL_REG
+
+#endif
static inline void memset_aligned_32(unsigned char *d, uint64_t v, size_t n)
{
@@ -3116,8 +3195,27 @@ void *__cdecl memset(void *dst, int c, size_t n)
if (n <= 64) return dst;
n = (n - a) & ~0x1f;
+#if defined(__i386__) || defined(__x86_64__)
+ if (n >= 2048 && erms_supported)
+ {
+ erms_memset_aligned_32(d + a, v, n);
+ return dst;
+ }
+#ifdef __x86_64__
+ sse2_memset_aligned_32(d + a, v, n);
+ return dst;
+#else
+ if (sse2_supported)
+ {
+ sse2_memset_aligned_32(d + a, v, n);
+ return dst;
+ }
+#endif
+#endif
+#ifndef __x86_64__
memset_aligned_32(d + a, v, n);
return dst;
+#endif
}
if (n >= 8)
{
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 5fc956b1dc4..4cec391cf8b 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -240,7 +240,41 @@ void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *ar
__ENDTRY
}
-#else /* __i386__ */
+#elif /* __i386__ */ defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED)
+EXCEPTION_DISPOSITION WINAPI call_thread_func_handler( EXCEPTION_RECORD *rec, ULONG64 frame,
+ CONTEXT *context, DISPATCHER_CONTEXT *dispatch )
+{
+ EXCEPTION_POINTERS ep = { rec, context };
+
+ WARN( "Unhandled exception, calling filter.\n" );
+
+ switch (call_unhandled_exception_filter( &ep ))
+ {
+ case EXCEPTION_CONTINUE_SEARCH:
+ return ExceptionContinueSearch;
+ case EXCEPTION_CONTINUE_EXECUTION:
+ return ExceptionContinueExecution;
+ case EXCEPTION_EXECUTE_HANDLER:
+ break;
+ }
+ NtTerminateProcess( GetCurrentProcess(), rec->ExceptionCode );
+ return ExceptionContinueExecution;
+}
+
+extern void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg );
+__ASM_GLOBAL_FUNC( RtlUserThreadStart,
+ "subq $0x28, %rsp\n\t"
+ __ASM_SEH(".seh_stackalloc 0x28\n\t")
+ __ASM_SEH(".seh_endprologue\n\t")
+ "movq %rdx,%r8\n\t"
+ "movq %rcx,%rdx\n\t"
+ "xorq %rcx,%rcx\n\t"
+ "movq pBaseThreadInitThunk(%rip),%r9\n\t"
+ "call *%r9\n\t"
+ "int3\n\t"
+ __ASM_SEH(".seh_handler call_thread_func_handler, @except\n\t") )
+
+#else /* defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED) */
void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
{
diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c
index 55c5695964d..4663374653a 100644
--- a/dlls/ntdll/unix/esync.c
+++ b/dlls/ntdll/unix/esync.c
@@ -526,6 +526,9 @@ NTSTATUS esync_set_event( HANDLE handle )
if ((ret = get_object( handle, &obj ))) return ret;
event = obj->shm;
+ if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT)
+ return STATUS_OBJECT_TYPE_MISMATCH;
+
if (obj->type == ESYNC_MANUAL_EVENT)
{
/* Acquire the spinlock. */
diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c
index 39d969f061d..0f19c63a5f2 100644
--- a/dlls/ntdll/unix/fsync.c
+++ b/dlls/ntdll/unix/fsync.c
@@ -112,6 +112,15 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v
waitv->__reserved = 0;
}
+static void simulate_sched_quantum(void)
+{
+ if (!fsync_simulate_sched_quantum) return;
+ /* futex wait is often very quick to resume a waiting thread when woken.
+ * That reveals synchonization bugs in some games which happen to work on
+ * Windows due to the waiting threads having some minimal delay to wake up. */
+ usleep(0);
+}
+
static inline int futex_wait_multiple( const struct futex_waitv *futexes,
int count, const ULONGLONG *end )
{
@@ -576,6 +585,9 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev )
if ((ret = get_object( handle, &obj ))) return ret;
event = obj->shm;
+ if (obj->type != FSYNC_MANUAL_EVENT && obj->type != FSYNC_AUTO_EVENT)
+ return STATUS_OBJECT_TYPE_MISMATCH;
+
if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )))
futex_wake( &event->signaled, INT_MAX );
@@ -753,8 +765,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1];
struct fsync *objs[MAXIMUM_WAIT_OBJECTS];
+ BOOL msgwait = FALSE, waited = FALSE;
int has_fsync = 0, has_server = 0;
- BOOL msgwait = FALSE;
int dummy_futex = 0;
unsigned int spin;
LONGLONG timeleft;
@@ -876,6 +888,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
&& __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current)
{
TRACE("Woken up by handle %p [%d].\n", handles[i], i);
+ if (waited) simulate_sched_quantum();
return i;
}
small_pause();
@@ -893,6 +906,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
{
TRACE("Woken up by handle %p [%d].\n", handles[i], i);
mutex->count++;
+ if (waited) simulate_sched_quantum();
return i;
}
@@ -902,6 +916,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
{
TRACE("Woken up by handle %p [%d].\n", handles[i], i);
mutex->count = 1;
+ if (waited) simulate_sched_quantum();
return i;
}
else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0)
@@ -929,6 +944,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
usleep( 0 );
TRACE("Woken up by handle %p [%d].\n", handles[i], i);
+ if (waited) simulate_sched_quantum();
return i;
}
small_pause();
@@ -951,6 +967,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
usleep( 0 );
TRACE("Woken up by handle %p [%d].\n", handles[i], i);
+ if (waited) simulate_sched_quantum();
return i;
}
small_pause();
@@ -1005,6 +1022,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles,
TRACE("Wait timed out.\n");
return STATUS_TIMEOUT;
}
+ else waited = TRUE;
} /* while (1) */
}
else
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 1d4160727e4..f078a967be8 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -2237,33 +2237,30 @@ static struct unix_funcs unix_funcs =
};
BOOL ac_odyssey;
+BOOL fsync_simulate_sched_quantum;
static void hacks_init(void)
{
+ static const char upc_exe[] = "Ubisoft Game Launcher\\upc.exe";
static const char ac_odyssey_exe[] = "ACOdyssey.exe";
- char cur_exe[MAX_PATH];
- DWORD cur_exe_len;
- const char *sgi;
- int fd;
-
- fd = open("/proc/self/comm", O_RDONLY);
- cur_exe_len = read(fd, cur_exe, sizeof(cur_exe));
- close(fd);
- cur_exe[cur_exe_len - 1] = 0;
+ const char *env_str;
- if (!strcasecmp(cur_exe, ac_odyssey_exe))
+ if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe))
{
- if (do_esync() || do_fsync())
- ERR("HACK: AC Odyssey sync tweak on.\n");
- else
- ERR("Not enabling AC Odyssey sync tweak as esync and fsync are disabled.\n");
-
+ ERR("HACK: AC Odyssey sync tweak on.\n");
ac_odyssey = TRUE;
return;
}
+ env_str = getenv("WINE_FSYNC_SIMULATE_SCHED_QUANTUM");
+ if (env_str)
+ fsync_simulate_sched_quantum = !!atoi(env_str);
+ else if (main_argc > 1)
+ fsync_simulate_sched_quantum = !!strstr(main_argv[1], upc_exe);
+ if (fsync_simulate_sched_quantum)
+ ERR("HACK: Simulating sched quantum in fsync.\n");
- sgi = getenv("SteamGameId");
- if (sgi && !strcmp(sgi, "50130"))
+ env_str = getenv("SteamGameId");
+ if (env_str && !strcmp(env_str, "50130"))
setenv("WINESTEAMNOEXEC", "1", 0);
}
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index eaa41d9e139..ff4dbedccac 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -835,6 +835,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
(DWORD)IP_sig(context), (DWORD)SP_sig(context), (DWORD)LR_sig(context),
(DWORD)PC_sig(context), (DWORD)CPSR_sig(context) );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION
+ && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] ))
+ ERR_(seh)( "Syscall stack overrun.\n ");
+
if (ntdll_get_thread_data()->jmp_buf)
{
TRACE( "returning to handler\n" );
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
index 26910173b81..ba3e3564c1a 100644
--- a/dlls/ntdll/unix/signal_arm64.c
+++ b/dlls/ntdll/unix/signal_arm64.c
@@ -860,6 +860,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
(DWORD64)REGn_sig(28, context), (DWORD64)FP_sig(context),
(DWORD64)LR_sig(context), (DWORD64)SP_sig(context) );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION
+ && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] ))
+ ERR_(seh)( "Syscall stack overrun.\n ");
+
if (ntdll_get_thread_data()->jmp_buf)
{
TRACE( "returning to handler\n" );
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index 53da5d3ac59..a0afd33ea13 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1757,6 +1757,10 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr,
context->Ebp, context->Esp, context->SegCs, context->SegDs,
context->SegEs, context->SegFs, context->SegGs, context->EFlags );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION
+ && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] ))
+ ERR_(seh)( "Syscall stack overrun.\n ");
+
if (ntdll_get_thread_data()->jmp_buf)
{
TRACE( "returning to handler\n" );
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 7d7f9090986..b1cc682649b 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2792,6 +2792,10 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec,
TRACE_(seh)( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
context->R12, context->R13, context->R14, context->R15 );
+ if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION
+ && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] ))
+ ERR_(seh)( "Syscall stack overrun.\n ");
+
if (ntdll_get_thread_data()->jmp_buf)
{
TRACE_(seh)( "returning to handler\n" );
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index af0c53d441e..58b7502ef06 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -77,6 +77,46 @@ static const char *debugstr_timeout( const LARGE_INTEGER *timeout )
return wine_dbgstr_longlong( timeout->QuadPart );
}
+#ifndef __NR_clock_gettime64
+#define __NR_clock_gettime64 403
+#endif
+
+struct timespec64
+{
+ long long tv_sec;
+ long long tv_nsec;
+};
+
+static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks )
+{
+ static int clock_gettime64_supported = -1;
+ struct timespec64 ts64;
+ struct timespec ts;
+ int ret;
+
+ if (clock_gettime64_supported < 0)
+ {
+ if (!syscall( __NR_clock_gettime64, clock_id, &ts64 ))
+ {
+ clock_gettime64_supported = 1;
+ *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100;
+ return 0;
+ }
+ clock_gettime64_supported = 0;
+ }
+
+ if (clock_gettime64_supported)
+ {
+ if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 )))
+ *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100;
+ return ret;
+ }
+
+ if (!(ret = clock_gettime( clock_id, &ts )))
+ *ticks = ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
+ return ret;
+}
+
/* return a monotonic time counter, in Win32 ticks */
static inline ULONGLONG monotonic_counter(void)
{
@@ -91,13 +131,13 @@ static inline ULONGLONG monotonic_counter(void)
#endif
return mach_absolute_time() * timebase.numer / timebase.denom / 100;
#elif defined(HAVE_CLOCK_GETTIME)
- struct timespec ts;
+ ULONGLONG ticks;
#if 0
- if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
- return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
+ if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks ))
+ return ticks;
#endif
- if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
- return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
+ if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks ))
+ return ticks;
#endif
gettimeofday( &now, 0 );
return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10 - server_start_time;
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 5f072956087..4bf0e7cb84e 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -88,7 +88,8 @@ static const SIZE_T teb_size = 0x3800; /* TEB64 + TEB32 + debug info */
static const SIZE_T signal_stack_mask = 0xffff;
static const SIZE_T signal_stack_size = 0x10000 - 0x3800;
static const SIZE_T kernel_stack_size = 0x60000;
-static const SIZE_T min_kernel_stack = 0x2000;
+static const SIZE_T kernel_stack_guard_size = 0x1000;
+static const SIZE_T min_kernel_stack = 0x3000;
static const LONG teb_offset = 0x2000;
#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
@@ -147,6 +148,7 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN;
#endif
extern BOOL ac_odyssey DECLSPEC_HIDDEN;
+extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN;
extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN;
extern void init_startup_info(void) DECLSPEC_HIDDEN;
@@ -330,6 +332,13 @@ static inline BOOL is_inside_signal_stack( void *ptr )
(char *)ptr < (char *)get_signal_stack() + signal_stack_size);
}
+static inline BOOL is_inside_syscall_stack_guard( const char *stack_ptr )
+{
+ const char *kernel_stack = ntdll_get_thread_data()->kernel_stack;
+
+ return (stack_ptr >= kernel_stack && stack_ptr < kernel_stack + kernel_stack_guard_size);
+}
+
static inline void mutex_lock( pthread_mutex_t *mutex )
{
if (!process_exiting) pthread_mutex_lock( mutex );
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index e7caf162ee1..10e2bf1477c 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -3225,6 +3225,7 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI
SIZE_T commit_size, SIZE_T extra_size )
{
struct file_view *view;
+ char *kernel_stack;
NTSTATUS status;
sigset_t sigset;
SIZE_T size;
@@ -3268,6 +3269,10 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI
delete_view( view );
goto done;
}
+ /* setup kernel stack no access guard page */
+ kernel_stack = (char *)view->base + view->size;
+ set_page_vprot( kernel_stack, kernel_stack_guard_size, VPROT_COMMITTED );
+ mprotect_range( kernel_stack, kernel_stack_guard_size, 0, 0 );
}
/* note: limit is lower than base since the stack grows down */
diff --git a/dlls/urlmon/binding.c b/dlls/urlmon/binding.c
index 708b81194c7..a74970033b3 100644
--- a/dlls/urlmon/binding.c
+++ b/dlls/urlmon/binding.c
@@ -1177,14 +1177,6 @@ static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *i
TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
- /* Make sure we don't call stop_binding before available data has been reported,
- as some custom protocol handlers call ReportResult within LockRequest */
- if (!(This->state & BINDING_LOCKED) && hrResult == S_OK)
- {
- This->download_state = END_DOWNLOAD;
- return S_OK;
- }
-
stop_binding(This, hrResult, szResult);
IInternetProtocolEx_Terminate(&This->protocol->IInternetProtocolEx_iface, 0);
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c
index 2afe5667a04..f081c4b7ee6 100644
--- a/dlls/user32/focus.c
+++ b/dlls/user32/focus.c
@@ -40,7 +40,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win);
*
* Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
*/
-static HWND set_focus_window( HWND hwnd, BOOL from_active )
+static HWND set_focus_window( HWND hwnd, BOOL from_active, BOOL force )
{
HWND previous = 0, ime_default;
BOOL ret;
@@ -53,7 +53,7 @@ static HWND set_focus_window( HWND hwnd, BOOL from_active )
}
SERVER_END_REQ;
if (!ret) return 0;
- if (previous == hwnd) return previous;
+ if (!force && hwnd == previous) return previous;
if (previous)
{
@@ -90,7 +90,7 @@ static HWND set_focus_window( HWND hwnd, BOOL from_active )
static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
{
HWND previous = GetActiveWindow();
- BOOL ret;
+ BOOL ret = FALSE;
DWORD old_thread, new_thread;
CBTACTIVATESTRUCT cbt;
@@ -100,10 +100,13 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
return TRUE;
}
+ if (prev) *prev = previous;
+ if (win_set_flags( hwnd, WIN_IS_ACTIVATING, 0 ) & WIN_IS_ACTIVATING) return TRUE;
+
/* call CBT hook chain */
cbt.fMouse = mouse;
cbt.hWndActive = previous;
- if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
+ if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) goto done;
if (IsWindow(previous))
{
@@ -115,13 +118,14 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
SERVER_START_REQ( set_active_window )
{
req->handle = wine_server_user_handle( hwnd );
+ req->internal_msg = WM_WINE_SETACTIVEWINDOW;
if ((ret = !wine_server_call_err( req )))
previous = wine_server_ptr_handle( reply->previous );
}
SERVER_END_REQ;
- if (!ret) return FALSE;
+ if (!ret) goto done;
if (prev) *prev = previous;
- if (previous == hwnd) return TRUE;
+ if (previous == hwnd) goto done;
if (hwnd)
{
@@ -129,7 +133,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
SMTO_ABORTIFHUNG, 2000, NULL );
- if (!IsWindow(hwnd)) return FALSE;
+ if (!(ret = IsWindow( hwnd ))) goto done;
}
old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
@@ -163,7 +167,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
if (IsWindow(hwnd))
{
- SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous );
+ SendMessageW( hwnd, WM_NCACTIVATE,
+ (hwnd == GetForegroundWindow()) && !(win_get_flags(previous) & WIN_IS_ACTIVATING),
+ (LPARAM)previous );
SendMessageW( hwnd, WM_ACTIVATE,
MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
(LPARAM)previous );
@@ -188,11 +194,13 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
if (hwnd == info.hwndActive)
{
if (!info.hwndFocus || !hwnd || GetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
- set_focus_window( hwnd, TRUE );
+ set_focus_window( hwnd, TRUE, FALSE );
}
}
- return TRUE;
+done:
+ win_set_flags( hwnd, 0, WIN_IS_ACTIVATING );
+ return ret;
}
@@ -219,12 +227,16 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
if (ret && previous != hwnd)
{
if (send_msg_old) /* old window belongs to other thread */
- SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
+ PostMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
else if (send_msg_new) /* old window belongs to us but new one to other thread */
ret = set_active_window( 0, NULL, mouse, TRUE );
+ /* already active, set_active_window will do no nothing */
+ if (!send_msg_new && hwnd == GetActiveWindow())
+ SendMessageW( hwnd, WM_NCACTIVATE, TRUE, (LPARAM)hwnd );
+
if (send_msg_new) /* new window belongs to other thread */
- SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
+ PostMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
else /* new window belongs to us */
ret = set_active_window( hwnd, NULL, mouse, TRUE );
}
@@ -329,7 +341,7 @@ HWND WINAPI SetFocus( HWND hwnd )
}
/* change focus and send messages */
- return set_focus_window( hwnd, FALSE );
+ return set_focus_window( hwnd, FALSE, hwnd != previous );
}
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index 183912cd653..988ef999edb 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -1876,7 +1876,8 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR
if (is_desktop_window( hwnd )) return 0;
return WIN_SetStyle(hwnd, wparam, lparam);
case WM_WINE_SETACTIVEWINDOW:
- if (!wparam && GetForegroundWindow() == hwnd) return 0;
+ if (!wparam && GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId())
+ return 0;
return (LRESULT)SetActiveWindow( (HWND)wparam );
case WM_WINE_KEYBOARD_LL_HOOK:
case WM_WINE_MOUSE_LL_HOOK:
diff --git a/dlls/user32/win.h b/dlls/user32/win.h
index 45d3acce7bc..4e9dc9efd38 100644
--- a/dlls/user32/win.h
+++ b/dlls/user32/win.h
@@ -80,6 +80,7 @@ typedef struct tagWND
#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */
#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */
#define WIN_IS_TOUCH 0x0100 /* the window has been registered for touch input */
+#define WIN_IS_ACTIVATING 0x0200 /* the window is being activated */
/* Window functions */
extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;
diff --git a/dlls/userenv/tests/userenv.c b/dlls/userenv/tests/userenv.c
index a91edeef260..c7a6791e2be 100644
--- a/dlls/userenv/tests/userenv.c
+++ b/dlls/userenv/tests/userenv.c
@@ -78,7 +78,7 @@ static void test_create_env(void)
BOOL r, is_wow64 = FALSE;
HANDLE htok;
WCHAR * env[4];
- char * st, systemroot[100];
+ char * st, systemroot[100], programdata[100];
int i, j;
static const struct profile_item common_vars[] = {
@@ -96,6 +96,7 @@ static void test_create_env(void)
};
static const struct profile_item common_post_nt4_vars[] = {
{ "ALLUSERSPROFILE" },
+ { "ProgramData" },
{ "TEMP" },
{ "TMP" },
{ "CommonProgramFiles" },
@@ -119,6 +120,12 @@ static void test_create_env(void)
r = SetEnvironmentVariableA("SystemRoot", "overwrite");
expect(TRUE, r);
+ r = GetEnvironmentVariableA("ProgramData", programdata, sizeof(programdata));
+ ok(r != 0, "GetEnvironmentVariable failed (%d)\n", GetLastError());
+
+ r = SetEnvironmentVariableA("ProgramData", "overwrite");
+ expect(TRUE, r);
+
if (0)
{
/* Crashes on NT4 */
@@ -151,12 +158,20 @@ static void test_create_env(void)
r = SetEnvironmentVariableA("SystemRoot", systemroot);
expect(TRUE, r);
+ r = SetEnvironmentVariableA("ProgramData", programdata);
+ expect(TRUE, r);
+
for(i=0; i<4; i++)
{
r = get_env(env[i], "SystemRoot", &st);
ok(!strcmp(st, "SystemRoot=overwrite"), "%s\n", st);
expect(TRUE, r);
HeapFree(GetProcessHeap(), 0, st);
+
+ r = get_env(env[i], "ProgramData", &st);
+ ok(strcmp(st, "ProgramData=overwrite"), "%s\n", st);
+ expect(TRUE, r);
+ HeapFree(GetProcessHeap(), 0, st);
}
/* Test for common environment variables (NT4 and higher) */
diff --git a/dlls/userenv/userenv_main.c b/dlls/userenv/userenv_main.c
index 87ace7d5c11..08dede60d35 100644
--- a/dlls/userenv/userenv_main.c
+++ b/dlls/userenv/userenv_main.c
@@ -243,7 +243,10 @@ BOOL WINAPI CreateEnvironmentBlock( LPVOID* lpEnvironment,
}
if (get_reg_value(env, hkey, L"Public", buf, UNICODE_STRING_MAX_CHARS))
+ {
set_env_var(&env, L"ALLUSERSPROFILE", buf);
+ set_env_var(&env, L"ProgramData", buf);
+ }
}
else
{
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index 26191ccb3a5..c5b45920d2e 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -187,12 +187,13 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl)
!(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick)))
impl->effect_support = 0;
else
+ {
impl->effect_support = pSDL_HapticQuery(impl->sdl_haptic);
-
- if (!(impl->effect_support & EFFECT_SUPPORT_HAPTICS) &&
- pSDL_HapticRumbleSupported(impl->sdl_haptic) &&
- pSDL_HapticRumbleInit(impl->sdl_haptic) == 0)
- impl->effect_support |= WINE_SDL_HAPTIC_RUMBLE;
+ if (!(impl->effect_support & EFFECT_SUPPORT_HAPTICS) &&
+ pSDL_HapticRumbleSupported(impl->sdl_haptic) &&
+ pSDL_HapticRumbleInit(impl->sdl_haptic) == 0)
+ impl->effect_support |= WINE_SDL_HAPTIC_RUMBLE;
+ }
if (!(impl->effect_support & EFFECT_SUPPORT_HAPTICS) && pSDL_JoystickRumble &&
!pSDL_JoystickRumble(impl->sdl_joystick, 0, 0, 0))
diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c
index c2f8e163067..b0043c0de7e 100644
--- a/dlls/winebus.sys/unixlib.c
+++ b/dlls/winebus.sys/unixlib.c
@@ -72,6 +72,7 @@ BOOL is_sdl_blacklisted(DWORD vid, DWORD pid)
BOOL is_steam_controller(WORD vid, WORD pid)
{
+ if (vid == 0x2808 && pid == 0x1015) return TRUE; /* Steam Deck touchscreen */
if (vid != 0x28de) return FALSE;
if (pid == 0x1101) return TRUE; /* Valve Legacy Steam Controller */
if (pid == 0x1102) return TRUE; /* Valve wired Steam Controller */
@@ -80,6 +81,7 @@ BOOL is_steam_controller(WORD vid, WORD pid)
if (pid == 0x1142) return TRUE; /* Valve wireless Steam Controller */
if (pid == 0x1201) return TRUE; /* Valve wired Steam Controller */
if (pid == 0x1202) return TRUE; /* Valve Bluetooth Steam Controller */
+ if (pid == 0x1205) return TRUE; /* Valve Steam Deck Mouse / Keyboard */
return FALSE;
}
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c
index 9fd2ed67dcc..8e8305352fe 100644
--- a/dlls/wined3d/context_gl.c
+++ b/dlls/wined3d/context_gl.c
@@ -1897,7 +1897,7 @@ HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc,
}
static BOOL wined3d_context_gl_create_wgl_ctx(struct wined3d_context_gl *context_gl,
- struct wined3d_swapchain_gl *swapchain_gl)
+ struct wined3d_swapchain_gl *swapchain_gl, BOOL *new_drawable)
{
enum wined3d_swap_effect swap_effect = swapchain_gl->s.state.desc.swap_effect;
const struct wined3d_format *colour_format, *ds_format;
@@ -1920,6 +1920,8 @@ static BOOL wined3d_context_gl_create_wgl_ctx(struct wined3d_context_gl *context
swap_effect_copy = swap_effect == WINED3D_SWAP_EFFECT_COPY || swap_effect == WINED3D_SWAP_EFFECT_COPY_VSYNC;
+ *new_drawable = !GetPixelFormat(context_gl->dc);
+
if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
{
static const enum wined3d_format_id ds_formats[] =
@@ -2018,7 +2020,7 @@ static BOOL wined3d_context_gl_create_wgl_ctx(struct wined3d_context_gl *context
}
context_gl->dc_is_private = TRUE;
- return wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl);
+ return wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl, new_drawable);
}
share_ctx = device->context_count ? wined3d_context_gl(device->contexts[0])->gl_ctx : NULL;
@@ -2064,6 +2066,7 @@ HRESULT wined3d_context_gl_init(struct wined3d_context_gl *context_gl, struct wi
const struct wined3d_d3d_info *d3d_info;
const struct wined3d_gl_info *gl_info;
struct wined3d_device *device;
+ BOOL new_drawable;
unsigned int i;
TRACE("context_gl %p, swapchain %p.\n", context_gl, swapchain_gl);
@@ -2142,7 +2145,7 @@ HRESULT wined3d_context_gl_init(struct wined3d_context_gl *context_gl, struct wi
sizeof(*context_gl->texture_type))))
goto fail;
- if (!wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl))
+ if (!wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl, &new_drawable))
goto fail;
/* Set up the context defaults. */
@@ -2299,6 +2302,14 @@ HRESULT wined3d_context_gl_init(struct wined3d_context_gl *context_gl, struct wi
gl_info->gl_ops.gl.p_glScissor(0, 0, 0, 0);
checkGLcall("glScissor");
+ if (new_drawable)
+ {
+ gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ gl_info->gl_ops.gl.p_glClearDepth(1.0f);
+ gl_info->gl_ops.gl.p_glClearStencil(0);
+ gl_info->gl_ops.gl.p_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ checkGLcall("glClear");
+ }
return WINED3D_OK;
fail:
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 49a40f3e1d6..5fcbfc58779 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -459,8 +459,9 @@ static void swapchain_blit_gdi(struct wined3d_swapchain *swapchain,
if (!(dst_dc = GetDCEx(swapchain->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
ERR("Failed to get destination DC.\n");
- if (!BitBlt(dst_dc, dst_rect->left, dst_rect->top, dst_rect->right - dst_rect->left,
- dst_rect->bottom - dst_rect->top, src_dc, src_rect->left, src_rect->top, SRCCOPY))
+ if (!StretchBlt(dst_dc, dst_rect->left, dst_rect->top, dst_rect->right - dst_rect->left,
+ dst_rect->bottom - dst_rect->top, src_dc, src_rect->left, src_rect->top,
+ src_rect->right - src_rect->left, src_rect->bottom - src_rect->top, SRCCOPY))
ERR("Failed to blit.\n");
ReleaseDC(swapchain->win_handle, dst_dc);
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 3b456aea3a2..4d9b9cb10fe 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -82,7 +82,7 @@ uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN;
struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN;
void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) DECLSPEC_HIDDEN;
-void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) DECLSPEC_HIDDEN;
+void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture, uint32_t flags) DECLSPEC_HIDDEN;
void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN;
bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) DECLSPEC_HIDDEN;
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c
index daa1a738c38..f6a4d47188f 100644
--- a/dlls/winegstreamer/h264_decoder.c
+++ b/dlls/winegstreamer/h264_decoder.c
@@ -520,7 +520,19 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I
static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
{
+ struct h264_decoder *decoder = impl_from_IMFTransform(iface);
+
FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param);
+
+ switch (message)
+ {
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ memset(&decoder->wg_format, 0, sizeof(decoder->wg_format));
+ break;
+ default:
+ break;
+ }
+
return S_OK;
}
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index 60651541dbc..8c6d8268541 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -180,13 +180,14 @@ void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, stru
__wine_unix_call(unix_handle, unix_wg_parser_stream_get_preferred_format, ¶ms);
}
-void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture)
+void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture, uint32_t flags)
{
struct wg_parser_stream_enable_params params =
{
.stream = stream,
.format = format,
.aperture = aperture,
+ .flags = flags,
};
__wine_unix_call(unix_handle, unix_wg_parser_stream_enable, ¶ms);
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 7d28fb26636..a41205c6e34 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -357,7 +357,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm
IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt);
mf_media_type_to_wg_format(current_mt, &format);
- wg_parser_stream_enable(stream->wg_stream, &format, NULL);
+ wg_parser_stream_enable(stream->wg_stream, &format, NULL, 0);
IMFMediaType_Release(current_mt);
IMFMediaTypeHandler_Release(mth);
@@ -872,7 +872,7 @@ static HRESULT new_media_stream(struct media_source *source,
static HRESULT media_stream_init_desc(struct media_stream *stream)
{
IMFMediaTypeHandler *type_handler = NULL;
- IMFMediaType *stream_types[7];
+ IMFMediaType *stream_types[8];
struct wg_format format;
DWORD type_count = 0;
unsigned int i;
@@ -892,6 +892,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream)
&MFVideoFormat_IYUV,
&MFVideoFormat_I420,
&MFVideoFormat_ARGB32,
+ &MFVideoFormat_RGB32,
};
IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c
index 2782f773beb..a58fa39e87e 100644
--- a/dlls/winegstreamer/quartz_parser.c
+++ b/dlls/winegstreamer/quartz_parser.c
@@ -1179,7 +1179,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
if (!(object = calloc(1, sizeof(*object))))
return E_OUTOFMEMORY;
- if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false)))
+ if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true)))
{
free(object);
return E_OUTOFMEMORY;
@@ -1533,7 +1533,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface,
ret = amt_to_wg_format(&pin->pin.pin.mt, &format);
assert(ret);
- wg_parser_stream_enable(pin->wg_stream, &format, NULL);
+ wg_parser_stream_enable(pin->wg_stream, &format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB);
/* We do need to drop any buffers that might have been sent with the old
* caps, but this will be handled in parser_init_stream(). */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index 79f68695fd8..0be6d267c1f 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -243,11 +243,14 @@ struct wg_parser_stream_get_preferred_format_params
struct wg_format *format;
};
+#define STREAM_ENABLE_FLAG_FLIP_RGB 0x1
+
struct wg_parser_stream_enable_params
{
struct wg_parser_stream *stream;
const struct wg_format *format;
const struct wg_rect *aperture;
+ uint32_t flags;
};
struct wg_parser_stream_get_event_params
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 178c47d5d32..f7c319d3c8f 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -30,6 +30,7 @@
#include
#include
+#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30
#include
#include
#include
@@ -668,31 +669,34 @@ static NTSTATUS wg_parser_stream_enable(void *args)
if (format->major_type == WG_MAJOR_TYPE_VIDEO)
{
- bool flip = (format->u.video.height < 0);
-
- switch (format->u.video.format)
+ if (params->flags & STREAM_ENABLE_FLAG_FLIP_RGB)
{
- case WG_VIDEO_FORMAT_BGRA:
- case WG_VIDEO_FORMAT_BGRx:
- case WG_VIDEO_FORMAT_BGR:
- case WG_VIDEO_FORMAT_RGB15:
- case WG_VIDEO_FORMAT_RGB16:
- flip = !flip;
- break;
+ bool flip = (format->u.video.height < 0);
- case WG_VIDEO_FORMAT_AYUV:
- case WG_VIDEO_FORMAT_I420:
- case WG_VIDEO_FORMAT_NV12:
- case WG_VIDEO_FORMAT_UYVY:
- case WG_VIDEO_FORMAT_YUY2:
- case WG_VIDEO_FORMAT_YV12:
- case WG_VIDEO_FORMAT_YVYU:
- case WG_VIDEO_FORMAT_UNKNOWN:
- case WG_VIDEO_FORMAT_CINEPAK:
- break;
- }
+ switch (format->u.video.format)
+ {
+ case WG_VIDEO_FORMAT_BGRA:
+ case WG_VIDEO_FORMAT_BGRx:
+ case WG_VIDEO_FORMAT_BGR:
+ case WG_VIDEO_FORMAT_RGB15:
+ case WG_VIDEO_FORMAT_RGB16:
+ flip = !flip;
+ break;
- gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none");
+ case WG_VIDEO_FORMAT_AYUV:
+ case WG_VIDEO_FORMAT_I420:
+ case WG_VIDEO_FORMAT_NV12:
+ case WG_VIDEO_FORMAT_UYVY:
+ case WG_VIDEO_FORMAT_YUY2:
+ case WG_VIDEO_FORMAT_YV12:
+ case WG_VIDEO_FORMAT_YVYU:
+ case WG_VIDEO_FORMAT_UNKNOWN:
+ case WG_VIDEO_FORMAT_CINEPAK:
+ break;
+ }
+
+ gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none");
+ }
if (aperture)
{
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index 905ce7306c8..98847c4b306 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -1520,7 +1520,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size)
stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx;
}
}
- wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL);
+ wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB);
}
wg_parser_end_flush(reader->wg_parser);
@@ -1787,7 +1787,7 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
}
stream->format = format;
- wg_parser_stream_enable(stream->wg_stream, &format, NULL);
+ wg_parser_stream_enable(stream->wg_stream, &format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB);
/* Re-decode any buffers that might have been generated with the old format.
*
@@ -2000,7 +2000,7 @@ HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count,
FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n",
selections[i], stream_numbers[i]);
TRACE("Enabling stream %u.\n", stream_numbers[i]);
- wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL);
+ wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB);
}
}
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 16a73a74aeb..a0287c1ff09 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -263,8 +263,6 @@ FUNCTION_OVERRIDES = {
# VK_EXT_debug_report
"vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
"vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
-
- "vkCmdWriteBufferMarkerAMD" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE},
}
STRUCT_CHAIN_CONVERSIONS = {
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index e0da6849d73..3c8bd452eca 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -2656,32 +2656,6 @@ NTSTATUS wine_vkDestroyDebugReportCallbackEXT(void *args)
return STATUS_SUCCESS;
}
-/* HACK: Rainbow Six Siege tries to call this function regardless of whether the extension is exposed */
-NTSTATUS wine_vkCmdWriteBufferMarkerAMD(void *args)
-{
- struct vkCmdWriteBufferMarkerAMD_params *params = args;
- VkCommandBuffer commandBuffer = params->commandBuffer;
- VkPipelineStageFlagBits pipelineStage = params->pipelineStage;
- VkBuffer dstBuffer = params->dstBuffer;
- VkDeviceSize dstOffset = params->dstOffset;
- uint32_t marker = params->marker;
-
- TRACE("%p, %#x, 0x%s, 0x%s, %u\n", commandBuffer, pipelineStage, wine_dbgstr_longlong(dstBuffer), wine_dbgstr_longlong(dstOffset), marker);
-
- if (commandBuffer->device->funcs.p_vkCmdWriteBufferMarkerAMD)
- {
- commandBuffer->device->funcs.p_vkCmdWriteBufferMarkerAMD(commandBuffer->command_buffer, pipelineStage, dstBuffer, dstOffset, marker);
- }
- else
- {
- static unsigned int once;
-
- if (!once++)
- FIXME("HACK: returning success from unexposed function.\n");
- }
- return STATUS_SUCCESS;
-}
-
NTSTATUS wine_vkAcquireNextImage2KHR(void *args)
{
struct vkAcquireNextImage2KHR_params *params = args;
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index ce81dd3c084..27d1fa7fbe0 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -340,6 +340,7 @@ static int try_grab_pointer( Display *display )
return 0;
XUngrabPointer( display, CurrentTime );
+ XFlush( display );
return 1;
}
@@ -845,6 +846,14 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
if (event->mode == NotifyUngrab && wm_is_mutter(event->display))
Sleep(100);
+ if (!try_grab_pointer( event->display ))
+ {
+ /* ask the desktop window to release its grab before trying to get ours */
+ SendMessageW( GetDesktopWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 );
+ XSendEvent( event->display, event->window, False, 0, xev );
+ return FALSE;
+ }
+
/* ask the foreground window to re-apply the current ClipCursor rect */
SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 );
@@ -867,11 +876,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime );
return TRUE;
}
- else if (!try_grab_pointer( event->display ))
- {
- XSendEvent( event->display, event->window, False, 0, xev );
- return FALSE;
- }
SetForegroundWindow( hwnd );
return TRUE;
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 82906303a85..a3377a659c3 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -2254,6 +2254,50 @@ static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawa
pglUseProgram( prev_program );
}
+enum fshack_texture_type
+{
+ FSHACK_TEXTURE_COLOUR,
+ FSHACK_TEXTURE_DEPTH,
+ FSHACK_TEXTURE_LAST,
+};
+
+static void gen_texture( struct wgl_context *ctx, GLuint *tex, enum fshack_texture_type type )
+{
+ static const GLuint texture_names[FSHACK_TEXTURE_LAST] =
+ {
+ 65535,
+ 65536,
+ };
+ static int texture_name_hack = -1;
+ static int once;
+
+ if (ctx->is_core)
+ {
+ opengl_funcs.gl.p_glGenTextures( 1, tex );
+ return;
+ }
+
+ if (texture_name_hack == -1)
+ {
+ const char *sgi = getenv("SteamGameId");
+
+ texture_name_hack = sgi && !strcmp( sgi, "6020" );
+ }
+
+ if (!texture_name_hack || opengl_funcs.gl.p_glIsTexture( texture_names[type] ))
+ {
+ if (texture_name_hack)
+ FIXME( "Texture %u already exists.\n", texture_names[type] );
+ opengl_funcs.gl.p_glGenTextures( 1, tex );
+ return;
+ }
+ /* Star Wars Jedi Knight: Jedi Academy uses texture names without allocating
+ * them with glGenTextures(). Trying to use a texture name which has low chances
+ * to overlap with what games may use. */
+ if (!once++) FIXME( "Using texture name hack.\n" );
+ *tex = texture_names[type];
+}
+
static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *gl )
{
GLuint prev_draw_fbo, prev_read_fbo, prev_texture, prev_renderbuffer;
@@ -2325,7 +2369,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *
fs_hack_get_attachments_config( gl, &attribs, &config );
if (!ctx->fs_hack_color_texture)
- opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture );
+ gen_texture( ctx, &ctx->fs_hack_color_texture, FSHACK_TEXTURE_COLOUR );
+
opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture );
opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.color_internalformat, width, height,
0, config.color_format, config.color_type, NULL);
@@ -2389,7 +2434,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *
else
{
if (!ctx->fs_hack_ds_texture)
- opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_ds_texture );
+ gen_texture( ctx, &ctx->fs_hack_ds_texture, FSHACK_TEXTURE_DEPTH );
+
opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_ds_texture );
opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.ds_internalformat, width, height,
0, config.ds_format, config.ds_type, NULL);
@@ -2408,12 +2454,25 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *
if (!ctx->has_been_current)
opengl_funcs.gl.p_glViewport(0, 0, width, height);
- if(!gl->fs_hack_context_set_up)
+ if (!gl->fs_hack_context_set_up)
{
- opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
- opengl_funcs.gl.p_glClearDepth( 1.0 );
- opengl_funcs.gl.p_glClearStencil( 0 );
- opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+ if (ctx->has_been_current)
+ {
+ GLbitfield mask = GL_COLOR_BUFFER_BIT;
+
+ if (attribs.depth_size) mask |= GL_DEPTH_BUFFER_BIT;
+ if (attribs.stencil_size) mask |= GL_STENCIL_BUFFER_BIT;
+
+ pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
+ pglBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, GL_NEAREST );
+ }
+ else
+ {
+ opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
+ opengl_funcs.gl.p_glClearDepth( 1.0 );
+ opengl_funcs.gl.p_glClearStencil( 0 );
+ opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+ }
}
pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
pglDrawBuffer( GL_BACK );
@@ -3228,6 +3287,21 @@ static struct wgl_context *X11DRV_wglCreateContextAttribsARB( HDC hdc, struct wg
case WGL_CONTEXT_LAYER_PLANE_ARB:
break;
case WGL_CONTEXT_FLAGS_ARB:
+ /* HACK: The Last Campfire sometimes uses an
+ * invalid value for WGL_CONTEXT_FLAGS_ARB, which
+ * triggers
+ * https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/152
+ * on the Deck. If we see the invalid value we
+ * directly return an error, so that Wine doesn't
+ * crash. This hack can be removed once that issue
+ * is fixed. */
+ if (attribList[1] == 0x31b3)
+ {
+ WARN("return early to avoid triggering a libX11 bug\n");
+ HeapFree(GetProcessHeap(), 0, ret);
+ release_gl_drawable(gl);
+ return NULL;
+ }
pContextAttribList[0] = GLX_CONTEXT_FLAGS_ARB;
pContextAttribList[1] = attribList[1];
pContextAttribList += 2;
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index 7e46a43aa05..053f8315fec 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -4816,7 +4816,7 @@ static void test_IWinHttpRequest_Invoke(void)
VariantInit(&arg[2]);
params.cArgs = 3;
hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, &err);
-todo_wine
+ todo_wine
ok(hr == S_OK, "error %#x\n", hr);
VariantInit(&arg[0]);
@@ -4861,7 +4861,7 @@ todo_wine
params.cArgs = 2;
hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL);
-todo_wine
+ todo_wine
ok(hr == S_OK, "error %#x\n", hr);
params.cArgs = 0;
diff --git a/dlls/winhttp/url.c b/dlls/winhttp/url.c
index 0d9dfb76de6..8efd5ed0c49 100644
--- a/dlls/winhttp/url.c
+++ b/dlls/winhttp/url.c
@@ -172,7 +172,7 @@ static DWORD parse_port( const WCHAR *str, DWORD len, INTERNET_PORT *ret )
*/
BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc )
{
- WCHAR *p, *q, *r, *url_decoded = NULL, *url_escaped = NULL;
+ WCHAR *p, *q, *r, *url_transformed = NULL;
INTERNET_SCHEME scheme_number = 0;
struct url_component scheme, username, password, hostname, path, extra;
BOOL overflow = FALSE;
@@ -189,25 +189,26 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN
if (flags & ICU_ESCAPE)
{
- if ((err = escape_url( url, &len, &url_escaped )))
+ if ((err = escape_url( url, &len, &url_transformed )))
{
SetLastError( err );
return FALSE;
}
- url = url_escaped;
+ url = url_transformed;
}
else if (flags & ICU_DECODE)
{
- if (!(url_decoded = decode_url( url, &len )))
+ if (!(url_transformed = decode_url( url, &len )))
{
SetLastError( ERROR_OUTOFMEMORY );
return FALSE;
}
- url = url_decoded;
+ url = url_transformed;
}
if (!(p = wcschr( url, ':' )))
{
SetLastError( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
+ free( url_transformed );
return FALSE;
}
if (p - url == 4 && !wcsnicmp( url, L"http", 4 )) scheme_number = INTERNET_SCHEME_HTTP;
@@ -331,8 +332,7 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN
if (overflow) err = ERROR_INSUFFICIENT_BUFFER;
uc->nScheme = scheme_number;
}
- free( url_decoded );
- free( url_escaped );
+ free( url_transformed );
SetLastError( err );
return !err;
}
diff --git a/dlls/winmm/waveform.c b/dlls/winmm/waveform.c
index 1159b48b483..ecffa700662 100644
--- a/dlls/winmm/waveform.c
+++ b/dlls/winmm/waveform.c
@@ -191,6 +191,7 @@ static LRESULT WOD_Close(HWAVEOUT hwave);
static LRESULT WID_Open(WINMM_OpenInfo *info);
static LRESULT WID_Close(HWAVEIN hwave);
static MMRESULT WINMM_BeginPlaying(WINMM_Device *device);
+static void WOD_PushData(WINMM_Device *device);
void WINMM_DeleteWaveform(void)
{
@@ -775,8 +776,11 @@ static HRESULT reroute_mapper_device(WINMM_Device *device, BOOL is_out)
HeapFree(GetProcessHeap(), 0, info.format);
- if(!stopped)
+ if(!stopped){
+ if(is_out)
+ WOD_PushData(device);
WINMM_BeginPlaying(device);
+ }
LeaveCriticalSection(&device->lock);
@@ -1948,10 +1952,6 @@ static MMRESULT WINMM_BeginPlaying(WINMM_Device *device)
TRACE("(%p)\n", device->handle);
- if(device->render)
- /* prebuffer data before starting */
- WOD_PushData(device);
-
if(device->stopped){
device->stopped = FALSE;
@@ -2893,6 +2893,9 @@ UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR *header, UINT uSize)
header->dwFlags &= ~WHDR_DONE;
header->dwFlags |= WHDR_INQUEUE;
+ if(device->stopped)
+ WOD_PushData(device);
+
mr = WINMM_BeginPlaying(device);
LeaveCriticalSection(&device->lock);
@@ -2970,6 +2973,9 @@ UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
device->stopped = TRUE;
+ if(device->render)
+ WOD_PushData(device);
+
mr = WINMM_BeginPlaying(device);
LeaveCriticalSection(&device->lock);
diff --git a/include/wine/asm.h b/include/wine/asm.h
index 0547ee94b19..9200491afd0 100644
--- a/include/wine/asm.h
+++ b/include/wine/asm.h
@@ -50,6 +50,7 @@
# define __ASM_SEH(str)
# else
# define __ASM_SEH(str) str
+# define __ASM_SEH_SUPPORTED
# endif
#else
# define __ASM_SEH(str)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 1d17a40530f..d67489de1f0 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -14,6 +14,7 @@
#include
#include
+#include
typedef unsigned int obj_handle_t;
typedef unsigned int user_handle_t;
@@ -470,7 +471,8 @@ enum apc_type
APC_MAP_VIEW,
APC_UNMAP_VIEW,
APC_CREATE_THREAD,
- APC_DUP_HANDLE
+ APC_DUP_HANDLE,
+ APC_PROCESS_SET_INFO,
};
typedef struct
@@ -579,6 +581,11 @@ typedef union
unsigned int attributes;
unsigned int options;
} dup_handle;
+ struct
+ {
+ enum apc_type type;
+ PROCESSINFOCLASS class;
+ } process_set_info;
} apc_call_t;
typedef union
@@ -677,6 +684,11 @@ typedef union
enum apc_type type;
unsigned int status;
} break_process;
+ struct
+ {
+ enum apc_type type;
+ unsigned int status;
+ } process_set_info;
} apc_result_t;
enum irp_type
@@ -815,6 +827,76 @@ typedef struct
lparam_t info;
} cursor_pos_t;
+struct cpu_topology_override
+{
+ unsigned int cpu_count;
+ unsigned char host_cpu_id[64];
+};
+
+struct shared_cursor
+{
+ int x;
+ int y;
+ unsigned int last_change;
+ rectangle_t clip;
+};
+
+struct ws_watch_entry
+{
+ client_ptr_t va;
+ client_ptr_t pc;
+ thread_id_t tid;
+ int __pad;
+};
+
+struct ws_watch_data
+{
+ data_size_t len;
+ int __pad;
+ struct ws_watch_entry entries[1];
+};
+
+struct desktop_shared_memory
+{
+ unsigned int seq;
+ struct shared_cursor cursor;
+ unsigned char keystate[256];
+ thread_id_t foreground_tid;
+};
+
+struct queue_shared_memory
+{
+ unsigned int seq;
+ int created;
+ unsigned int wake_bits;
+ unsigned int changed_bits;
+ unsigned int wake_mask;
+ unsigned int changed_mask;
+ thread_id_t input_tid;
+};
+
+struct input_shared_memory
+{
+ unsigned int seq;
+ int created;
+ thread_id_t tid;
+ user_handle_t focus;
+ user_handle_t capture;
+ user_handle_t active;
+ user_handle_t menu_owner;
+ user_handle_t move_size;
+ user_handle_t caret;
+ user_handle_t cursor;
+ rectangle_t caret_rect;
+ int cursor_count;
+ unsigned char keystate[256];
+ int keystate_lock;
+};
+
+
+#define SEQUENCE_MASK_BITS 4
+#define SEQUENCE_MASK ((1UL << SEQUENCE_MASK_BITS) - 1)
+
@@ -907,11 +989,15 @@ struct init_process_done_request
client_ptr_t teb;
client_ptr_t peb;
client_ptr_t ldt_copy;
+ client_ptr_t kernel_stack;
+ unsigned int kernel_stack_size;
+ char __pad_52[4];
};
struct init_process_done_reply
{
struct reply_header __header;
client_ptr_t entry;
+ /* VARARG(cpu_override,cpu_topology_override); */
int suspend;
char __pad_20[4];
};
@@ -926,6 +1012,8 @@ struct init_first_thread_request
int debug_level;
int reply_fd;
int wait_fd;
+ char nice_limit;
+ char __pad_33[7];
};
struct init_first_thread_reply
{
@@ -948,6 +1036,9 @@ struct init_thread_request
int wait_fd;
client_ptr_t teb;
client_ptr_t entry;
+ client_ptr_t kernel_stack;
+ unsigned int kernel_stack_size;
+ char __pad_52[4];
};
struct init_thread_reply
{
@@ -1748,14 +1839,16 @@ struct recv_socket_request
struct request_header __header;
int oob;
async_data_t async;
- unsigned int status;
- unsigned int total;
+ int force_async;
+ char __pad_60[4];
};
struct recv_socket_reply
{
struct reply_header __header;
obj_handle_t wait;
unsigned int options;
+ int nonblocking;
+ char __pad_20[4];
};
@@ -2139,7 +2232,9 @@ struct read_process_memory_request
struct read_process_memory_reply
{
struct reply_header __header;
+ int unix_pid;
/* VARARG(data,bytes); */
+ char __pad_12[4];
};
@@ -2686,10 +2781,10 @@ struct send_hardware_message_reply
int prev_y;
int new_x;
int new_y;
- /* VARARG(keystate,bytes); */
char __pad_28[4];
};
#define SEND_HWMSG_INJECTED 0x01
+#define SEND_HWMSG_RAWINPUT 0x02
@@ -2715,9 +2810,9 @@ struct get_message_reply
int x;
int y;
unsigned int time;
- unsigned int active_hooks;
data_size_t total;
/* VARARG(data,message_data); */
+ char __pad_52[4];
};
@@ -2889,6 +2984,23 @@ struct get_async_result_reply
+struct set_async_direct_result_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+ apc_param_t information;
+ unsigned int status;
+ char __pad_28[4];
+};
+struct set_async_direct_result_reply
+{
+ struct reply_header __header;
+ obj_handle_t handle;
+ char __pad_12[4];
+};
+
+
+
struct read_request
{
struct request_header __header;
@@ -3769,14 +3881,10 @@ struct get_thread_input_reply
user_handle_t focus;
user_handle_t capture;
user_handle_t active;
- user_handle_t foreground;
user_handle_t menu_owner;
user_handle_t move_size;
user_handle_t caret;
- user_handle_t cursor;
- int show_count;
rectangle_t rect;
- char __pad_60[4];
};
@@ -3934,6 +4042,20 @@ enum caret_state
+struct get_active_hooks_request
+{
+ struct request_header __header;
+ char __pad_12[4];
+};
+struct get_active_hooks_reply
+{
+ struct reply_header __header;
+ unsigned int active_hooks;
+ char __pad_12[4];
+};
+
+
+
struct set_hook_request
{
struct request_header __header;
@@ -4985,6 +5107,8 @@ struct remove_completion_request
{
struct request_header __header;
obj_handle_t handle;
+ int waited;
+ char __pad_20[4];
};
struct remove_completion_reply
{
@@ -5388,7 +5512,6 @@ struct resume_process_reply
};
-
struct get_next_thread_request
{
struct request_header __header;
@@ -5405,6 +5528,200 @@ struct get_next_thread_reply
char __pad_12[4];
};
+enum esync_type
+{
+ ESYNC_SEMAPHORE = 1,
+ ESYNC_AUTO_EVENT,
+ ESYNC_MANUAL_EVENT,
+ ESYNC_MUTEX,
+ ESYNC_AUTO_SERVER,
+ ESYNC_MANUAL_SERVER,
+ ESYNC_QUEUE,
+};
+
+
+struct create_esync_request
+{
+ struct request_header __header;
+ unsigned int access;
+ int initval;
+ int type;
+ int max;
+ /* VARARG(objattr,object_attributes); */
+ char __pad_28[4];
+};
+struct create_esync_reply
+{
+ struct reply_header __header;
+ obj_handle_t handle;
+ int type;
+ unsigned int shm_idx;
+ char __pad_20[4];
+};
+
+struct open_esync_request
+{
+ struct request_header __header;
+ unsigned int access;
+ unsigned int attributes;
+ obj_handle_t rootdir;
+ int type;
+ /* VARARG(name,unicode_str); */
+ char __pad_28[4];
+};
+struct open_esync_reply
+{
+ struct reply_header __header;
+ obj_handle_t handle;
+ int type;
+ unsigned int shm_idx;
+ char __pad_20[4];
+};
+
+
+struct get_esync_fd_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+};
+struct get_esync_fd_reply
+{
+ struct reply_header __header;
+ int type;
+ unsigned int shm_idx;
+};
+
+
+struct esync_msgwait_request
+{
+ struct request_header __header;
+ int in_msgwait;
+};
+struct esync_msgwait_reply
+{
+ struct reply_header __header;
+};
+
+
+struct get_esync_apc_fd_request
+{
+ struct request_header __header;
+ char __pad_12[4];
+};
+struct get_esync_apc_fd_reply
+{
+ struct reply_header __header;
+};
+
+enum fsync_type
+{
+ FSYNC_SEMAPHORE = 1,
+ FSYNC_AUTO_EVENT,
+ FSYNC_MANUAL_EVENT,
+ FSYNC_MUTEX,
+ FSYNC_AUTO_SERVER,
+ FSYNC_MANUAL_SERVER,
+ FSYNC_QUEUE,
+};
+
+
+struct create_fsync_request
+{
+ struct request_header __header;
+ unsigned int access;
+ int low;
+ int high;
+ int type;
+ /* VARARG(objattr,object_attributes); */
+ char __pad_28[4];
+};
+struct create_fsync_reply
+{
+ struct reply_header __header;
+ obj_handle_t handle;
+ int type;
+ unsigned int shm_idx;
+ char __pad_20[4];
+};
+
+
+struct open_fsync_request
+{
+ struct request_header __header;
+ unsigned int access;
+ unsigned int attributes;
+ obj_handle_t rootdir;
+ int type;
+ /* VARARG(name,unicode_str); */
+ char __pad_28[4];
+};
+struct open_fsync_reply
+{
+ struct reply_header __header;
+ obj_handle_t handle;
+ int type;
+ unsigned int shm_idx;
+ char __pad_20[4];
+};
+
+
+struct get_fsync_idx_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+};
+struct get_fsync_idx_reply
+{
+ struct reply_header __header;
+ int type;
+ unsigned int shm_idx;
+};
+
+struct fsync_msgwait_request
+{
+ struct request_header __header;
+ int in_msgwait;
+};
+struct fsync_msgwait_reply
+{
+ struct reply_header __header;
+};
+
+struct get_fsync_apc_idx_request
+{
+ struct request_header __header;
+ char __pad_12[4];
+};
+struct get_fsync_apc_idx_reply
+{
+ struct reply_header __header;
+ unsigned int shm_idx;
+ char __pad_12[4];
+};
+
+
+struct init_working_set_watch_request
+{
+ struct request_header __header;
+ int fd;
+};
+struct init_working_set_watch_reply
+{
+ struct reply_header __header;
+};
+
+
+struct get_ws_watches_request
+{
+ struct request_header __header;
+ obj_handle_t process;
+};
+struct get_ws_watches_reply
+{
+ struct reply_header __header;
+ /* VARARG(info,ws_watch_data); */
+};
+
enum request
{
@@ -5531,6 +5848,7 @@ enum request
REQ_register_async,
REQ_cancel_async,
REQ_get_async_result,
+ REQ_set_async_direct_result,
REQ_read,
REQ_write,
REQ_ioctl,
@@ -5591,6 +5909,7 @@ enum request
REQ_set_capture_window,
REQ_set_caret_window,
REQ_set_caret_info,
+ REQ_get_active_hooks,
REQ_set_hook,
REQ_remove_hook,
REQ_start_hook_chain,
@@ -5682,6 +6001,18 @@ enum request
REQ_suspend_process,
REQ_resume_process,
REQ_get_next_thread,
+ REQ_create_esync,
+ REQ_open_esync,
+ REQ_get_esync_fd,
+ REQ_esync_msgwait,
+ REQ_get_esync_apc_fd,
+ REQ_create_fsync,
+ REQ_open_fsync,
+ REQ_get_fsync_idx,
+ REQ_fsync_msgwait,
+ REQ_get_fsync_apc_idx,
+ REQ_init_working_set_watch,
+ REQ_get_ws_watches,
REQ_NB_REQUESTS
};
@@ -5812,6 +6143,7 @@ union generic_request
struct register_async_request register_async_request;
struct cancel_async_request cancel_async_request;
struct get_async_result_request get_async_result_request;
+ struct set_async_direct_result_request set_async_direct_result_request;
struct read_request read_request;
struct write_request write_request;
struct ioctl_request ioctl_request;
@@ -5872,6 +6204,7 @@ union generic_request
struct set_capture_window_request set_capture_window_request;
struct set_caret_window_request set_caret_window_request;
struct set_caret_info_request set_caret_info_request;
+ struct get_active_hooks_request get_active_hooks_request;
struct set_hook_request set_hook_request;
struct remove_hook_request remove_hook_request;
struct start_hook_chain_request start_hook_chain_request;
@@ -5963,6 +6296,18 @@ union generic_request
struct suspend_process_request suspend_process_request;
struct resume_process_request resume_process_request;
struct get_next_thread_request get_next_thread_request;
+ struct create_esync_request create_esync_request;
+ struct open_esync_request open_esync_request;
+ struct get_esync_fd_request get_esync_fd_request;
+ struct esync_msgwait_request esync_msgwait_request;
+ struct get_esync_apc_fd_request get_esync_apc_fd_request;
+ struct create_fsync_request create_fsync_request;
+ struct open_fsync_request open_fsync_request;
+ struct get_fsync_idx_request get_fsync_idx_request;
+ struct fsync_msgwait_request fsync_msgwait_request;
+ struct get_fsync_apc_idx_request get_fsync_apc_idx_request;
+ struct init_working_set_watch_request init_working_set_watch_request;
+ struct get_ws_watches_request get_ws_watches_request;
};
union generic_reply
{
@@ -6091,6 +6436,7 @@ union generic_reply
struct register_async_reply register_async_reply;
struct cancel_async_reply cancel_async_reply;
struct get_async_result_reply get_async_result_reply;
+ struct set_async_direct_result_reply set_async_direct_result_reply;
struct read_reply read_reply;
struct write_reply write_reply;
struct ioctl_reply ioctl_reply;
@@ -6151,6 +6497,7 @@ union generic_reply
struct set_capture_window_reply set_capture_window_reply;
struct set_caret_window_reply set_caret_window_reply;
struct set_caret_info_reply set_caret_info_reply;
+ struct get_active_hooks_reply get_active_hooks_reply;
struct set_hook_reply set_hook_reply;
struct remove_hook_reply remove_hook_reply;
struct start_hook_chain_reply start_hook_chain_reply;
@@ -6242,11 +6589,23 @@ union generic_reply
struct suspend_process_reply suspend_process_reply;
struct resume_process_reply resume_process_reply;
struct get_next_thread_reply get_next_thread_reply;
+ struct create_esync_reply create_esync_reply;
+ struct open_esync_reply open_esync_reply;
+ struct get_esync_fd_reply get_esync_fd_reply;
+ struct esync_msgwait_reply esync_msgwait_reply;
+ struct get_esync_apc_fd_reply get_esync_apc_fd_reply;
+ struct create_fsync_reply create_fsync_reply;
+ struct open_fsync_reply open_fsync_reply;
+ struct get_fsync_idx_reply get_fsync_idx_reply;
+ struct fsync_msgwait_reply fsync_msgwait_reply;
+ struct get_fsync_apc_idx_reply get_fsync_apc_idx_reply;
+ struct init_working_set_watch_reply init_working_set_watch_reply;
+ struct get_ws_watches_reply get_ws_watches_reply;
};
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 739
+#define SERVER_PROTOCOL_VERSION 740
/* ### protocol_version end ### */
diff --git a/loader/wine.inf.in b/loader/wine.inf.in
index fe8370742b2..a08568eb9a3 100644
--- a/loader/wine.inf.in
+++ b/loader/wine.inf.in
@@ -5930,6 +5930,7 @@ HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin"
HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin"
HKCU,Software\Wine\AppDefaults\msedgewebview2.exe,"Version",,"win81"
HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin"
+HKCU,Software\Wine\AppDefaults\starwarssquadrons.exe\DllOverrides,"atiadlxx",,"builtin"
;;App-specific overrides to limit the number of resolutions
HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32"
HKCU,Software\Wine\AppDefaults\sekiro.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32"
diff --git a/programs/belauncher/Makefile.in b/programs/belauncher/Makefile.in
new file mode 100644
index 00000000000..f2dc59b07ce
--- /dev/null
+++ b/programs/belauncher/Makefile.in
@@ -0,0 +1,7 @@
+MODULE = belauncher.exe
+IMPORTS =
+
+EXTRADLLFLAGS = -mwindows -municode
+
+C_SRCS = \
+ main.c \
diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c
new file mode 100644
index 00000000000..86ec46ecee4
--- /dev/null
+++ b/programs/belauncher/main.c
@@ -0,0 +1,117 @@
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(belauncher);
+
+int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow)
+{
+ char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL;
+ LARGE_INTEGER launcher_cfg_size;
+ unsigned char battleye_status;
+ int game_exe_len, arg_len;
+ PROCESS_INFORMATION pi;
+ HANDLE launcher_cfg;
+ LPWSTR launch_cmd;
+ STARTUPINFOW si = {0};
+ DWORD size;
+ BOOL wow64;
+
+ battleye_status = 0x3; /* Starting */
+ _write(1, &battleye_status, 1);
+
+ launcher_cfg = CreateFileW(L"Battleye\\BELauncher.ini", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (launcher_cfg == INVALID_HANDLE_VALUE)
+ goto start_failed;
+
+ if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart)
+ {
+ CloseHandle(launcher_cfg);
+ goto start_failed;
+ }
+
+ configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart);
+
+ if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart)
+ {
+ CloseHandle(launcher_cfg);
+ HeapFree( GetProcessHeap(), 0, configs );
+ goto start_failed;
+ }
+
+ CloseHandle(launcher_cfg);
+
+ config = configs;
+ do
+ {
+ if (!strncmp(config, "32BitExe=", 9))
+ arch_32_exe = config + 9;
+
+ if (!strncmp(config, "64BitExe=", 9))
+ arch_64_exe = config + 9;
+
+ if (!strncmp(config, "BEArg=", 6))
+ be_arg = config + 6;
+ }
+ while ((config = strchr(config, '\n')) && *(config++));
+
+ if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64)))
+ game_exe = arch_64_exe;
+ else if (arch_32_exe)
+ game_exe = arch_32_exe;
+ else
+ {
+ HeapFree( GetProcessHeap(), 0, configs );
+ WINE_WARN("Failed to find game executable name from BattlEye config.\n");
+ goto start_failed;
+ }
+
+ if (strchr(game_exe, '\r'))
+ *(strchr(game_exe, '\r')) = 0;
+ if (strchr(game_exe, '\n'))
+ *(strchr(game_exe, '\n')) = 0;
+ game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1;
+
+ if (!be_arg) arg_len = 0;
+ else
+ {
+ if (strchr(be_arg, '\r'))
+ *(strchr(be_arg, '\r')) = 0;
+ if (strchr(be_arg, '\n'))
+ *(strchr(be_arg, '\n')) = 0;
+ arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1;
+ }
+
+ WINE_TRACE("Launching game executable %s for BattlEye.\n", game_exe);
+ battleye_status = 0x9; /* Launching Game */
+ _write(1, &battleye_status, 1);
+
+ launch_cmd = HeapAlloc(GetProcessHeap(), 0, (game_exe_len + 1 + wcslen(cmdline) + 1 + arg_len + 1) * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, game_exe, -1, launch_cmd, game_exe_len + 1);
+ launch_cmd[game_exe_len] = ' ';
+
+ wcscpy(launch_cmd + game_exe_len + 1, cmdline);
+ launch_cmd[game_exe_len + 1 + wcslen(cmdline)] = ' ';
+
+ MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1);
+
+ if (!CreateProcessW(NULL, launch_cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
+ {
+ battleye_status = 0xA; /* Launch Failed */
+ _write(1, &battleye_status, 1);
+
+ HeapFree( GetProcessHeap(), 0, launch_cmd );
+ return GetLastError();
+ }
+ HeapFree( GetProcessHeap(), 0, launch_cmd );
+
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hProcess);
+ return 0;
+
+start_failed:
+ battleye_status = 0x4; /* Start Failed */
+ _write(1, &battleye_status, 1);
+ return 0;
+}
diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c
index 16b44ca28ab..012155fccba 100644
--- a/programs/wineboot/wineboot.c
+++ b/programs/wineboot/wineboot.c
@@ -83,6 +83,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(wineboot);
+#define TICKSPERSEC 10000000
+
extern BOOL shutdown_close_windows( BOOL force );
extern BOOL shutdown_all_desktops( BOOL force );
extern void kill_processes( BOOL kill_desktop );
@@ -242,15 +244,173 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data)
TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]);
}
+static UINT64 read_tsc_frequency( BOOL has_rdtscp )
+{
+ UINT64 freq = 0;
+
+/* FIXME: Intel provides TSC freq in some CPUID but it's been slightly broken,
+ fix it properly and test it on real Intel hardware */
+
+#if 0
+ int regs[4], cpuid_level, tmp;
+ UINT64 denom, numer;
+
+ __cpuid( regs, 0 );
+ tmp = regs[2];
+ regs[2] = regs[3];
+ regs[3] = tmp;
+
+ /* only available on some intel CPUs */
+ if (memcmp( regs + 1, "GenuineIntel", 12 )) freq = 0;
+ else if ((cpuid_level = regs[0]) < 0x15) freq = 0;
+ else
+ {
+ __cpuid( regs, 0x15 );
+ if (!(denom = regs[0]) || !(numer = regs[1])) freq = 0;
+ else
+ {
+ if ((freq = regs[2])) freq = freq * numer / denom;
+ else if (cpuid_level >= 0x16)
+ {
+ __cpuid( regs, 0x16 ); /* eax is base freq in MHz */
+ freq = regs[0] * (UINT64)1000000;
+ }
+ else freq = 0;
+ }
+
+ if (!freq) WARN( "Failed to read TSC frequency from CPUID, falling back to calibration.\n" );
+ else TRACE( "TSC frequency read from CPUID, found %I64u Hz\n", freq );
+ }
+#endif
+
+ if (freq == 0)
+ {
+ LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error;
+ unsigned int aux;
+ UINT retries = 50;
+ int regs[4];
+
+ do
+ {
+ if (has_rdtscp)
+ {
+ tsc0 = __rdtscp( &aux );
+ time0 = RtlGetSystemTimePrecise();
+ tsc1 = __rdtscp( &aux );
+ Sleep( 1 );
+ tsc2 = __rdtscp( &aux );
+ time1 = RtlGetSystemTimePrecise();
+ tsc3 = __rdtscp( &aux );
+ }
+ else
+ {
+ tsc0 = __rdtsc(); __cpuid( regs, 0 );
+ time0 = RtlGetSystemTimePrecise();
+ tsc1 = __rdtsc(); __cpuid( regs, 0 );
+ Sleep(1);
+ tsc2 = __rdtsc(); __cpuid( regs, 0 );
+ time1 = RtlGetSystemTimePrecise();
+ tsc3 = __rdtsc(); __cpuid( regs, 0 );
+ }
+
+ freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0);
+ freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0);
+ error = llabs( (freq1 - freq0) * 1000000 / min( freq1, freq0 ) );
+ }
+ while (error > 100 && --retries);
+
+ if (!retries) WARN( "TSC frequency calibration failed, unstable TSC?\n" );
+ else
+ {
+ freq = (freq0 + freq1) / 2;
+ TRACE( "TSC frequency calibration complete, found %I64u Hz\n", freq );
+ }
+ }
+
+ return freq;
+}
+
+static BOOL is_tsc_trusted_by_the_kernel(void)
+{
+ char buf[4] = {};
+ DWORD num_read;
+ HANDLE handle;
+ BOOL ret = TRUE;
+
+ handle = CreateFileA( "\\??\\unix\\sys\\bus\\clocksource\\devices\\clocksource0\\current_clocksource",
+ GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
+ if (handle == INVALID_HANDLE_VALUE) return TRUE;
+
+ if (ReadFile( handle, buf, sizeof(buf) - 1, &num_read, NULL ) && strcmp( "tsc", buf ))
+ ret = FALSE;
+
+ CloseHandle( handle );
+ return ret;
+}
+
+static void initialize_qpc_features( struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency )
+{
+ BOOL has_rdtscp = FALSE;
+ int regs[4];
+
+ data->QpcBypassEnabled = 0;
+ data->QpcFrequency = TICKSPERSEC;
+ data->QpcShift = 0;
+ data->QpcBias = 0;
+ *tsc_frequency = 0;
+
+ if (!is_tsc_trusted_by_the_kernel())
+ {
+ WARN( "Failed to compute TSC frequency, not trusted by the kernel.\n" );
+ return;
+ }
+
+ if (!data->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE])
+ {
+ WARN( "Failed to compute TSC frequency, RDTSC instruction not supported.\n" );
+ return;
+ }
+
+ __cpuid( regs, 0x80000000 );
+ if (regs[0] < 0x80000007)
+ {
+ WARN( "Failed to compute TSC frequency, unable to check invariant TSC.\n" );
+ return;
+ }
+
+ /* check for invariant tsc bit */
+ __cpuid( regs, 0x80000007 );
+ if (!(regs[3] & (1 << 8)))
+ {
+ WARN( "Failed to compute TSC frequency, no invariant TSC.\n" );
+ return;
+ }
+
+ /* check for rdtscp support bit */
+ __cpuid( regs, 0x80000001 );
+ if ((regs[3] & (1 << 27))) has_rdtscp = TRUE;
+
+ *tsc_frequency = read_tsc_frequency( has_rdtscp );
+}
+
#else
static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data)
{
}
+static void initialize_qpc_features( struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency )
+{
+ data->QpcBypassEnabled = 0;
+ data->QpcFrequency = TICKSPERSEC;
+ data->QpcShift = 0;
+ data->QpcBias = 0;
+ *tsc_frequency = 0;
+}
+
#endif
-static void create_user_shared_data(void)
+static void create_user_shared_data( UINT64 *tsc_frequency )
{
struct _KUSER_SHARED_DATA *data;
RTL_OSVERSIONINFOEXW version;
@@ -337,6 +497,7 @@ static void create_user_shared_data(void)
data->ActiveGroupCount = 1;
initialize_xstate_features( data );
+ initialize_qpc_features( data, tsc_frequency );
UnmapViewOfFile( data );
}
@@ -648,7 +809,7 @@ static void create_bios_key( HKEY system_key )
}
/* create the volatile hardware registry keys */
-static void create_hardware_registry_keys(void)
+static void create_hardware_registry_keys( UINT64 tsc_frequency )
{
unsigned int i;
HKEY hkey, system_key, cpu_key, fpu_key;
@@ -723,12 +884,15 @@ static void create_hardware_registry_keys(void)
if (!RegCreateKeyExW( cpu_key, numW, 0, NULL, REG_OPTION_VOLATILE,
KEY_ALL_ACCESS, NULL, &hkey, NULL ))
{
+ DWORD tsc_freq_mhz = (DWORD)(tsc_frequency / 1000000ull); /* Hz -> Mhz */
+ if (!tsc_freq_mhz) tsc_freq_mhz = power_info[i].MaxMhz;
+
RegSetValueExW( hkey, L"FeatureSet", 0, REG_DWORD, (BYTE *)&sci.ProcessorFeatureBits, sizeof(DWORD) );
set_reg_value( hkey, L"Identifier", id );
/* TODO: report ARM properly */
set_reg_value( hkey, L"ProcessorNameString", namestr );
set_reg_value( hkey, L"VendorIdentifier", vendorid );
- RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&power_info[i].MaxMhz, sizeof(DWORD) );
+ RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&tsc_freq_mhz, sizeof(DWORD) );
RegCloseKey( hkey );
}
if (sci.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_ARM &&
@@ -1659,6 +1823,7 @@ int __cdecl main( int argc, char *argv[] )
BOOL end_session, force, init, kill, restart, shutdown, update;
HANDLE event;
OBJECT_ATTRIBUTES attr;
+ UINT64 tsc_frequency = 0;
UNICODE_STRING nameW;
BOOL is_wow64;
@@ -1745,8 +1910,8 @@ int __cdecl main( int argc, char *argv[] )
ResetEvent( event ); /* in case this is a restart */
- create_user_shared_data();
- create_hardware_registry_keys();
+ create_user_shared_data( &tsc_frequency );
+ create_hardware_registry_keys( tsc_frequency );
create_dynamic_registry_keys();
create_environment_registry_keys();
create_computer_name_keys();
diff --git a/server/mapping.c b/server/mapping.c
index ecbfbee7ea1..4514a877177 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -268,6 +268,7 @@ int grow_file( int unix_fd, file_pos_t new_size )
return 0;
}
+#ifndef HAVE_MEMFD_CREATE
/* simplified version of mkstemps() */
static int make_temp_file( char name[16] )
{
@@ -301,10 +302,23 @@ static int check_current_dir_for_exec(void)
unlink( tmpfn );
return (ret != MAP_FAILED);
}
+#endif
/* create a temp file for anonymous mappings */
static int create_temp_file( file_pos_t size )
{
+#ifdef HAVE_MEMFD_CREATE
+ int fd = memfd_create( "wine-mapping", MFD_ALLOW_SEALING );
+ if (fd != -1)
+ {
+ if (!grow_file( fd, size ))
+ {
+ close( fd );
+ fd = -1;
+ }
+ }
+ else file_set_error();
+#else
static int temp_dir_fd = -1;
char tmpfn[16];
int fd;
@@ -337,6 +351,7 @@ static int create_temp_file( file_pos_t size )
else file_set_error();
if (temp_dir_fd != server_dir_fd) fchdir( server_dir_fd );
+#endif
return fd;
}
@@ -1103,6 +1118,10 @@ int get_page_size(void)
return page_mask + 1;
}
+#ifndef F_SEAL_FUTURE_WRITE
+#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */
+#endif
+
struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd )
{
@@ -1112,6 +1131,7 @@ struct object *create_user_data_mapping( struct object *root, const struct unico
if (!(mapping = create_mapping( root, name, attr, sizeof(KSHARED_USER_DATA),
SEC_COMMIT, 0, FILE_READ_DATA | FILE_WRITE_DATA, sd ))) return NULL;
ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 );
+
if (ptr != MAP_FAILED)
{
user_shared_data = ptr;
@@ -1123,11 +1143,15 @@ struct object *create_user_data_mapping( struct object *root, const struct unico
struct object *create_shared_mapping( struct object *root, const struct unicode_str *name,
mem_size_t size, const struct security_descriptor *sd, void **ptr )
{
+ static int seals = F_SEAL_FUTURE_WRITE | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL;
struct mapping *mapping;
if (!(mapping = create_mapping( root, name, OBJ_OPENIF, size, SEC_COMMIT, 0,
FILE_READ_DATA | FILE_WRITE_DATA, sd ))) return NULL;
*ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 );
+
+ fcntl( get_unix_fd( mapping->fd ), F_ADD_SEALS, seals );
+
if (*ptr == MAP_FAILED)
{
release_object( &mapping->obj );
diff --git a/server/process.c b/server/process.c
index 8203eead9d4..1f9ec4eb619 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1462,6 +1462,24 @@ DECL_HANDLER(init_process_done)
const pe_image_info_t *image_info;
const struct cpu_topology_override *cpu_override = get_req_data();
unsigned int have_cpu_override = get_req_data_size() / sizeof(*cpu_override);
+ unsigned int i;
+
+ if (have_cpu_override)
+ {
+ if (cpu_override->cpu_count > ARRAY_SIZE(process->wine_cpu_id_from_host))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+ for (i = 0; i < cpu_override->cpu_count; ++i)
+ {
+ if (cpu_override->host_cpu_id[i] >= ARRAY_SIZE(process->wine_cpu_id_from_host))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+ }
+ }
if (is_process_init_done(process))
{
@@ -1493,7 +1511,12 @@ DECL_HANDLER(init_process_done)
reply->suspend = (current->suspend || process->suspend);
if (have_cpu_override)
+ {
process->cpu_override = *cpu_override;
+ memset( process->wine_cpu_id_from_host, 0, sizeof(process->wine_cpu_id_from_host) );
+ for (i = 0; i < process->cpu_override.cpu_count; ++i)
+ process->wine_cpu_id_from_host[process->cpu_override.host_cpu_id[i]] = i;
+ }
}
/* open a handle to a process */
diff --git a/server/process.h b/server/process.h
index 404bbb12550..60a80be1fc1 100644
--- a/server/process.h
+++ b/server/process.h
@@ -94,6 +94,7 @@ struct process
int esync_fd; /* esync file descriptor (signaled on exit) */
unsigned int fsync_idx;
struct cpu_topology_override cpu_override; /* Overridden CPUs to host CPUs mapping. */
+ unsigned char wine_cpu_id_from_host[64]; /* Host to overridden CPU mapping. */
};
/* process functions */
diff --git a/server/protocol.def b/server/protocol.def
index fbf8a017cd0..4dca9ee3f45 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2821,6 +2821,7 @@ enum coords_relative
/* Set the current thread active window */
@REQ(set_active_window)
user_handle_t handle; /* handle to the active window */
+ unsigned int internal_msg; /* set active window internal message */
@REPLY
user_handle_t previous; /* handle to the previous active window */
@END
diff --git a/server/queue.c b/server/queue.c
index 15c46aea3ab..b07dceb2043 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -3503,7 +3503,11 @@ DECL_HANDLER(set_focus_window)
/* set the current thread active window */
DECL_HANDLER(set_active_window)
{
+ struct message *msg, *next;
struct msg_queue *queue = get_current_queue();
+ struct desktop *desktop;
+
+ if (!(desktop = get_thread_desktop( current, 0 ))) return;
reply->previous = 0;
if (queue && check_queue_input_window( queue, req->handle ))
@@ -3514,9 +3518,17 @@ DECL_HANDLER(set_active_window)
SHARED_WRITE_BEGIN( &queue->input->shared->seq );
queue->input->shared->active = get_user_full_handle( req->handle );
SHARED_WRITE_END( &queue->input->shared->seq );
+
+ if (desktop->foreground_input == queue->input && req->handle != reply->previous)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE( msg, next, &queue->msg_list[POST_MESSAGE], struct message, entry )
+ if (msg->msg == req->internal_msg) remove_queue_message( queue, msg, POST_MESSAGE );
+ }
}
else set_error( STATUS_INVALID_HANDLE );
}
+
+ release_object( desktop );
}
diff --git a/server/request.c b/server/request.c
index 6e1820313d1..a1d646f9643 100644
--- a/server/request.c
+++ b/server/request.c
@@ -519,6 +519,46 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle )
return -1;
}
+#ifndef __NR_clock_gettime64
+#define __NR_clock_gettime64 403
+#endif
+
+struct timespec64
+{
+ long long tv_sec;
+ long long tv_nsec;
+};
+
+static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks )
+{
+ static int clock_gettime64_supported = -1;
+ struct timespec64 ts64;
+ struct timespec ts;
+ int ret;
+
+ if (clock_gettime64_supported < 0)
+ {
+ if (!syscall( __NR_clock_gettime64, clock_id, &ts64 ))
+ {
+ clock_gettime64_supported = 1;
+ *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100;
+ return 0;
+ }
+ clock_gettime64_supported = 0;
+ }
+
+ if (clock_gettime64_supported)
+ {
+ if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 )))
+ *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100;
+ return ret;
+ }
+
+ if (!(ret = clock_gettime( clock_id, &ts )))
+ *ticks = ts.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts.tv_nsec / 100;
+ return ret;
+}
+
/* return a monotonic time counter */
timeout_t monotonic_counter(void)
{
@@ -532,13 +572,13 @@ timeout_t monotonic_counter(void)
#endif
return mach_absolute_time() * timebase.numer / timebase.denom / 100;
#elif defined(HAVE_CLOCK_GETTIME)
- struct timespec ts;
+ ULONGLONG ticks;
#if 0
- if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
- return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100;
+ if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks ))
+ return ticks;
#endif
- if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
- return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100;
+ if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks ))
+ return ticks;
#endif
return current_time - server_start_time;
}
diff --git a/server/request.h b/server/request.h
index 3c455799d54..8c5da1b3c48 100644
--- a/server/request.h
+++ b/server/request.h
@@ -242,6 +242,7 @@ DECL_HANDLER(set_serial_info);
DECL_HANDLER(register_async);
DECL_HANDLER(cancel_async);
DECL_HANDLER(get_async_result);
+DECL_HANDLER(set_async_direct_result);
DECL_HANDLER(read);
DECL_HANDLER(write);
DECL_HANDLER(ioctl);
@@ -302,6 +303,7 @@ DECL_HANDLER(set_active_window);
DECL_HANDLER(set_capture_window);
DECL_HANDLER(set_caret_window);
DECL_HANDLER(set_caret_info);
+DECL_HANDLER(get_active_hooks);
DECL_HANDLER(set_hook);
DECL_HANDLER(remove_hook);
DECL_HANDLER(start_hook_chain);
@@ -393,6 +395,18 @@ DECL_HANDLER(terminate_job);
DECL_HANDLER(suspend_process);
DECL_HANDLER(resume_process);
DECL_HANDLER(get_next_thread);
+DECL_HANDLER(create_esync);
+DECL_HANDLER(open_esync);
+DECL_HANDLER(get_esync_fd);
+DECL_HANDLER(esync_msgwait);
+DECL_HANDLER(get_esync_apc_fd);
+DECL_HANDLER(create_fsync);
+DECL_HANDLER(open_fsync);
+DECL_HANDLER(get_fsync_idx);
+DECL_HANDLER(fsync_msgwait);
+DECL_HANDLER(get_fsync_apc_idx);
+DECL_HANDLER(init_working_set_watch);
+DECL_HANDLER(get_ws_watches);
#ifdef WANT_REQUEST_HANDLERS
@@ -522,6 +536,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_register_async,
(req_handler)req_cancel_async,
(req_handler)req_get_async_result,
+ (req_handler)req_set_async_direct_result,
(req_handler)req_read,
(req_handler)req_write,
(req_handler)req_ioctl,
@@ -582,6 +597,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_set_capture_window,
(req_handler)req_set_caret_window,
(req_handler)req_set_caret_info,
+ (req_handler)req_get_active_hooks,
(req_handler)req_set_hook,
(req_handler)req_remove_hook,
(req_handler)req_start_hook_chain,
@@ -673,6 +689,18 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_suspend_process,
(req_handler)req_resume_process,
(req_handler)req_get_next_thread,
+ (req_handler)req_create_esync,
+ (req_handler)req_open_esync,
+ (req_handler)req_get_esync_fd,
+ (req_handler)req_esync_msgwait,
+ (req_handler)req_get_esync_apc_fd,
+ (req_handler)req_create_fsync,
+ (req_handler)req_open_fsync,
+ (req_handler)req_get_fsync_idx,
+ (req_handler)req_fsync_msgwait,
+ (req_handler)req_get_fsync_apc_idx,
+ (req_handler)req_init_working_set_watch,
+ (req_handler)req_get_ws_watches,
};
C_ASSERT( sizeof(abstime_t) == 8 );
@@ -739,7 +767,9 @@ C_ASSERT( sizeof(struct get_startup_info_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct init_process_done_request, teb) == 16 );
C_ASSERT( FIELD_OFFSET(struct init_process_done_request, peb) == 24 );
C_ASSERT( FIELD_OFFSET(struct init_process_done_request, ldt_copy) == 32 );
-C_ASSERT( sizeof(struct init_process_done_request) == 40 );
+C_ASSERT( FIELD_OFFSET(struct init_process_done_request, kernel_stack) == 40 );
+C_ASSERT( FIELD_OFFSET(struct init_process_done_request, kernel_stack_size) == 48 );
+C_ASSERT( sizeof(struct init_process_done_request) == 56 );
C_ASSERT( FIELD_OFFSET(struct init_process_done_reply, entry) == 8 );
C_ASSERT( FIELD_OFFSET(struct init_process_done_reply, suspend) == 16 );
C_ASSERT( sizeof(struct init_process_done_reply) == 24 );
@@ -748,7 +778,8 @@ C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, unix_tid) == 16 );
C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, debug_level) == 20 );
C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, reply_fd) == 24 );
C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, wait_fd) == 28 );
-C_ASSERT( sizeof(struct init_first_thread_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, nice_limit) == 32 );
+C_ASSERT( sizeof(struct init_first_thread_request) == 40 );
C_ASSERT( FIELD_OFFSET(struct init_first_thread_reply, pid) == 8 );
C_ASSERT( FIELD_OFFSET(struct init_first_thread_reply, tid) == 12 );
C_ASSERT( FIELD_OFFSET(struct init_first_thread_reply, server_start) == 16 );
@@ -760,7 +791,9 @@ C_ASSERT( FIELD_OFFSET(struct init_thread_request, reply_fd) == 16 );
C_ASSERT( FIELD_OFFSET(struct init_thread_request, wait_fd) == 20 );
C_ASSERT( FIELD_OFFSET(struct init_thread_request, teb) == 24 );
C_ASSERT( FIELD_OFFSET(struct init_thread_request, entry) == 32 );
-C_ASSERT( sizeof(struct init_thread_request) == 40 );
+C_ASSERT( FIELD_OFFSET(struct init_thread_request, kernel_stack) == 40 );
+C_ASSERT( FIELD_OFFSET(struct init_thread_request, kernel_stack_size) == 48 );
+C_ASSERT( sizeof(struct init_thread_request) == 56 );
C_ASSERT( FIELD_OFFSET(struct init_thread_reply, suspend) == 8 );
C_ASSERT( sizeof(struct init_thread_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct terminate_process_request, handle) == 12 );
@@ -1042,12 +1075,12 @@ C_ASSERT( FIELD_OFFSET(struct unlock_file_request, count) == 24 );
C_ASSERT( sizeof(struct unlock_file_request) == 32 );
C_ASSERT( FIELD_OFFSET(struct recv_socket_request, oob) == 12 );
C_ASSERT( FIELD_OFFSET(struct recv_socket_request, async) == 16 );
-C_ASSERT( FIELD_OFFSET(struct recv_socket_request, status) == 56 );
-C_ASSERT( FIELD_OFFSET(struct recv_socket_request, total) == 60 );
+C_ASSERT( FIELD_OFFSET(struct recv_socket_request, force_async) == 56 );
C_ASSERT( sizeof(struct recv_socket_request) == 64 );
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 );
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 );
-C_ASSERT( sizeof(struct recv_socket_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, nonblocking) == 16 );
+C_ASSERT( sizeof(struct recv_socket_reply) == 24 );
C_ASSERT( FIELD_OFFSET(struct send_socket_request, async) == 16 );
C_ASSERT( FIELD_OFFSET(struct send_socket_request, status) == 56 );
C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 );
@@ -1162,7 +1195,8 @@ C_ASSERT( sizeof(struct set_debug_obj_info_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, addr) == 16 );
C_ASSERT( sizeof(struct read_process_memory_request) == 24 );
-C_ASSERT( sizeof(struct read_process_memory_reply) == 8 );
+C_ASSERT( FIELD_OFFSET(struct read_process_memory_reply, unix_pid) == 8 );
+C_ASSERT( sizeof(struct read_process_memory_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct write_process_memory_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct write_process_memory_request, addr) == 16 );
C_ASSERT( sizeof(struct write_process_memory_request) == 24 );
@@ -1347,8 +1381,7 @@ C_ASSERT( FIELD_OFFSET(struct get_message_reply, type) == 32 );
C_ASSERT( FIELD_OFFSET(struct get_message_reply, x) == 36 );
C_ASSERT( FIELD_OFFSET(struct get_message_reply, y) == 40 );
C_ASSERT( FIELD_OFFSET(struct get_message_reply, time) == 44 );
-C_ASSERT( FIELD_OFFSET(struct get_message_reply, active_hooks) == 48 );
-C_ASSERT( FIELD_OFFSET(struct get_message_reply, total) == 52 );
+C_ASSERT( FIELD_OFFSET(struct get_message_reply, total) == 48 );
C_ASSERT( sizeof(struct get_message_reply) == 56 );
C_ASSERT( FIELD_OFFSET(struct reply_message_request, remove) == 12 );
C_ASSERT( FIELD_OFFSET(struct reply_message_request, result) == 16 );
@@ -1396,6 +1429,12 @@ C_ASSERT( sizeof(struct cancel_async_request) == 32 );
C_ASSERT( FIELD_OFFSET(struct get_async_result_request, user_arg) == 16 );
C_ASSERT( sizeof(struct get_async_result_request) == 24 );
C_ASSERT( sizeof(struct get_async_result_reply) == 8 );
+C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_request, handle) == 12 );
+C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_request, information) == 16 );
+C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_request, status) == 24 );
+C_ASSERT( sizeof(struct set_async_direct_result_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_reply, handle) == 8 );
+C_ASSERT( sizeof(struct set_async_direct_result_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct read_request, async) == 16 );
C_ASSERT( FIELD_OFFSET(struct read_request, pos) == 56 );
C_ASSERT( sizeof(struct read_request) == 64 );
@@ -1703,14 +1742,11 @@ C_ASSERT( sizeof(struct get_thread_input_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, focus) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, capture) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, active) == 16 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, foreground) == 20 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, menu_owner) == 24 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, move_size) == 28 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, caret) == 32 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, cursor) == 36 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, show_count) == 40 );
-C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, rect) == 44 );
-C_ASSERT( sizeof(struct get_thread_input_reply) == 64 );
+C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, menu_owner) == 20 );
+C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, move_size) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, caret) == 28 );
+C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, rect) == 32 );
+C_ASSERT( sizeof(struct get_thread_input_reply) == 48 );
C_ASSERT( sizeof(struct get_last_input_time_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_last_input_time_reply, time) == 8 );
C_ASSERT( sizeof(struct get_last_input_time_reply) == 16 );
@@ -1762,6 +1798,9 @@ C_ASSERT( FIELD_OFFSET(struct set_caret_info_reply, old_rect) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_caret_info_reply, old_hide) == 28 );
C_ASSERT( FIELD_OFFSET(struct set_caret_info_reply, old_state) == 32 );
C_ASSERT( sizeof(struct set_caret_info_reply) == 40 );
+C_ASSERT( sizeof(struct get_active_hooks_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_active_hooks_reply, active_hooks) == 8 );
+C_ASSERT( sizeof(struct get_active_hooks_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_hook_request, id) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_hook_request, pid) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_hook_request, tid) == 20 );
@@ -2121,7 +2160,8 @@ C_ASSERT( FIELD_OFFSET(struct add_completion_request, information) == 32 );
C_ASSERT( FIELD_OFFSET(struct add_completion_request, status) == 40 );
C_ASSERT( sizeof(struct add_completion_request) == 48 );
C_ASSERT( FIELD_OFFSET(struct remove_completion_request, handle) == 12 );
-C_ASSERT( sizeof(struct remove_completion_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct remove_completion_request, waited) == 16 );
+C_ASSERT( sizeof(struct remove_completion_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, ckey) == 8 );
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, cvalue) == 16 );
C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, information) == 24 );
@@ -2244,6 +2284,65 @@ C_ASSERT( FIELD_OFFSET(struct get_next_thread_request, flags) == 28 );
C_ASSERT( sizeof(struct get_next_thread_request) == 32 );
C_ASSERT( FIELD_OFFSET(struct get_next_thread_reply, handle) == 8 );
C_ASSERT( sizeof(struct get_next_thread_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_request, access) == 12 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_request, initval) == 16 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_request, type) == 20 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_request, max) == 24 );
+C_ASSERT( sizeof(struct create_esync_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_reply, handle) == 8 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_reply, type) == 12 );
+C_ASSERT( FIELD_OFFSET(struct create_esync_reply, shm_idx) == 16 );
+C_ASSERT( sizeof(struct create_esync_reply) == 24 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_request, access) == 12 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_request, attributes) == 16 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_request, rootdir) == 20 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_request, type) == 24 );
+C_ASSERT( sizeof(struct open_esync_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_reply, handle) == 8 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_reply, type) == 12 );
+C_ASSERT( FIELD_OFFSET(struct open_esync_reply, shm_idx) == 16 );
+C_ASSERT( sizeof(struct open_esync_reply) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_esync_fd_request, handle) == 12 );
+C_ASSERT( sizeof(struct get_esync_fd_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, type) == 8 );
+C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, shm_idx) == 12 );
+C_ASSERT( sizeof(struct get_esync_fd_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct esync_msgwait_request, in_msgwait) == 12 );
+C_ASSERT( sizeof(struct esync_msgwait_request) == 16 );
+C_ASSERT( sizeof(struct get_esync_apc_fd_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_request, access) == 12 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_request, low) == 16 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_request, high) == 20 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_request, type) == 24 );
+C_ASSERT( sizeof(struct create_fsync_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_reply, handle) == 8 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_reply, type) == 12 );
+C_ASSERT( FIELD_OFFSET(struct create_fsync_reply, shm_idx) == 16 );
+C_ASSERT( sizeof(struct create_fsync_reply) == 24 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_request, access) == 12 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_request, attributes) == 16 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_request, rootdir) == 20 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_request, type) == 24 );
+C_ASSERT( sizeof(struct open_fsync_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_reply, handle) == 8 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_reply, type) == 12 );
+C_ASSERT( FIELD_OFFSET(struct open_fsync_reply, shm_idx) == 16 );
+C_ASSERT( sizeof(struct open_fsync_reply) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_fsync_idx_request, handle) == 12 );
+C_ASSERT( sizeof(struct get_fsync_idx_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_fsync_idx_reply, type) == 8 );
+C_ASSERT( FIELD_OFFSET(struct get_fsync_idx_reply, shm_idx) == 12 );
+C_ASSERT( sizeof(struct get_fsync_idx_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct fsync_msgwait_request, in_msgwait) == 12 );
+C_ASSERT( sizeof(struct fsync_msgwait_request) == 16 );
+C_ASSERT( sizeof(struct get_fsync_apc_idx_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_fsync_apc_idx_reply, shm_idx) == 8 );
+C_ASSERT( sizeof(struct get_fsync_apc_idx_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct init_working_set_watch_request, fd) == 12 );
+C_ASSERT( sizeof(struct init_working_set_watch_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_ws_watches_request, process) == 12 );
+C_ASSERT( sizeof(struct get_ws_watches_request) == 16 );
+C_ASSERT( sizeof(struct get_ws_watches_reply) == 8 );
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/thread.c b/server/thread.c
index 4c51567c286..5163d540531 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -758,8 +758,21 @@ affinity_t get_thread_affinity( struct thread *thread )
unsigned int i;
if (!sched_getaffinity( thread->unix_tid, sizeof(set), &set ))
+ {
for (i = 0; i < 8 * sizeof(mask); i++)
- if (CPU_ISSET( i, &set )) mask |= (affinity_t)1 << i;
+ if (CPU_ISSET( i, &set ))
+ {
+ if (thread->process->cpu_override.cpu_count)
+ {
+ if (i < ARRAY_SIZE(thread->process->wine_cpu_id_from_host))
+ mask |= (affinity_t)1 << thread->process->wine_cpu_id_from_host[i];
+ }
+ else
+ {
+ mask |= (affinity_t)1 << i;
+ }
+ }
+ }
}
#endif
if (!mask) mask = ~(affinity_t)0;
@@ -1672,8 +1685,7 @@ DECL_HANDLER(init_first_thread)
else
{
set_thread_priority( current, current->process->priority, current->priority );
- if (!process->cpu_override.cpu_count)
- set_thread_affinity( current, current->affinity );
+ set_thread_affinity( current, current->affinity );
}
debug_level = max( debug_level, req->debug_level );
@@ -1706,8 +1718,7 @@ DECL_HANDLER(init_thread)
init_thread_context( current );
generate_debug_event( current, DbgCreateThreadStateChange, &req->entry );
set_thread_priority( current, current->process->priority, current->priority );
- if (!current->process->cpu_override.cpu_count)
- set_thread_affinity( current, current->affinity );
+ set_thread_affinity( current, current->affinity );
reply->suspend = (current->suspend || current->process->suspend || current->context != NULL);
}
diff --git a/server/trace.c b/server/trace.c
index e971ba20b6f..39afbe199f4 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1487,6 +1487,8 @@ static void dump_init_process_done_request( const struct init_process_done_reque
dump_uint64( " teb=", &req->teb );
dump_uint64( ", peb=", &req->peb );
dump_uint64( ", ldt_copy=", &req->ldt_copy );
+ dump_uint64( ", kernel_stack=", &req->kernel_stack );
+ fprintf( stderr, ", kernel_stack_size=%08x", req->kernel_stack_size );
}
static void dump_init_process_done_reply( const struct init_process_done_reply *req )
@@ -1503,6 +1505,7 @@ static void dump_init_first_thread_request( const struct init_first_thread_reque
fprintf( stderr, ", debug_level=%d", req->debug_level );
fprintf( stderr, ", reply_fd=%d", req->reply_fd );
fprintf( stderr, ", wait_fd=%d", req->wait_fd );
+ fprintf( stderr, ", nice_limit=%c", req->nice_limit );
}
static void dump_init_first_thread_reply( const struct init_first_thread_reply *req )
@@ -1522,6 +1525,8 @@ static void dump_init_thread_request( const struct init_thread_request *req )
fprintf( stderr, ", wait_fd=%d", req->wait_fd );
dump_uint64( ", teb=", &req->teb );
dump_uint64( ", entry=", &req->entry );
+ dump_uint64( ", kernel_stack=", &req->kernel_stack );
+ fprintf( stderr, ", kernel_stack_size=%08x", req->kernel_stack_size );
}
static void dump_init_thread_reply( const struct init_thread_reply *req )
@@ -2098,14 +2103,14 @@ static void dump_recv_socket_request( const struct recv_socket_request *req )
{
fprintf( stderr, " oob=%d", req->oob );
dump_async_data( ", async=", &req->async );
- fprintf( stderr, ", status=%08x", req->status );
- fprintf( stderr, ", total=%08x", req->total );
+ fprintf( stderr, ", force_async=%d", req->force_async );
}
static void dump_recv_socket_reply( const struct recv_socket_reply *req )
{
fprintf( stderr, " wait=%04x", req->wait );
fprintf( stderr, ", options=%08x", req->options );
+ fprintf( stderr, ", nonblocking=%d", req->nonblocking );
}
static void dump_send_socket_request( const struct send_socket_request *req )
@@ -2340,7 +2345,8 @@ static void dump_read_process_memory_request( const struct read_process_memory_r
static void dump_read_process_memory_reply( const struct read_process_memory_reply *req )
{
- dump_varargs_bytes( " data=", cur_size );
+ fprintf( stderr, " unix_pid=%d", req->unix_pid );
+ dump_varargs_bytes( ", data=", cur_size );
}
static void dump_write_process_memory_request( const struct write_process_memory_request *req )
@@ -2698,7 +2704,6 @@ static void dump_send_hardware_message_reply( const struct send_hardware_message
fprintf( stderr, ", prev_y=%d", req->prev_y );
fprintf( stderr, ", new_x=%d", req->new_x );
fprintf( stderr, ", new_y=%d", req->new_y );
- dump_varargs_bytes( ", keystate=", cur_size );
}
static void dump_get_message_request( const struct get_message_request *req )
@@ -2722,7 +2727,6 @@ static void dump_get_message_reply( const struct get_message_reply *req )
fprintf( stderr, ", x=%d", req->x );
fprintf( stderr, ", y=%d", req->y );
fprintf( stderr, ", time=%08x", req->time );
- fprintf( stderr, ", active_hooks=%08x", req->active_hooks );
fprintf( stderr, ", total=%u", req->total );
dump_varargs_message_data( ", data=", cur_size );
}
@@ -2824,6 +2828,18 @@ static void dump_get_async_result_reply( const struct get_async_result_reply *re
dump_varargs_bytes( " out_data=", cur_size );
}
+static void dump_set_async_direct_result_request( const struct set_async_direct_result_request *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+ dump_uint64( ", information=", &req->information );
+ fprintf( stderr, ", status=%08x", req->status );
+}
+
+static void dump_set_async_direct_result_reply( const struct set_async_direct_result_reply *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+}
+
static void dump_read_request( const struct read_request *req )
{
dump_async_data( " async=", &req->async );
@@ -3428,12 +3444,9 @@ static void dump_get_thread_input_reply( const struct get_thread_input_reply *re
fprintf( stderr, " focus=%08x", req->focus );
fprintf( stderr, ", capture=%08x", req->capture );
fprintf( stderr, ", active=%08x", req->active );
- fprintf( stderr, ", foreground=%08x", req->foreground );
fprintf( stderr, ", menu_owner=%08x", req->menu_owner );
fprintf( stderr, ", move_size=%08x", req->move_size );
fprintf( stderr, ", caret=%08x", req->caret );
- fprintf( stderr, ", cursor=%08x", req->cursor );
- fprintf( stderr, ", show_count=%d", req->show_count );
dump_rectangle( ", rect=", &req->rect );
}
@@ -3541,6 +3554,15 @@ static void dump_set_caret_info_reply( const struct set_caret_info_reply *req )
fprintf( stderr, ", old_state=%d", req->old_state );
}
+static void dump_get_active_hooks_request( const struct get_active_hooks_request *req )
+{
+}
+
+static void dump_get_active_hooks_reply( const struct get_active_hooks_reply *req )
+{
+ fprintf( stderr, " active_hooks=%08x", req->active_hooks );
+}
+
static void dump_set_hook_request( const struct set_hook_request *req )
{
fprintf( stderr, " id=%d", req->id );
@@ -4286,6 +4308,7 @@ static void dump_add_completion_request( const struct add_completion_request *re
static void dump_remove_completion_request( const struct remove_completion_request *req )
{
fprintf( stderr, " handle=%04x", req->handle );
+ fprintf( stderr, ", waited=%d", req->waited );
}
static void dump_remove_completion_reply( const struct remove_completion_reply *req )
@@ -4536,6 +4559,130 @@ static void dump_get_next_thread_reply( const struct get_next_thread_reply *req
fprintf( stderr, " handle=%04x", req->handle );
}
+static void dump_create_esync_request( const struct create_esync_request *req )
+{
+ fprintf( stderr, " access=%08x", req->access );
+ fprintf( stderr, ", initval=%d", req->initval );
+ fprintf( stderr, ", type=%d", req->type );
+ fprintf( stderr, ", max=%d", req->max );
+ dump_varargs_object_attributes( ", objattr=", cur_size );
+}
+
+static void dump_create_esync_reply( const struct create_esync_reply *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+ fprintf( stderr, ", type=%d", req->type );
+ fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_open_esync_request( const struct open_esync_request *req )
+{
+ fprintf( stderr, " access=%08x", req->access );
+ fprintf( stderr, ", attributes=%08x", req->attributes );
+ fprintf( stderr, ", rootdir=%04x", req->rootdir );
+ fprintf( stderr, ", type=%d", req->type );
+ dump_varargs_unicode_str( ", name=", cur_size );
+}
+
+static void dump_open_esync_reply( const struct open_esync_reply *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+ fprintf( stderr, ", type=%d", req->type );
+ fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_get_esync_fd_request( const struct get_esync_fd_request *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+}
+
+static void dump_get_esync_fd_reply( const struct get_esync_fd_reply *req )
+{
+ fprintf( stderr, " type=%d", req->type );
+ fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_esync_msgwait_request( const struct esync_msgwait_request *req )
+{
+ fprintf( stderr, " in_msgwait=%d", req->in_msgwait );
+}
+
+static void dump_get_esync_apc_fd_request( const struct get_esync_apc_fd_request *req )
+{
+}
+
+static void dump_create_fsync_request( const struct create_fsync_request *req )
+{
+ fprintf( stderr, " access=%08x", req->access );
+ fprintf( stderr, ", low=%d", req->low );
+ fprintf( stderr, ", high=%d", req->high );
+ fprintf( stderr, ", type=%d", req->type );
+ dump_varargs_object_attributes( ", objattr=", cur_size );
+}
+
+static void dump_create_fsync_reply( const struct create_fsync_reply *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+ fprintf( stderr, ", type=%d", req->type );
+ fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_open_fsync_request( const struct open_fsync_request *req )
+{
+ fprintf( stderr, " access=%08x", req->access );
+ fprintf( stderr, ", attributes=%08x", req->attributes );
+ fprintf( stderr, ", rootdir=%04x", req->rootdir );
+ fprintf( stderr, ", type=%d", req->type );
+ dump_varargs_unicode_str( ", name=", cur_size );
+}
+
+static void dump_open_fsync_reply( const struct open_fsync_reply *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+ fprintf( stderr, ", type=%d", req->type );
+ fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_get_fsync_idx_request( const struct get_fsync_idx_request *req )
+{
+ fprintf( stderr, " handle=%04x", req->handle );
+}
+
+static void dump_get_fsync_idx_reply( const struct get_fsync_idx_reply *req )
+{
+ fprintf( stderr, " type=%d", req->type );
+ fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_fsync_msgwait_request( const struct fsync_msgwait_request *req )
+{
+ fprintf( stderr, " in_msgwait=%d", req->in_msgwait );
+}
+
+static void dump_get_fsync_apc_idx_request( const struct get_fsync_apc_idx_request *req )
+{
+}
+
+static void dump_get_fsync_apc_idx_reply( const struct get_fsync_apc_idx_reply *req )
+{
+ fprintf( stderr, " shm_idx=%08x", req->shm_idx );
+}
+
+static void dump_init_working_set_watch_request( const struct init_working_set_watch_request *req )
+{
+ fprintf( stderr, " fd=%d", req->fd );
+}
+
+static void dump_get_ws_watches_request( const struct get_ws_watches_request *req )
+{
+ fprintf( stderr, " process=%04x", req->process );
+}
+
+static void dump_get_ws_watches_reply( const struct get_ws_watches_reply *req )
+{
+ dump_varargs_ws_watch_data( " info=", cur_size );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
@@ -4660,6 +4807,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_register_async_request,
(dump_func)dump_cancel_async_request,
(dump_func)dump_get_async_result_request,
+ (dump_func)dump_set_async_direct_result_request,
(dump_func)dump_read_request,
(dump_func)dump_write_request,
(dump_func)dump_ioctl_request,
@@ -4720,6 +4868,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_capture_window_request,
(dump_func)dump_set_caret_window_request,
(dump_func)dump_set_caret_info_request,
+ (dump_func)dump_get_active_hooks_request,
(dump_func)dump_set_hook_request,
(dump_func)dump_remove_hook_request,
(dump_func)dump_start_hook_chain_request,
@@ -4811,6 +4960,18 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_suspend_process_request,
(dump_func)dump_resume_process_request,
(dump_func)dump_get_next_thread_request,
+ (dump_func)dump_create_esync_request,
+ (dump_func)dump_open_esync_request,
+ (dump_func)dump_get_esync_fd_request,
+ (dump_func)dump_esync_msgwait_request,
+ (dump_func)dump_get_esync_apc_fd_request,
+ (dump_func)dump_create_fsync_request,
+ (dump_func)dump_open_fsync_request,
+ (dump_func)dump_get_fsync_idx_request,
+ (dump_func)dump_fsync_msgwait_request,
+ (dump_func)dump_get_fsync_apc_idx_request,
+ (dump_func)dump_init_working_set_watch_request,
+ (dump_func)dump_get_ws_watches_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -4937,6 +5098,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
NULL,
NULL,
(dump_func)dump_get_async_result_reply,
+ (dump_func)dump_set_async_direct_result_reply,
(dump_func)dump_read_reply,
(dump_func)dump_write_reply,
(dump_func)dump_ioctl_reply,
@@ -4997,6 +5159,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_capture_window_reply,
(dump_func)dump_set_caret_window_reply,
(dump_func)dump_set_caret_info_reply,
+ (dump_func)dump_get_active_hooks_reply,
(dump_func)dump_set_hook_reply,
(dump_func)dump_remove_hook_reply,
(dump_func)dump_start_hook_chain_reply,
@@ -5088,6 +5251,18 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
NULL,
NULL,
(dump_func)dump_get_next_thread_reply,
+ (dump_func)dump_create_esync_reply,
+ (dump_func)dump_open_esync_reply,
+ (dump_func)dump_get_esync_fd_reply,
+ NULL,
+ NULL,
+ (dump_func)dump_create_fsync_reply,
+ (dump_func)dump_open_fsync_reply,
+ (dump_func)dump_get_fsync_idx_reply,
+ NULL,
+ (dump_func)dump_get_fsync_apc_idx_reply,
+ NULL,
+ (dump_func)dump_get_ws_watches_reply,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -5214,6 +5389,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"register_async",
"cancel_async",
"get_async_result",
+ "set_async_direct_result",
"read",
"write",
"ioctl",
@@ -5274,6 +5450,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"set_capture_window",
"set_caret_window",
"set_caret_info",
+ "get_active_hooks",
"set_hook",
"remove_hook",
"start_hook_chain",
@@ -5365,6 +5542,18 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"suspend_process",
"resume_process",
"get_next_thread",
+ "create_esync",
+ "open_esync",
+ "get_esync_fd",
+ "esync_msgwait",
+ "get_esync_apc_fd",
+ "create_fsync",
+ "open_fsync",
+ "get_fsync_idx",
+ "fsync_msgwait",
+ "get_fsync_apc_idx",
+ "init_working_set_watch",
+ "get_ws_watches",
};
static const struct
@@ -5480,6 +5669,7 @@ static const struct
{ "PIPE_EMPTY", STATUS_PIPE_EMPTY },
{ "PIPE_LISTENING", STATUS_PIPE_LISTENING },
{ "PIPE_NOT_AVAILABLE", STATUS_PIPE_NOT_AVAILABLE },
+ { "PORT_ALREADY_SET", STATUS_PORT_ALREADY_SET },
{ "PORT_NOT_SET", STATUS_PORT_NOT_SET },
{ "PREDEFINED_HANDLE", STATUS_PREDEFINED_HANDLE },
{ "PRIVILEGE_NOT_HELD", STATUS_PRIVILEGE_NOT_HELD },
diff --git a/tools/Makefile.in b/tools/Makefile.in
index adf53bb2c51..ff2da5e8584 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -5,4 +5,5 @@ C_SRCS = \
make_xftmpl.c
IN_SRCS = \
+ gdbinit.py.in \
wineapploader.in
diff --git a/tools/gdbinit.py b/tools/gdbinit.py
new file mode 100644
index 00000000000..ba3b7d003ac
--- /dev/null
+++ b/tools/gdbinit.py
@@ -0,0 +1,113 @@
+#!/bin/env python3
+
+# Copyright 2021 RĂ©mi Bernon for CodeWeavers
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+from __future__ import print_function
+
+import gdb
+import re
+import subprocess
+import sys
+
+class LoadSymbolFiles(gdb.Command):
+ 'Command to load symbol files directly from /proc//maps.'
+
+ def __init__(self):
+ sup = super(LoadSymbolFiles, self)
+ sup.__init__('load-symbol-files', gdb.COMMAND_FILES, gdb.COMPLETE_NONE,
+ False)
+
+ self.libs = {}
+ gdb.execute('alias -a lsf = load-symbol-files', True)
+
+ def invoke(self, arg, from_tty):
+ pid = gdb.selected_inferior().pid
+ if not pid in self.libs: self.libs[pid] = {}
+
+ def command(cmd, confirm=from_tty, to_string=not from_tty):
+ gdb.execute(cmd, from_tty=confirm, to_string=to_string)
+
+ def execute(cmd):
+ return subprocess.check_output(cmd, stderr=subprocess.STDOUT) \
+ .decode('utf-8')
+
+ # load mappings addresses
+ libs = {}
+ with open('/proc/{}/maps'.format(pid), 'r') as maps:
+ for line in maps:
+ addr, _, _, _, node, path = re.split(r'\s+', line, 5)
+ path = path.strip()
+ if node == '0': continue
+ if path in libs: continue
+ libs[path] = int(addr.split('-')[0], 16)
+
+ # unload symbol file if address changed
+ for k in set(libs) & set(self.libs[pid]):
+ if libs[k] != self.libs[pid][k]:
+ command('remove-symbol-file "{}"'.format(k), confirm=False)
+ del self.libs[k]
+
+ # load symbol file for new mappings
+ for k in set(libs) - set(self.libs[pid]):
+ if arg is not None and re.search(arg, k) is None: continue
+ addr = self.libs[pid][k] = libs[k]
+ has_debug = False
+ offs = None
+
+ try:
+ out = execute(['file', k])
+ except:
+ continue
+
+ # try loading mapping as ELF
+ try:
+ out = execute(['readelf', '-l', k])
+ for line in out.split('\n'):
+ if not 'LOAD' in line: continue
+ base = int(line.split()[2], 16)
+ break
+ except:
+ # assume mapping is PE
+ base = -1
+
+ try:
+ name = None
+ cmd = 'add-symbol-file "{}"'.format(k)
+ out = execute(['objdump', '-h', k])
+ for line in out.split('\n'):
+ if '2**' in line:
+ _, name, _, vma, _, off, _ = line.split(maxsplit=6)
+ if base < 0: offs = int(off, 16)
+ else: offs = int(vma, 16) - base
+ if 'ALLOC' in line:
+ cmd += ' -s {} 0x{:x}'.format(name, addr + offs)
+ elif name in ['.gnu_debuglink', '.debug_info']:
+ has_debug = True
+ elif 'DEBUGGING' in line:
+ has_debug = True
+ except:
+ continue
+
+ if not has_debug:
+ print('no debugging info found in {}'.format(k))
+ continue
+
+ print('loading symbols for {}'.format(k))
+ command(cmd, confirm=False, to_string=True)
+
+
+LoadSymbolFiles()
diff --git a/tools/gdbinit.py.in b/tools/gdbinit.py.in
new file mode 120000
index 00000000000..9fb7fdf9b92
--- /dev/null
+++ b/tools/gdbinit.py.in
@@ -0,0 +1 @@
+gdbinit.py
\ No newline at end of file