Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2019
- 73 participants
- 565 discussions
11 Jun '19
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/dxgi/tests/dxgi.c | 167 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 167 insertions(+)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 765b174af6..216f03eed8 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -3992,9 +3992,13 @@ static void test_swapchain_parameters(void)
static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
{
+ static const DWORD flags[] = {0, DXGI_PRESENT_TEST};
+ static const DWORD timeout = 2000;
DXGI_SWAP_CHAIN_DESC swapchain_desc;
IDXGISwapChain *swapchain;
IDXGIFactory *factory;
+ IDXGIOutput *output;
+ BOOL fullscreen;
unsigned int i;
ULONG refcount;
HRESULT hr;
@@ -4029,6 +4033,169 @@ static void test_swapchain_present(IUnknown *device, BOOL is_d3d12)
hr = IDXGISwapChain_Present(swapchain, 0, 0);
ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ for (i = 0; i < ARRAY_SIZE(flags); ++i)
+ {
+ HWND occluding_hwnd = CreateWindowA("static", "occluding_window", WS_POPUP | WS_VISIBLE, 0, 0, 400, 200, 0, 0, 0, 0);
+
+ /* Another window covers the swapchain window, doesn't report as occluded */
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* Minimized window */
+ ShowWindow(swapchain_desc.OutputWindow, SW_MINIMIZE);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ todo_wine_if(!is_d3d12) ok(hr == (is_d3d12 ? S_OK : DXGI_STATUS_OCCLUDED), "Got unexpected hr %#x.\n", hr);
+ ShowWindow(swapchain_desc.OutputWindow, SW_NORMAL);
+
+ /* Hidden window */
+ ShowWindow(swapchain_desc.OutputWindow, SW_HIDE);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ShowWindow(swapchain_desc.OutputWindow, SW_SHOW);
+ DestroyWindow(occluding_hwnd);
+
+ /* Test IDXGIOutput_ReleaseOwnership makes the swapchain exit fullscreen */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE on some machines. DXGI_ERROR_UNSUPPORTED on Win 7 testbot. */
+ if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE || broken(hr == DXGI_ERROR_UNSUPPORTED))
+ {
+ skip("Could not change fullscreen state.\n");
+ continue;
+ }
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ output = NULL;
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, &output);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ todo_wine_if(is_d3d12) ok(output != NULL, "Expect output not null.\n");
+
+ if (output) IDXGIOutput_ReleaseOwnership(output);
+ /* Still in fullscreen */
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ /* Now calling IDXGISwapChain_Present will exit the fullscreen */
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ /* Now fullscreen mode is exited */
+ if (flags[i] == 0 && !is_d3d12)
+ {
+ /* Still on fullscreen on vista and 2008 */
+ todo_wine ok(!fullscreen || broken(fullscreen), "Unexpected fullscreen status.\n");
+ }
+ else
+ ok(fullscreen, "Unexpected fullscreen status.\n");
+ if (output) IDXGIOutput_Release(output);
+
+
+ /* Test creating a window when swapchain is in fullscreen.
+ * The window should break the swapchain out of fullscreen mode on d3d10/11.
+ * d3d12 is different, new occluding window doesn't break swapchain out of fullscreen because d3d12 swapchain
+ * fullscreen mode doesn't take exclusive ownership over output, nor does it disable compositing.
+ * d3d12 fullscreen mode acts just like borderless fullscreen window mode */
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ occluding_hwnd = CreateWindowA("static", "occluding_window", WS_POPUP, 0, 0, 400, 200, 0, 0, 0, 0);
+ /* Invisible window doesn't cause fullscreen mode to exit */
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = FALSE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(is_d3d12) ok(fullscreen, "Unexpected fullscreen status.\n");
+ /* Visible but with bottom z-order window still cause fullscreen mode to exit */
+ SetWindowPos(occluding_hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ ShowWindow(occluding_hwnd, SW_SHOW);
+ /* Fullscreen mode takes a while to exit */
+ Sleep(timeout);
+
+ /* No longer fullscreen before calling IDXGISwapChain_Present except for d3d12 */
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen, "Unexpected fullscreen status.\n");
+
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK), "Got unexpected hr %#x.\n", hr);
+
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ if (flags[i] == DXGI_PRESENT_TEST)
+ todo_wine_if(!is_d3d12) ok(is_d3d12 ? fullscreen : !fullscreen, "Unexpected fullscreen status.\n");
+ else
+ todo_wine ok(!fullscreen, "Unexpected fullscreen status.\n");
+
+ /* Even though d3d12 doesn't exit fullscreen, a IDXGISwapChain_ResizeBuffers is still needed for subsequent
+ * IDXGISwapChain_Present calls to work, otherwise they will return DXGI_ERROR_INVALID_CALL */
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ if (flags[i] == DXGI_PRESENT_TEST)
+ todo_wine_if(is_d3d12) ok(hr == (is_d3d12 ? DXGI_STATUS_OCCLUDED : S_OK), "Got unexpected hr %#x.\n", hr);
+ else
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+
+ /* Trying break out of fullscreen mode again. This time, don't call IDXGISwapChain_GetFullscreenState before
+ * IDXGISwapChain_Present */
+ ShowWindow(occluding_hwnd, SW_HIDE);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ShowWindow(occluding_hwnd, SW_SHOW);
+
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ /* hr == S_OK on vista and 2008 */
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK), "Got unexpected hr %#x.\n", hr);
+
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ if (flags[i] == DXGI_PRESENT_TEST)
+ {
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK), "Got unexpected hr %#x.\n", hr);
+ /* IDXGISwapChain_Present without flags refresh the occlusion state */
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == S_OK), "Got unexpected hr %#x.\n", hr);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+ else
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ fullscreen = TRUE;
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!fullscreen, "Unexpected fullscreen status.\n");
+
+ DestroyWindow(occluding_hwnd);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ hr = IDXGISwapChain_Present(swapchain, 0, flags[i]);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ todo_wine_if(is_d3d12) ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
+ }
+
wait_device_idle(device);
IDXGISwapChain_Release(swapchain);
--
2.20.1
3
2
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/main.c | 75 +++++++++++++++++++++++++++++++-------
dlls/mfplat/mfplat.spec | 1 +
dlls/mfplat/tests/mfplat.c | 15 ++++++++
3 files changed, 77 insertions(+), 14 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 4082f9e2ac..b0db0db922 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -48,13 +48,22 @@ static LONG platform_lock;
struct local_handler
{
struct list entry;
- WCHAR *scheme;
+ union
+ {
+ WCHAR *scheme;
+ struct
+ {
+ WCHAR *extension;
+ WCHAR *mime;
+ } bytestream;
+ } u;
IMFActivate *activate;
};
static CRITICAL_SECTION local_handlers_section = { NULL, -1, 0, 0, 0, 0 };
static struct list local_scheme_handlers = LIST_INIT(local_scheme_handlers);
+static struct list local_bytestream_handlers = LIST_INIT(local_bytestream_handlers);
struct system_clock
{
@@ -7154,21 +7163,25 @@ static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl =
async_create_file_callback_Invoke,
};
-static WCHAR *heap_strdupW(const WCHAR *str)
+static HRESULT heap_strdupW(const WCHAR *str, WCHAR **dest)
{
- WCHAR *ret = NULL;
+ HRESULT hr = S_OK;
if (str)
{
unsigned int size;
size = (strlenW(str) + 1) * sizeof(WCHAR);
- ret = heap_alloc(size);
- if (ret)
- memcpy(ret, str, size);
+ *dest = heap_alloc(size);
+ if (*dest)
+ memcpy(*dest, str, size);
+ else
+ hr = E_OUTOFMEMORY;
}
+ else
+ *dest = NULL;
- return ret;
+ return hr;
}
/***********************************************************************
@@ -7202,12 +7215,8 @@ HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMOD
async->access_mode = access_mode;
async->open_mode = open_mode;
async->flags = flags;
- async->path = heap_strdupW(path);
- if (!async->path)
- {
- hr = E_OUTOFMEMORY;
+ if (FAILED(hr = heap_strdupW(path, &async->path)))
goto failed;
- }
hr = MFCreateAsyncResult(NULL, &async->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
if (FAILED(hr))
@@ -7301,6 +7310,7 @@ HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie)
HRESULT WINAPI MFRegisterLocalSchemeHandler(const WCHAR *scheme, IMFActivate *activate)
{
struct local_handler *handler;
+ HRESULT hr;
TRACE("%s, %p.\n", debugstr_w(scheme), activate);
@@ -7310,10 +7320,10 @@ HRESULT WINAPI MFRegisterLocalSchemeHandler(const WCHAR *scheme, IMFActivate *ac
if (!(handler = heap_alloc(sizeof(*handler))))
return E_OUTOFMEMORY;
- if (!(handler->scheme = heap_strdupW(scheme)))
+ if (FAILED(hr = heap_strdupW(scheme, &handler->u.scheme)))
{
heap_free(handler);
- return E_OUTOFMEMORY;
+ return hr;
}
handler->activate = activate;
IMFActivate_AddRef(handler->activate);
@@ -7324,3 +7334,40 @@ HRESULT WINAPI MFRegisterLocalSchemeHandler(const WCHAR *scheme, IMFActivate *ac
return S_OK;
}
+
+/***********************************************************************
+ * MFRegisterLocalByteStreamHandler (mfplat.@)
+ */
+HRESULT WINAPI MFRegisterLocalByteStreamHandler(const WCHAR *extension, const WCHAR *mime, IMFActivate *activate)
+{
+ struct local_handler *handler;
+ HRESULT hr;
+
+ TRACE("%s, %s, %p.\n", debugstr_w(extension), debugstr_w(mime), activate);
+
+ if ((!extension && !mime) || !activate)
+ return E_INVALIDARG;
+
+ if (!(handler = heap_alloc_zero(sizeof(*handler))))
+ return E_OUTOFMEMORY;
+
+ hr = heap_strdupW(extension, &handler->u.bytestream.extension);
+ if (SUCCEEDED(hr))
+ hr = heap_strdupW(mime, &handler->u.bytestream.mime);
+
+ if (FAILED(hr))
+ goto failed;
+
+ EnterCriticalSection(&local_handlers_section);
+ list_add_head(&local_bytestream_handlers, &handler->entry);
+ LeaveCriticalSection(&local_handlers_section);
+
+ return hr;
+
+failed:
+ heap_free(handler->u.bytestream.extension);
+ heap_free(handler->u.bytestream.mime);
+ heap_free(handler);
+
+ return hr;
+}
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 2dfa92f202..1ae0927f51 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -128,6 +128,7 @@
@ stdcall MFPutWorkItemEx(long ptr)
@ stdcall MFPutWorkItemEx2(long long ptr)
@ stub MFRecordError
+@ stdcall MFRegisterLocalByteStreamHandler(wstr wstr ptr)
@ stdcall MFRegisterLocalSchemeHandler(wstr ptr)
@ stdcall MFRemovePeriodicCallback(long)
@ stdcall MFScheduleWorkItem(ptr ptr int64 ptr)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index ab651c54f2..e63efc154b 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -3591,6 +3591,21 @@ static void test_local_handlers(void)
hr = pMFRegisterLocalSchemeHandler(localW, &local_activate);
ok(hr == S_OK, "Failed to register scheme handler, hr %#x.\n", hr);
+
+ hr = pMFRegisterLocalByteStreamHandler(NULL, NULL, NULL);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ hr = pMFRegisterLocalByteStreamHandler(NULL, NULL, &local_activate);
+ ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+ hr = pMFRegisterLocalByteStreamHandler(NULL, localW, &local_activate);
+ ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr);
+
+ hr = pMFRegisterLocalByteStreamHandler(localW, NULL, &local_activate);
+ ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr);
+
+ hr = pMFRegisterLocalByteStreamHandler(localW, localW, &local_activate);
+ ok(hr == S_OK, "Failed to register stream handler, hr %#x.\n", hr);
}
START_TEST(mfplat)
--
2.20.1
2
5
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/misc.c | 202 +++++++++++++++++++++++++++++++++++-
dlls/user32/tests/monitor.c | 8 +-
2 files changed, 205 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c
index 355457098d..5f26cf9af3 100644
--- a/dlls/user32/misc.c
+++ b/dlls/user32/misc.c
@@ -29,9 +29,13 @@
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
+#include "winreg.h"
#include "winnls.h"
#include "winternl.h"
#include "controls.h"
+#include "initguid.h"
+#include "devguid.h"
+#include "setupapi.h"
#include "user_private.h"
#include "wine/unicode.h"
@@ -39,6 +43,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(win);
+/* Wine specific monitor properties */
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
+
static const WCHAR default_adapter_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
static const WCHAR default_monitor_name[] =
{'\\','\\','.','\\',
@@ -66,6 +73,36 @@ static const WCHAR default_monitor_interface_id[] =
'{','e','6','f','0','7','b','5','f','-','e','e','9','7','-','4','a','9','0','-',
'b','0','7','6','-','3','3','f','5','7','b','f','4','e','a','a','7','}',0};
+static const WCHAR monitor_fmtW[] =
+ {'\\','\\','.','\\',
+ 'D','I','S','P','L','A','Y','%','d','\\',
+ 'M','o','n','i','t','o','r','%','d',0};
+static const WCHAR adapter_fmtW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','%','d',0};
+static const WCHAR displayW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'};
+static const WCHAR video_keyW[] =
+ {'H','A','R','D','W','A','R','E','\\',
+ 'D','E','V','I','C','E','M','A','P','\\',
+ 'V','I','D','E','O','\\',0};
+static const WCHAR video_value_fmtW[] =
+ {'\\','D','e','v','i','c','e','\\',
+ 'V','i','d','e','o','%','d',0};
+static const WCHAR monitor_interface_prefixW[] = {'\\','\\','\?','\\',0};
+static const WCHAR guid_devinterface_monitorW[] =
+ {'#','{','e','6','f','0','7','b','5','f','-','e','e','9','7','-',
+ '4','a','9','0','-','b','0','7','6','-','3','3','f','5','7','b','f','4','e','a','a','7','}',0};
+static const WCHAR backslashW[] = {'\\',0};
+static const WCHAR nt_classW[] =
+ {'\\','R','e','g','i','s','t','r','y','\\',
+ 'M','a','c','h','i','n','e','\\',
+ 'S','y','s','t','e','m','\\',
+ 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+ 'C','o','n','t','r','o','l','\\',
+ 'C','l','a','s','s','\\',0};
+static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
+static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
+static const WCHAR mointor_id_value_fmtW[] = {'M','o','n','i','t','o','r','I','D','%','d',0};
+
#define IMM_INIT_MAGIC 0x19650412
static HWND (WINAPI *imm_get_ui_window)(HKL);
BOOL (WINAPI *imm_register_window)(HWND) = NULL;
@@ -309,11 +346,174 @@ BOOL WINAPI EnumDisplayDevicesA( LPCSTR lpDevice, DWORD i, LPDISPLAY_DEVICEA lpD
BOOL WINAPI EnumDisplayDevicesW( LPCWSTR lpDevice, DWORD i, LPDISPLAY_DEVICEW lpDisplayDevice,
DWORD dwFlags )
{
- FIXME("(%s,%d,%p,0x%08x), stub!\n",debugstr_w(lpDevice),i,lpDisplayDevice,dwFlags);
+ SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+ HDEVINFO set = INVALID_HANDLE_VALUE;
+ WCHAR key_nameW[MAX_PATH];
+ WCHAR instanceW[MAX_PATH];
+ WCHAR bufferW[1024];
+ LONG adapter_index;
+ WCHAR *next_charW;
+ DWORD size;
+ DWORD type;
+ HKEY hkey;
+ BOOL ret = FALSE;
+
+ TRACE("%s %d %p %#x\n", debugstr_w(lpDevice), i, lpDisplayDevice, dwFlags);
+
+ /* Find adapter */
+ if (!lpDevice)
+ {
+ sprintfW(key_nameW, video_value_fmtW, i);
+ size = sizeof(bufferW);
+ if (RegGetValueW(HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size))
+ return FALSE;
+
+ /* DeviceKey */
+ if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
+ lstrcpyW(lpDisplayDevice->DeviceKey, bufferW);
+
+ /* DeviceName */
+ sprintfW(lpDisplayDevice->DeviceName, adapter_fmtW, i + 1);
+
+ /* Strip \Registry\Machine\ */
+ lstrcpyW(key_nameW, bufferW + 18);
+
+ /* DeviceString */
+ size = sizeof(lpDisplayDevice->DeviceString);
+ if (RegGetValueW(HKEY_LOCAL_MACHINE, key_nameW, driver_descW, RRF_RT_REG_SZ, NULL,
+ lpDisplayDevice->DeviceString, &size))
+ return FALSE;
+
+ /* StateFlags */
+ size = sizeof(lpDisplayDevice->StateFlags);
+ if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, RRF_RT_REG_DWORD, NULL,
+ &lpDisplayDevice->StateFlags, &size))
+ return FALSE;
+
+ /* DeviceID */
+ if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
+ {
+ if (dwFlags & EDD_GET_DEVICE_INTERFACE_NAME)
+ lpDisplayDevice->DeviceID[0] = 0;
+ else
+ {
+ size = sizeof(bufferW);
+ if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, gpu_idW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
+ bufferW, &size))
+ return FALSE;
+ set = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+ if (!SetupDiOpenDeviceInfoW(set, bufferW, NULL, 0, &device_data)
+ || !SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
+ sizeof(bufferW), NULL))
+ goto done;
+ lstrcpyW(lpDisplayDevice->DeviceID, bufferW);
+ }
+ }
+ }
+ /* Find monitor */
+ else
+ {
+ /* Check adapter name */
+ if (strncmpiW(lpDevice, displayW, ARRAY_SIZE(displayW)))
+ return FALSE;
+
+ adapter_index = strtolW(lpDevice + ARRAY_SIZE(displayW), NULL, 10);
+ sprintfW(key_nameW, video_value_fmtW, adapter_index - 1);
+
+ size = sizeof(bufferW);
+ if (RegGetValueW(HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size))
+ return FALSE;
+ /* DeviceName */
+ sprintfW(lpDisplayDevice->DeviceName, monitor_fmtW, adapter_index, i);
+
+ /* Get monitor instance */
+ /* Strip \Registry\Machine\ first */
+ lstrcpyW(key_nameW, bufferW + 18);
+ sprintfW(bufferW, mointor_id_value_fmtW, i);
+
+ size = sizeof(instanceW);
+ if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ, NULL, instanceW, &size))
+ return FALSE;
+
+ set = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
+ if (!SetupDiOpenDeviceInfoW(set, instanceW, NULL, 0, &device_data))
+ goto done;
+
+ /* StateFlags */
+ if (!SetupDiGetDevicePropertyW(set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
+ (BYTE *)&lpDisplayDevice->StateFlags, sizeof(lpDisplayDevice->StateFlags), NULL, 0))
+ goto done;
+
+ /* DeviceString */
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DEVICEDESC, NULL,
+ (BYTE *)lpDisplayDevice->DeviceString,
+ sizeof(lpDisplayDevice->DeviceString), NULL))
+ goto done;
+
+ /* DeviceKey */
+ if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
+ {
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
+ sizeof(bufferW), NULL))
+ goto done;
+
+ lstrcpyW(lpDisplayDevice->DeviceKey, nt_classW);
+ lstrcatW(lpDisplayDevice->DeviceKey, bufferW);
+ }
+
+ /* DeviceID */
+ if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
+ {
+ if (dwFlags & EDD_GET_DEVICE_INTERFACE_NAME)
+ {
+ lstrcpyW(lpDisplayDevice->DeviceID, monitor_interface_prefixW);
+ lstrcatW(lpDisplayDevice->DeviceID, instanceW);
+ lstrcatW(lpDisplayDevice->DeviceID, guid_devinterface_monitorW);
+ /* Replace '\\' with '#' after prefix */
+ for (next_charW = lpDisplayDevice->DeviceID + strlenW(monitor_interface_prefixW); *next_charW;
+ next_charW++)
+ {
+ if (*next_charW == '\\')
+ *next_charW = '#';
+ }
+ }
+ else
+ {
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
+ sizeof(bufferW), NULL))
+ goto done;
+
+ lstrcpyW(lpDisplayDevice->DeviceID, bufferW);
+ lstrcatW(lpDisplayDevice->DeviceID, backslashW);
+
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
+ sizeof(bufferW), NULL))
+ goto done;
+
+ lstrcatW(lpDisplayDevice->DeviceID, bufferW);
+ }
+ }
+ }
+
+ ret = TRUE;
+done:
+ SetupDiDestroyDeviceInfoList(set);
+ if (ret)
+ return ret;
+
+ /* Fallback to report at least one adapter and monitor, if user driver didn't initialize display device registry */
if (i)
return FALSE;
+ /* If user driver did initialize the registry, then exit */
+ if (!RegOpenKeyW(HKEY_LOCAL_MACHINE, video_keyW, &hkey))
+ {
+ RegCloseKey(hkey);
+ return FALSE;
+ }
+ WARN("Reporting fallback display devices\n");
+
/* Adapter */
if (!lpDevice)
{
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index e3e1f38d66..26ee28a122 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -115,7 +115,7 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de
ls = RegQueryValueExA(hkey, video_name, NULL, NULL, (unsigned char *)video_value, &size);
ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls);
RegCloseKey(hkey);
- todo_wine ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
+ ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
}
}
else
@@ -208,9 +208,9 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
/* DeviceKey */
lstrcpynA(buffer, device->DeviceKey, sizeof(device_key_prefix));
- todo_wine ok(!lstrcmpiA(buffer, device_key_prefix), "#%d: wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
- todo_wine ok(sscanf(device->DeviceKey + sizeof(device_key_prefix) - 1, "%04d", &number) == 1,
- "#%d wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
+ ok(!lstrcmpiA(buffer, device_key_prefix), "#%d: wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
+ ok(sscanf(device->DeviceKey + sizeof(device_key_prefix) - 1, "%04d", &number) == 1,
+ "#%d wrong DeviceKey : %s\n", monitor_index, device->DeviceKey);
}
static void test_enumdisplaydevices(void)
--
2.20.1
2
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/misc.c | 74 +++++++++++++++++++++++++++++--------
dlls/user32/tests/monitor.c | 18 ++++-----
2 files changed, 68 insertions(+), 24 deletions(-)
diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c
index 1a03d70dde..355457098d 100644
--- a/dlls/user32/misc.c
+++ b/dlls/user32/misc.c
@@ -39,6 +39,33 @@
WINE_DEFAULT_DEBUG_CHANNEL(win);
+static const WCHAR default_adapter_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
+static const WCHAR default_monitor_name[] =
+ {'\\','\\','.','\\',
+ 'D','I','S','P','L','A','Y','1','\\',
+ 'M','o','n','i','t','o','r','0',0};
+static const WCHAR default_adapter_string[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
+static const WCHAR default_monitor_string[] =
+ {'G','e','n','e','r','i','c',' ','N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
+static const WCHAR default_adapter_id[] =
+ {'P','C','I','\\',
+ 'V','E','N','_','0','0','0','0','&',
+ 'D','E','V','_','0','0','0','0','&',
+ 'S','U','B','S','Y','S','_','0','0','0','0','0','0','0','0','&',
+ 'R','E','V','_','0','0',0};
+static const WCHAR default_monitor_id[] =
+ {'M','O','N','I','T','O','R','\\',
+ 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r','\\',
+ '{','4','d','3','6','e','9','6','e','-','e','3','2','5','-','1','1','c','e','-',
+ 'b','f','c','1','-','0','8','0','0','2','b','e','1','0','3','1','8','}',
+ '\\','0','0','0','0',0};
+static const WCHAR default_monitor_interface_id[] =
+ {'\\','\\','\?','\\',
+ 'D','I','S','P','L','A','Y','#','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r','#',
+ '4','&','1','7','f','0','f','f','5','4','&','0','&','U','I','D','0','#',
+ '{','e','6','f','0','7','b','5','f','-','e','e','9','7','-','4','a','9','0','-',
+ 'b','0','7','6','-','3','3','f','5','7','b','f','4','e','a','a','7','}',0};
+
#define IMM_INIT_MAGIC 0x19650412
static HWND (WINAPI *imm_get_ui_window)(HKL);
BOOL (WINAPI *imm_register_window)(HWND) = NULL;
@@ -243,12 +270,6 @@ DWORD WINAPI SetLogonNotifyWindow(HWINSTA hwinsta,HWND hwnd)
return 1;
}
-static const WCHAR primary_device_name[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','1',0};
-static const WCHAR primary_device_string[] = {'X','1','1',' ','W','i','n','d','o','w','i','n','g',' ',
- 'S','y','s','t','e','m',0};
-static const WCHAR primary_device_deviceid[] = {'P','C','I','\\','V','E','N','_','0','0','0','0','&',
- 'D','E','V','_','0','0','0','0',0};
-
/***********************************************************************
* EnumDisplayDevicesA (USER32.@)
*/
@@ -293,16 +314,39 @@ BOOL WINAPI EnumDisplayDevicesW( LPCWSTR lpDevice, DWORD i, LPDISPLAY_DEVICEW lp
if (i)
return FALSE;
- memcpy(lpDisplayDevice->DeviceName, primary_device_name, sizeof(primary_device_name));
- memcpy(lpDisplayDevice->DeviceString, primary_device_string, sizeof(primary_device_string));
-
- lpDisplayDevice->StateFlags =
- DISPLAY_DEVICE_ATTACHED_TO_DESKTOP |
- DISPLAY_DEVICE_PRIMARY_DEVICE |
- DISPLAY_DEVICE_VGA_COMPATIBLE;
+ /* Adapter */
+ if (!lpDevice)
+ {
+ memcpy(lpDisplayDevice->DeviceName, default_adapter_name, sizeof(default_adapter_name));
+ memcpy(lpDisplayDevice->DeviceString, default_adapter_string, sizeof(default_adapter_string));
+ lpDisplayDevice->StateFlags =
+ DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE;
+ if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
+ {
+ if (dwFlags & EDD_GET_DEVICE_INTERFACE_NAME)
+ lpDisplayDevice->DeviceID[0] = 0;
+ else
+ memcpy(lpDisplayDevice->DeviceID, default_adapter_id, sizeof(default_adapter_id));
+ }
+ }
+ /* Monitor */
+ else
+ {
+ if (lstrcmpiW(default_adapter_name, lpDevice))
+ return FALSE;
+
+ memcpy(lpDisplayDevice->DeviceName, default_monitor_name, sizeof(default_monitor_name));
+ memcpy(lpDisplayDevice->DeviceString, default_monitor_string, sizeof(default_monitor_string));
+ lpDisplayDevice->StateFlags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
+ if (lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
+ {
+ if (dwFlags & EDD_GET_DEVICE_INTERFACE_NAME)
+ memcpy(lpDisplayDevice->DeviceID, default_monitor_interface_id, sizeof(default_monitor_interface_id));
+ else
+ memcpy(lpDisplayDevice->DeviceID, default_monitor_id, sizeof(default_monitor_id));
+ }
+ }
- if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(lpDisplayDevice->DeviceID))
- memcpy(lpDisplayDevice->DeviceID, primary_device_deviceid, sizeof(primary_device_deviceid));
if(lpDisplayDevice->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(lpDisplayDevice->DeviceKey))
lpDisplayDevice->DeviceKey[0] = 0;
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index bee1085a14..e3e1f38d66 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -146,13 +146,13 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de
* by changing the data and rerun EnumDisplayDevices. But it's difficult to find corresponding PCI device on
* userland. So here we check the expected format instead. */
if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
- todo_wine ok(strlen(device->DeviceID) == 0 || /* vista+ */
+ ok(strlen(device->DeviceID) == 0 || /* vista+ */
sscanf(device->DeviceID, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
&vendor_id, &device_id, &subsys_id, &revision_id) == 4, /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */
"#%d: got %s\n", index, device->DeviceID);
else
{
- todo_wine ok(broken(strlen(device->DeviceID) == 0) || /* XP on Testbot returns an empty string, whereas real machine doesn't */
+ ok(broken(strlen(device->DeviceID) == 0) || /* XP on Testbot returns an empty string, whereas real machine doesn't */
sscanf(device->DeviceID, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X", &vendor_id, &device_id, &subsys_id,
&revision_id) == 4, "#%d: wrong DeviceID %s\n", index, device->DeviceID);
}
@@ -173,14 +173,14 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
/* DeviceName */
lstrcpyA(monitor_name, adapter_name);
sprintf(monitor_name + strlen(monitor_name), "\\Monitor%d", monitor_index);
- todo_wine ok(!strcmp(monitor_name, device->DeviceName), "#%d: expect %s, got %s\n", monitor_index, monitor_name, device->DeviceName);
+ ok(!strcmp(monitor_name, device->DeviceName), "#%d: expect %s, got %s\n", monitor_index, monitor_name, device->DeviceName);
/* DeviceString */
ok(strlen(device->DeviceString) > 0, "#%d: expect DeviceString not empty\n", monitor_index);
/* StateFlags */
if (adapter_index == 0 && monitor_index == 0)
- todo_wine ok(device->StateFlags & DISPLAY_DEVICE_ATTACHED, "#%d expect to have a primary monitor attached\n", monitor_index);
+ ok(device->StateFlags & DISPLAY_DEVICE_ATTACHED, "#%d expect to have a primary monitor attached\n", monitor_index);
else
ok(device->StateFlags <= (DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE), "#%d wrong state %#x\n", monitor_index,
device->StateFlags);
@@ -191,7 +191,7 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
{ /* HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\4&2abfaa30&0&UID0 GUID_DEVINTERFACE_MONITOR
* ^ ^ ^
* Expect format \\?\DISPLAY#Default_Monitor#4&2abfaa30&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} */
- todo_wine ok(strlen(device->DeviceID) == 0 || /* vista ~ win7 */
+ ok(strlen(device->DeviceID) == 0 || /* vista ~ win7 */
sscanf(device->DeviceID, "\\\\?\\DISPLAY#Default_Monitor#%[^#]#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}", buffer) == 1 || /* win8+ */
(!lstrcmpiA(buffer, device_id_prefix) &&
sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1), /* XP/2003 ignores EDD_GET_DEVICE_INTERFACE_NAME */
@@ -201,9 +201,9 @@ static void test_enumdisplaydevices_monitor(int adapter_index, int monitor_index
{
/* Expect HarewareID value data + Driver value data in HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\Default_Monitor\{Instance} */
/* But we don't know which monitor instance this belongs to, so check format instead */
- todo_wine ok(!lstrcmpiA(buffer, device_id_prefix), "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
- todo_wine ok(sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1,
- "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
+ ok(!lstrcmpiA(buffer, device_id_prefix), "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
+ ok(sscanf(device->DeviceID + sizeof(device_id_prefix) - 1, "%04d", &number) == 1,
+ "#%d wrong DeviceID : %s\n", monitor_index, device->DeviceID);
}
/* DeviceKey */
@@ -235,7 +235,7 @@ static void test_enumdisplaydevices(void)
/* Doesn't accept \\.\DISPLAY */
dd.cb = sizeof(dd);
ret = pEnumDisplayDevicesA("\\\\.\\DISPLAY", 0, &dd, 0);
- todo_wine ok(!ret, "Expect failure\n");
+ ok(!ret, "Expect failure\n");
/* Enumeration */
for (flag_index = 0; flag_index < ARRAY_SIZE(flags); flag_index++)
--
2.20.1
2
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/desktop.c | 1 +
dlls/winex11.drv/display.c | 4 ++--
dlls/winex11.drv/x11drv.h | 2 +-
dlls/winex11.drv/x11drv_main.c | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index d478cbdcb3..a0495c44b1 100644
--- a/dlls/winex11.drv/desktop.c
+++ b/dlls/winex11.drv/desktop.c
@@ -154,6 +154,7 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height )
max_width = primary_rect.right - primary_rect.left;
max_height = primary_rect.bottom - primary_rect.top;
xinerama_init( width, height );
+ X11DRV_DisplayDevices_Init( TRUE );
/* initialize the available resolutions */
dd_modes = X11DRV_Settings_SetHandlers("desktop",
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index a85925d1f1..93eacf6110 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -339,7 +339,7 @@ static void cleanup_devices(void)
SetupDiDestroyDeviceInfoList(devinfo);
}
-void X11DRV_DisplayDevices_Init(void)
+void X11DRV_DisplayDevices_Init(BOOL force)
{
static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
HANDLE mutex;
@@ -366,7 +366,7 @@ void X11DRV_DisplayDevices_Init(void)
}
/* Avoid unnecessary reinit */
- if (disposition != REG_CREATED_NEW_KEY)
+ if (!force && disposition != REG_CREATED_NEW_KEY)
goto done;
TRACE("via %s\n", wine_dbgstr_a(handler.name));
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index f8f28f0e0b..ba473c3fc5 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -736,7 +736,7 @@ struct x11drv_display_device_handler
};
extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;
-extern void X11DRV_DisplayDevices_Init(void) DECLSPEC_HIDDEN;
+extern void X11DRV_DisplayDevices_Init(BOOL force) DECLSPEC_HIDDEN;
/* XIM support */
extern BOOL X11DRV_InitXIM( const char *input_style ) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 69478741f1..21807af3f1 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -597,7 +597,7 @@ static BOOL process_attach(void)
X11DRV_InitKeyboard( gdi_display );
if (use_xim) use_xim = X11DRV_InitXIM( input_style );
- X11DRV_DisplayDevices_Init();
+ X11DRV_DisplayDevices_Init(FALSE);
return TRUE;
}
--
2.20.1
2
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/display.c | 95 +++++++++++++++++++++++++++++++++++--
dlls/winex11.drv/x11drv.h | 18 +++++++
dlls/winex11.drv/xinerama.c | 51 ++++++++++++++++++++
3 files changed, 159 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index 4502c6b2b1..a85925d1f1 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -39,10 +39,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
+/* Wine specific monitor properties */
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
+
static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
static const WCHAR symbolic_link_valueW[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
+static const WCHAR mointor_id_fmtW[] = {'M','o','n','i','t','o','r','I','D','%','d',0};
static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
static const WCHAR guid_fmtW[] = {
'{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
@@ -84,6 +88,13 @@ static const WCHAR nt_classW[] = {
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'C','o','n','t','r','o','l','\\',
'C','l','a','s','s','\\',0};
+static const WCHAR monitor_instance_fmtW[] = {
+ 'D','I','S','P','L','A','Y','\\',
+ 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r','\\',
+ '%','0','4','X','&','%','0','4','X',0};
+static const WCHAR monitor_hardware_idW[] = {
+ 'M','O','N','I','T','O','R','\\',
+ 'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
static struct x11drv_display_device_handler handler;
@@ -169,7 +180,7 @@ done:
return ret;
}
-static BOOL X11DRV_InitAdapter(HKEY video_hkey, INT video_index, INT gpu_index, INT adapter_index,
+static BOOL X11DRV_InitAdapter(HKEY video_hkey, INT video_index, INT gpu_index, INT adapter_index, INT monitor_count,
const struct x11drv_gpu *gpu, const WCHAR *guid_string,
const WCHAR *gpu_driver, const struct x11drv_adapter *adapter)
{
@@ -179,6 +190,7 @@ static BOOL X11DRV_InitAdapter(HKEY video_hkey, INT video_index, INT gpu_index,
HKEY hkey = NULL;
BOOL ret = FALSE;
LSTATUS ls;
+ INT i;
sprintfW(key_nameW, device_video_fmtW, video_index);
lstrcpyW(bufferW, machine_prefixW);
@@ -213,6 +225,15 @@ static BOOL X11DRV_InitAdapter(HKEY video_hkey, INT video_index, INT gpu_index,
if (RegSetValueExW(hkey, gpu_idW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
+ /* Write all monitor instances paths under this adapter */
+ for (i = 0; i < monitor_count; i++)
+ {
+ sprintfW(key_nameW, mointor_id_fmtW, i);
+ sprintfW(bufferW, monitor_instance_fmtW, video_index, i);
+ if (RegSetValueExW(hkey, key_nameW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
+ goto done;
+ }
+
/* Write StateFlags */
if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags,
sizeof(adapter->state_flags)))
@@ -226,6 +247,43 @@ done:
return ret;
}
+static BOOL X11DRV_InitMonitor(HDEVINFO devinfo, const struct x11drv_monitor *monitor, int monitor_index,
+ int video_index)
+{
+ SP_DEVINFO_DATA device_data = {sizeof(SP_DEVINFO_DATA)};
+ WCHAR bufferW[MAX_PATH];
+ HKEY hkey;
+ BOOL ret = FALSE;
+
+ /* Create GUID_DEVCLASS_MONITOR instance */
+ sprintfW(bufferW, monitor_instance_fmtW, video_index, monitor_index);
+ SetupDiCreateDeviceInfoW(devinfo, bufferW, &GUID_DEVCLASS_MONITOR, monitor->name, NULL, 0, &device_data);
+ if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
+ goto done;
+
+ /* Write HaredwareID registry property */
+ if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID,
+ (const BYTE *)monitor_hardware_idW, sizeof(monitor_hardware_idW)))
+ goto done;
+
+ /* Create driver key */
+ hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+ RegCloseKey(hkey);
+
+ /* FIXME:
+ * Following properties are Wine specific, see comments in X11DRV_InitAdapter for details */
+ /* StateFlags */
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, DEVPROP_TYPE_UINT32,
+ (const BYTE *)&monitor->state_flags, sizeof(monitor->state_flags), 0))
+ goto done;
+
+ ret = TRUE;
+done:
+ if (!ret)
+ ERR("Failed to initialize monitor\n");
+ return ret;
+}
+
static void prepare_devices(HKEY video_hkey)
{
static const BOOL not_present = FALSE;
@@ -233,6 +291,15 @@ static void prepare_devices(HKEY video_hkey)
HDEVINFO devinfo;
DWORD i = 0;
+ /* Remove all monitors */
+ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, NULL, NULL, 0);
+ while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+ {
+ if (!SetupDiRemoveDevice(devinfo, &device_data))
+ ERR("Failed to remove monitor\n");
+ }
+ SetupDiDestroyDeviceInfoList(devinfo);
+
/* Clean up old adapter keys for reinitialization */
RegDeleteTreeW(video_hkey, NULL);
@@ -241,6 +308,7 @@ static void prepare_devices(HKEY video_hkey)
* case application use SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
* of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
* the same GUID for the same GPU. */
+ i = 0;
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
{
@@ -277,9 +345,10 @@ void X11DRV_DisplayDevices_Init(void)
HANDLE mutex;
struct x11drv_gpu *gpus = NULL;
struct x11drv_adapter *adapters = NULL;
- INT gpu_count, adapter_count;
- INT gpu, adapter;
- HDEVINFO gpu_devinfo = NULL;
+ struct x11drv_monitor *monitors = NULL;
+ INT gpu_count, adapter_count, monitor_count;
+ INT gpu, adapter, monitor;
+ HDEVINFO gpu_devinfo = NULL, monitor_devinfo = NULL;
HKEY video_hkey = NULL;
INT video_index = 0;
DWORD disposition = 0;
@@ -305,6 +374,7 @@ void X11DRV_DisplayDevices_Init(void)
prepare_devices(video_hkey);
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+ monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
/* Initialize GPUs */
if (!handler.pGetGpus(&gpus, &gpu_count))
@@ -321,10 +391,22 @@ void X11DRV_DisplayDevices_Init(void)
for (adapter = 0; adapter < adapter_count; adapter++)
{
- if (!X11DRV_InitAdapter(video_hkey, video_index, gpu, adapter,
+ if (!handler.pGetMonitors(adapters[adapter].id, &monitors, &monitor_count))
+ goto done;
+
+ if (!X11DRV_InitAdapter(video_hkey, video_index, gpu, adapter, monitor_count,
&gpus[gpu], guidW, driverW, &adapters[adapter]))
goto done;
+ /* Initialize monitors */
+ for (monitor = 0; monitor < monitor_count; monitor++)
+ {
+ if (!X11DRV_InitMonitor(monitor_devinfo, &monitors[monitor], monitor, video_index))
+ goto done;
+ }
+
+ handler.pFreeMonitors(monitors);
+ monitors = NULL;
video_index++;
}
@@ -334,6 +416,7 @@ void X11DRV_DisplayDevices_Init(void)
done:
cleanup_devices();
+ SetupDiDestroyDeviceInfoList(monitor_devinfo);
SetupDiDestroyDeviceInfoList(gpu_devinfo);
RegCloseKey(video_hkey);
ReleaseMutex(mutex);
@@ -342,4 +425,6 @@ done:
handler.pFreeGpus(gpus);
if (adapters)
handler.pFreeAdapters(adapters);
+ if (monitors)
+ handler.pFreeMonitors(monitors);
}
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 5d99d69eff..f8f28f0e0b 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -690,6 +690,15 @@ struct x11drv_adapter
DWORD state_flags;
};
+/* Represent a monitor in EnumDisplayDevices context */
+struct x11drv_monitor
+{
+ /* Name */
+ WCHAR name[128];
+ /* StateFlags in DISPLAY_DEVICE struct */
+ DWORD state_flags;
+};
+
/* Required functions for display device registry initialization */
struct x11drv_display_device_handler
{
@@ -710,11 +719,20 @@ struct x11drv_display_device_handler
* Return FALSE on failure with parameters unchanged */
BOOL (*pGetAdapters)(ULONG_PTR gpu_id, struct x11drv_adapter **adapters, int *count);
+ /* pGetMonitors will be called to get a list of monitors in EnumDisplayDevices context under an adapter.
+ * The first monitor has to be primary if adapter is primary.
+ *
+ * Return FALSE on failure with parameters unchanged */
+ BOOL (*pGetMonitors)(ULONG_PTR adapter_id, struct x11drv_monitor **monitors, int *count);
+
/* pFreeGpus will be called to free a GPU list from pGetGpus */
void (*pFreeGpus)(struct x11drv_gpu *gpus);
/* pFreeAdapters will be called to free an adapter list from pGetAdapters */
void (*pFreeAdapters)(struct x11drv_adapter *adapters);
+
+ /* pFreeMonitors will be called to free a monitor list from pGetMonitors */
+ void (*pFreeMonitors)(struct x11drv_monitor *monitors);
};
extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c
index 8b0ee51f7e..fde2e189f6 100644
--- a/dlls/winex11.drv/xinerama.c
+++ b/dlls/winex11.drv/xinerama.c
@@ -291,6 +291,55 @@ static void xinerama_free_adapters( struct x11drv_adapter *adapters )
heap_free( adapters );
}
+static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor **new_monitors, int *count )
+{
+ static const WCHAR generic_nonpnp_monitorW[] = {
+ 'G','e','n','e','r','i','c',' ',
+ 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0};
+ struct x11drv_monitor *monitor;
+ INT first = (INT)adapter_id;
+ INT monitor_count = 0;
+ INT index = 0;
+ INT i;
+
+ for (i = first; i < nb_monitors; i++)
+ {
+ if (i == first
+ || (EqualRect( &monitors[i].rcMonitor, &monitors[first].rcMonitor )
+ && !IsRectEmpty( &monitors[first].rcMonitor )))
+ monitor_count++;
+ }
+
+ monitor = heap_calloc( monitor_count, sizeof(*monitor) );
+ if (!monitor)
+ return FALSE;
+
+ for (i = first; i < nb_monitors; i++)
+ {
+ if (i == first
+ || (EqualRect( &monitors[i].rcMonitor, &monitors[first].rcMonitor )
+ && !IsRectEmpty( &monitors[first].rcMonitor )))
+ {
+ lstrcpyW( monitor[index].name, generic_nonpnp_monitorW );
+ /* Xinerama only reports monitors already attached */
+ monitor[index].state_flags = DISPLAY_DEVICE_ATTACHED;
+ if (!IsRectEmpty( &monitors[i].rcMonitor ))
+ monitor[index].state_flags |= DISPLAY_DEVICE_ACTIVE;
+
+ index++;
+ }
+ }
+
+ *new_monitors = monitor;
+ *count = monitor_count;
+ return TRUE;
+}
+
+static void xinerama_free_monitors( struct x11drv_monitor *monitors )
+{
+ heap_free( monitors );
+}
+
void xinerama_init( unsigned int width, unsigned int height )
{
struct x11drv_display_device_handler handler;
@@ -331,8 +380,10 @@ void xinerama_init( unsigned int width, unsigned int height )
handler.priority = 100;
handler.pGetGpus = xinerama_get_gpus;
handler.pGetAdapters = xinerama_get_adapters;
+ handler.pGetMonitors = xinerama_get_monitors;
handler.pFreeGpus = xinerama_free_gpus;
handler.pFreeAdapters = xinerama_free_adapters;
+ handler.pFreeMonitors = xinerama_free_monitors;
X11DRV_DisplayDevices_SetHandler( &handler );
TRACE( "virtual size: %s primary: %s\n",
--
2.20.1
2
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/tests/monitor.c | 4 +-
dlls/winex11.drv/display.c | 128 ++++++++++++++++++++++++++++++++++--
dlls/winex11.drv/x11drv.h | 18 +++++
dlls/winex11.drv/xinerama.c | 69 +++++++++++++++++++
4 files changed, 210 insertions(+), 9 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 0a097cc85c..bee1085a14 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -113,9 +113,9 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de
memset(video_value, 0, sizeof(video_value));
size = sizeof(video_value);
ls = RegQueryValueExA(hkey, video_name, NULL, NULL, (unsigned char *)video_value, &size);
- todo_wine ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls);
+ ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls);
RegCloseKey(hkey);
- ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
+ todo_wine ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
}
}
else
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index 6ff5828b3a..4502c6b2b1 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -41,6 +41,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
+static const WCHAR symbolic_link_valueW[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
+static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
+static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
static const WCHAR guid_fmtW[] = {
'{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
'%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
@@ -61,6 +64,26 @@ static const WCHAR video_keyW[] = {
'H','A','R','D','W','A','R','E','\\',
'D','E','V','I','C','E','M','A','P','\\',
'V','I','D','E','O',0};
+static const WCHAR adapter_key_fmtW[] = {
+ 'S','y','s','t','e','m','\\',
+ 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+ 'C','o','n','t','r','o','l','\\',
+ 'V','i','d','e','o','\\',
+ '%','s','\\',
+ '%','0','4','x',0};
+static const WCHAR device_video_fmtW[] = {
+ '\\','D','e','v','i','c','e','\\',
+ 'V','i','d','e','o','%','d',0};
+static const WCHAR machine_prefixW[] = {
+ '\\','R','e','g','i','s','t','r','y','\\',
+ 'M','a','c','h','i','n','e','\\',0};
+static const WCHAR nt_classW[] = {
+ '\\','R','e','g','i','s','t','r','y','\\',
+ 'M','a','c','h','i','n','e','\\',
+ 'S','y','s','t','e','m','\\',
+ 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+ 'C','o','n','t','r','o','l','\\',
+ 'C','l','a','s','s','\\',0};
static struct x11drv_display_device_handler handler;
@@ -73,8 +96,9 @@ void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler
}
}
-/* Initialize a GPU instance */
-static BOOL X11DRV_InitGpu(HDEVINFO devinfo, const struct x11drv_gpu *gpu, INT gpu_index)
+/* Initialize a GPU instance and return its GUID string in guid_string and driver value in driver parameter */
+static BOOL X11DRV_InitGpu(HDEVINFO devinfo, const struct x11drv_gpu *gpu, INT gpu_index, WCHAR *guid_string,
+ WCHAR *driver)
{
static const BOOL present = TRUE;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
@@ -116,6 +140,13 @@ static BOOL X11DRV_InitGpu(HDEVINFO devinfo, const struct x11drv_gpu *gpu, INT g
goto done;
RegCloseKey(hkey);
+ /* Retrieve driver value for adapters */
+ if (!SetupDiGetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW, sizeof(bufferW),
+ NULL))
+ goto done;
+ lstrcpyW(driver, nt_classW);
+ lstrcatW(driver, bufferW);
+
/* Write GUID in VideoID in .../instance/Device Parameters, reuse the GUID if it's existent */
hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL);
@@ -128,6 +159,7 @@ static BOOL X11DRV_InitGpu(HDEVINFO devinfo, const struct x11drv_gpu *gpu, INT g
if (RegSetValueExW(hkey, video_idW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
}
+ lstrcpyW(guid_string, bufferW);
ret = TRUE;
done:
@@ -137,13 +169,73 @@ done:
return ret;
}
-static void prepare_devices(void)
+static BOOL X11DRV_InitAdapter(HKEY video_hkey, INT video_index, INT gpu_index, INT adapter_index,
+ const struct x11drv_gpu *gpu, const WCHAR *guid_string,
+ const WCHAR *gpu_driver, const struct x11drv_adapter *adapter)
+{
+ WCHAR adapter_keyW[MAX_PATH];
+ WCHAR key_nameW[MAX_PATH];
+ WCHAR bufferW[1024];
+ HKEY hkey = NULL;
+ BOOL ret = FALSE;
+ LSTATUS ls;
+
+ sprintfW(key_nameW, device_video_fmtW, video_index);
+ lstrcpyW(bufferW, machine_prefixW);
+ sprintfW(adapter_keyW, adapter_key_fmtW, guid_string, adapter_index);
+ lstrcatW(bufferW, adapter_keyW);
+
+ /* Write value of \Device\Video? (adapter key) in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
+ if (RegSetValueExW(video_hkey, key_nameW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
+ goto done;
+
+ /* Create HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} link to GPU driver */
+ ls = RegCreateKeyExW(HKEY_LOCAL_MACHINE, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
+ KEY_ALL_ACCESS, NULL, &hkey, NULL);
+ if (ls == ERROR_ALREADY_EXISTS)
+ RegCreateKeyExW(HKEY_LOCAL_MACHINE, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_OPEN_LINK,
+ KEY_ALL_ACCESS, NULL, &hkey, NULL);
+ if (RegSetValueExW(hkey, symbolic_link_valueW, 0, REG_LINK, (const BYTE *)gpu_driver,
+ strlenW(gpu_driver) * sizeof(WCHAR)))
+ goto done;
+ RegCloseKey(hkey);
+ hkey = NULL;
+
+ /* FIXME:
+ * Following information are Wine specific, they don't really exist on Windows. They are used so that we can
+ * implement EnumDisplayDevices etc by querying registry only. These information are most likely reported by the
+ * device driver on Windows */
+ RegCreateKeyExW(HKEY_CURRENT_CONFIG, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
+
+ /* Write GPU instance path so that we can find the GPU instance via adapters quickly. Another way is trying to match
+ * them via the GUID in Device Paramters/VideoID, but it would required enumrating all GPU instances */
+ sprintfW(bufferW, gpu_instance_fmtW, gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index);
+ if (RegSetValueExW(hkey, gpu_idW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
+ goto done;
+
+ /* Write StateFlags */
+ if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags,
+ sizeof(adapter->state_flags)))
+ goto done;
+
+ ret = TRUE;
+done:
+ RegCloseKey(hkey);
+ if (!ret)
+ ERR("Failed to initialize adapter\n");
+ return ret;
+}
+
+static void prepare_devices(HKEY video_hkey)
{
static const BOOL not_present = FALSE;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HDEVINFO devinfo;
DWORD i = 0;
+ /* Clean up old adapter keys for reinitialization */
+ RegDeleteTreeW(video_hkey, NULL);
+
/* FIXME:
* Currently SetupDiGetClassDevsW with DIGCF_PRESENT is unsupported, So we need to clean up not present devices in
* case application use SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
@@ -184,11 +276,15 @@ void X11DRV_DisplayDevices_Init(void)
static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
HANDLE mutex;
struct x11drv_gpu *gpus = NULL;
- INT gpu_count;
- INT gpu;
+ struct x11drv_adapter *adapters = NULL;
+ INT gpu_count, adapter_count;
+ INT gpu, adapter;
HDEVINFO gpu_devinfo = NULL;
HKEY video_hkey = NULL;
+ INT video_index = 0;
DWORD disposition = 0;
+ WCHAR guidW[40];
+ WCHAR driverW[1024];
mutex = CreateMutexW(NULL, FALSE, init_mutexW);
WaitForSingleObject(mutex, INFINITE);
@@ -206,7 +302,7 @@ void X11DRV_DisplayDevices_Init(void)
TRACE("via %s\n", wine_dbgstr_a(handler.name));
- prepare_devices();
+ prepare_devices(video_hkey);
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
@@ -216,8 +312,24 @@ void X11DRV_DisplayDevices_Init(void)
for (gpu = 0; gpu < gpu_count; gpu++)
{
- if (!X11DRV_InitGpu(gpu_devinfo, &gpus[gpu], gpu))
+ if (!X11DRV_InitGpu(gpu_devinfo, &gpus[gpu], gpu, guidW, driverW))
+ goto done;
+
+ /* Initialize adapters */
+ if (!handler.pGetAdapters(gpus[gpu].id, &adapters, &adapter_count))
goto done;
+
+ for (adapter = 0; adapter < adapter_count; adapter++)
+ {
+ if (!X11DRV_InitAdapter(video_hkey, video_index, gpu, adapter,
+ &gpus[gpu], guidW, driverW, &adapters[adapter]))
+ goto done;
+
+ video_index++;
+ }
+
+ handler.pFreeAdapters(adapters);
+ adapters = NULL;
}
done:
@@ -228,4 +340,6 @@ done:
CloseHandle(mutex);
if (gpus)
handler.pFreeGpus(gpus);
+ if (adapters)
+ handler.pFreeAdapters(adapters);
}
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index e50158d282..5d99d69eff 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -681,6 +681,15 @@ struct x11drv_gpu
UINT revision_id;
};
+/* Represent an adapter in EnumDisplayDevices context */
+struct x11drv_adapter
+{
+ /* ID to uniquely identify an adapter in handler */
+ ULONG_PTR id;
+ /* as StateFlags in DISPLAY_DEVICE struct */
+ DWORD state_flags;
+};
+
/* Required functions for display device registry initialization */
struct x11drv_display_device_handler
{
@@ -695,8 +704,17 @@ struct x11drv_display_device_handler
* Return FALSE on failure with parameters unchanged */
BOOL (*pGetGpus)(struct x11drv_gpu **gpus, int *count);
+ /* pGetAdapters will be called to get a list of adapters in EnumDisplayDevices context under a GPU.
+ * The first adapter has to be primary if GPU is primary.
+ *
+ * Return FALSE on failure with parameters unchanged */
+ BOOL (*pGetAdapters)(ULONG_PTR gpu_id, struct x11drv_adapter **adapters, int *count);
+
/* pFreeGpus will be called to free a GPU list from pGetGpus */
void (*pFreeGpus)(struct x11drv_gpu *gpus);
+
+ /* pFreeAdapters will be called to free an adapter list from pGetAdapters */
+ void (*pFreeAdapters)(struct x11drv_adapter *adapters);
};
extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c
index 900cfd91db..8b0ee51f7e 100644
--- a/dlls/winex11.drv/xinerama.c
+++ b/dlls/winex11.drv/xinerama.c
@@ -224,6 +224,73 @@ static void xinerama_free_gpus( struct x11drv_gpu *gpus )
heap_free( gpus );
}
+static BOOL xinerama_get_adapters( ULONG_PTR gpu_id, struct x11drv_adapter **new_adapters, int *count )
+{
+ struct x11drv_adapter *adapters = NULL;
+ INT index = 0;
+ INT i, j;
+ INT primary_index;
+ BOOL mirrored;
+
+ if (gpu_id)
+ return FALSE;
+
+ /* Being lazy, actual adapter count maybe less */
+ adapters = heap_calloc( nb_monitors, sizeof(*adapters) );
+ if (!adapters)
+ return FALSE;
+
+ primary_index = primary_monitor;
+ if (primary_index >= nb_monitors)
+ primary_index = 0;
+
+ for (i = 0; i < nb_monitors; i++)
+ {
+ mirrored = FALSE;
+ for (j = 0; j < i; j++)
+ {
+ if (EqualRect( &monitors[i].rcMonitor, &monitors[j].rcMonitor) && !IsRectEmpty( &monitors[j].rcMonitor ))
+ {
+ mirrored = TRUE;
+ break;
+ }
+ }
+
+ /* Mirrored monitors share the same adapter */
+ if (mirrored)
+ continue;
+
+ /* Use monitor index as id */
+ adapters[index].id = (ULONG_PTR)i;
+
+ if (i == primary_index)
+ adapters[index].state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
+
+ if (!IsRectEmpty( &monitors[i].rcMonitor ))
+ adapters[index].state_flags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
+
+ index++;
+ }
+
+ /* Primary adapter has to be first */
+ if (primary_index)
+ {
+ struct x11drv_adapter tmp;
+ tmp = adapters[primary_index];
+ adapters[primary_index] = adapters[0];
+ adapters[0] = tmp;
+ }
+
+ *new_adapters = adapters;
+ *count = index;
+ return TRUE;
+}
+
+static void xinerama_free_adapters( struct x11drv_adapter *adapters )
+{
+ heap_free( adapters );
+}
+
void xinerama_init( unsigned int width, unsigned int height )
{
struct x11drv_display_device_handler handler;
@@ -263,7 +330,9 @@ void xinerama_init( unsigned int width, unsigned int height )
strcpy( handler.name, "Xinerama" );
handler.priority = 100;
handler.pGetGpus = xinerama_get_gpus;
+ handler.pGetAdapters = xinerama_get_adapters;
handler.pFreeGpus = xinerama_free_gpus;
+ handler.pFreeAdapters = xinerama_free_adapters;
X11DRV_DisplayDevices_SetHandler( &handler );
TRACE( "virtual size: %s primary: %s\n",
--
2.20.1
2
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/Makefile.in | 2 +-
dlls/winex11.drv/display.c | 154 +++++++++++++++++++++++++++++++++++
dlls/winex11.drv/x11drv.h | 22 +++++
dlls/winex11.drv/xinerama.c | 25 ++++++
4 files changed, 202 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
index 9ca2fc6efe..72ab1bb77b 100644
--- a/dlls/winex11.drv/Makefile.in
+++ b/dlls/winex11.drv/Makefile.in
@@ -1,5 +1,5 @@
MODULE = winex11.drv
-IMPORTS = uuid user32 gdi32 advapi32
+IMPORTS = uuid user32 gdi32 advapi32 ntoskrnl setupapi
DELAYIMPORTS = comctl32 ole32 shell32 imm32
EXTRAINCL = $(X_CFLAGS)
EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS)
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index e3e4dce84d..6ff5828b3a 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -26,11 +26,37 @@
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
+#include "initguid.h"
+#include "devguid.h"
+#include "devpkey.h"
+#include "setupapi.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
+#include "ddk/ntddk.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "x11drv.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
+static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
+static const WCHAR guid_fmtW[] = {
+ '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
+ '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
+static const WCHAR gpu_instance_fmtW[] = {
+ 'P','C','I','\\',
+ 'V','E','N','_','%','0','4','X','&',
+ 'D','E','V','_','%','0','4','X','&',
+ 'S','U','B','S','Y','S','_','%','0','8','X','&',
+ 'R','E','V','_','%','0','2','X','\\',
+ '%','0','8','X',0};
+static const WCHAR gpu_hardware_id_fmtW[] = {
+ 'P','C','I','\\',
+ 'V','E','N','_','%','0','4','X','&',
+ 'D','E','V','_','%','0','4','X','&',
+ 'S','U','B','S','Y','S','_','0','0','0','0','0','0','0','0','&',
+ 'R','E','V','_','0','0',0};
static const WCHAR video_keyW[] = {
'H','A','R','D','W','A','R','E','\\',
'D','E','V','I','C','E','M','A','P','\\',
@@ -47,10 +73,120 @@ void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler
}
}
+/* Initialize a GPU instance */
+static BOOL X11DRV_InitGpu(HDEVINFO devinfo, const struct x11drv_gpu *gpu, INT gpu_index)
+{
+ static const BOOL present = TRUE;
+ SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+ WCHAR instanceW[MAX_PATH];
+ WCHAR bufferW[1024];
+ HKEY hkey = NULL;
+ GUID guid;
+ INT written;
+ DWORD size;
+ BOOL ret = FALSE;
+
+ sprintfW(instanceW, gpu_instance_fmtW, gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index);
+ if (!SetupDiOpenDeviceInfoW(devinfo, instanceW, NULL, 0, &device_data))
+ {
+ SetupDiCreateDeviceInfoW(devinfo, instanceW, &GUID_DEVCLASS_DISPLAY, gpu->name, NULL, 0, &device_data);
+ if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
+ goto done;
+ }
+
+ /* Write HaredwareID registry property, REG_MULTI_SZ */
+ written = sprintfW(bufferW, gpu_hardware_id_fmtW, gpu->vendor_id, gpu->device_id);
+ bufferW[written + 1] = 0;
+ if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID, (const BYTE *)bufferW,
+ (written + 2) * sizeof(WCHAR)))
+ goto done;
+
+ /* Write DEVPKEY_Device_IsPresent property */
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
+ (const BYTE *)&present, sizeof(present), 0))
+ goto done;
+
+ /* Open driver key.
+ * This is where HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} links to */
+ hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+
+ /* Write DriverDesc value */
+ if (RegSetValueExW(hkey, driver_descW, 0, REG_SZ, (const BYTE *)gpu->name,
+ (strlenW(gpu->name) + 1) * sizeof(WCHAR)))
+ goto done;
+ RegCloseKey(hkey);
+
+ /* Write GUID in VideoID in .../instance/Device Parameters, reuse the GUID if it's existent */
+ hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL);
+
+ size = sizeof(bufferW);
+ if (RegQueryValueExW(hkey, video_idW, 0, NULL, (BYTE *)bufferW, &size))
+ {
+ ExUuidCreate(&guid);
+ sprintfW(bufferW, guid_fmtW, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
+ guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
+ if (RegSetValueExW(hkey, video_idW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
+ goto done;
+ }
+
+ ret = TRUE;
+done:
+ RegCloseKey(hkey);
+ if (!ret)
+ ERR("Failed to initialize GPU\n");
+ return ret;
+}
+
+static void prepare_devices(void)
+{
+ static const BOOL not_present = FALSE;
+ SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+ HDEVINFO devinfo;
+ DWORD i = 0;
+
+ /* FIXME:
+ * Currently SetupDiGetClassDevsW with DIGCF_PRESENT is unsupported, So we need to clean up not present devices in
+ * case application use SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
+ * of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
+ * the same GUID for the same GPU. */
+ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
+ while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+ {
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
+ (const BYTE *)¬_present, sizeof(not_present), 0))
+ ERR("Failed to set GPU present property\n");
+ }
+ SetupDiDestroyDeviceInfoList(devinfo);
+}
+
+static void cleanup_devices(void)
+{
+ SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+ HDEVINFO devinfo;
+ DWORD type;
+ DWORD i = 0;
+ BOOL present;
+
+ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
+ while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+ {
+ present = FALSE;
+ SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, &type, (BYTE *)&present,
+ sizeof(present), NULL, 0);
+ if (!present && !SetupDiRemoveDevice(devinfo, &device_data))
+ ERR("Failed to remove GPU\n");
+ }
+ SetupDiDestroyDeviceInfoList(devinfo);
+}
+
void X11DRV_DisplayDevices_Init(void)
{
static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
HANDLE mutex;
+ struct x11drv_gpu *gpus = NULL;
+ INT gpu_count;
+ INT gpu;
+ HDEVINFO gpu_devinfo = NULL;
HKEY video_hkey = NULL;
DWORD disposition = 0;
@@ -70,8 +206,26 @@ void X11DRV_DisplayDevices_Init(void)
TRACE("via %s\n", wine_dbgstr_a(handler.name));
+ prepare_devices();
+
+ gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+
+ /* Initialize GPUs */
+ if (!handler.pGetGpus(&gpus, &gpu_count))
+ goto done;
+
+ for (gpu = 0; gpu < gpu_count; gpu++)
+ {
+ if (!X11DRV_InitGpu(gpu_devinfo, &gpus[gpu], gpu))
+ goto done;
+ }
+
done:
+ cleanup_devices();
+ SetupDiDestroyDeviceInfoList(gpu_devinfo);
RegCloseKey(video_hkey);
ReleaseMutex(mutex);
CloseHandle(mutex);
+ if (gpus)
+ handler.pFreeGpus(gpus);
}
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index fbc5a104f6..e50158d282 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -667,6 +667,20 @@ void X11DRV_XRandR_Init(void) DECLSPEC_HIDDEN;
/* X11 display device handler. Used to initialize display device registry data */
+/* Represent a physical GPU in the PCI slots */
+struct x11drv_gpu
+{
+ /* ID to uniquely identify a GPU in handler */
+ ULONG_PTR id;
+ /* Name */
+ WCHAR name[128];
+ /* PCI ID */
+ UINT vendor_id;
+ UINT device_id;
+ UINT subsys_id;
+ UINT revision_id;
+};
+
/* Required functions for display device registry initialization */
struct x11drv_display_device_handler
{
@@ -675,6 +689,14 @@ struct x11drv_display_device_handler
/* Higher priority can override handlers with lower proprity */
INT priority;
+
+ /* pGetGpus will be called to get a list of GPUs. First GPU has to be where the primary adapter is.
+ *
+ * Return FALSE on failure with parameters unchanged */
+ BOOL (*pGetGpus)(struct x11drv_gpu **gpus, int *count);
+
+ /* pFreeGpus will be called to free a GPU list from pGetGpus */
+ void (*pFreeGpus)(struct x11drv_gpu *gpus);
};
extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c
index 35dd36049b..900cfd91db 100644
--- a/dlls/winex11.drv/xinerama.c
+++ b/dlls/winex11.drv/xinerama.c
@@ -201,6 +201,29 @@ RECT get_primary_monitor_rect(void)
return get_primary()->rcMonitor;
}
+static BOOL xinerama_get_gpus( struct x11drv_gpu **new_gpus, int *count )
+{
+ static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
+ struct x11drv_gpu *gpus;
+
+ /* Xinerama has no support for GPU, faking one */
+ gpus = heap_calloc( 1, sizeof(*gpus) );
+ if (!gpus)
+ return FALSE;
+
+ lstrcpyW( gpus[0].name, wine_adapterW );
+
+ *new_gpus = gpus;
+ *count = 1;
+
+ return TRUE;
+}
+
+static void xinerama_free_gpus( struct x11drv_gpu *gpus )
+{
+ heap_free( gpus );
+}
+
void xinerama_init( unsigned int width, unsigned int height )
{
struct x11drv_display_device_handler handler;
@@ -239,6 +262,8 @@ void xinerama_init( unsigned int width, unsigned int height )
strcpy( handler.name, "Xinerama" );
handler.priority = 100;
+ handler.pGetGpus = xinerama_get_gpus;
+ handler.pFreeGpus = xinerama_free_gpus;
X11DRV_DisplayDevices_SetHandler( &handler );
TRACE( "virtual size: %s primary: %s\n",
--
2.20.1
2
1
11 Jun '19
Display device handlers are used to initialize the display device
registry data. Different handlers can be implemented according to
the defined interface, for example, via Xinerama or XRandR.
With those registry data, EnumDisplayDevices, EnumDisplayMonitors
and GetMonitorInfo can be built on top of it.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v2: fix xinerama primary adapter reporting, fix registry data reinit failure.
v3: Rebase
v4: Merge patches. Rebase.
v5: Fix explorer patch triggered user32 test failures.
v6: Restructure patches.
v7: Add mutex to avoid init race. Remove old adapter keys during reinit.
Add fallback monitor data in explorer. Simplify code.
v8: Rename mutex. Prefer lstr* functions. Move fallback to EnumDisplayDevicesW(). Minor cleanup.
v9: Supersede 166265~166271. Fix intermediate test failure. I was testing with a polluted prefix.
dlls/user32/tests/monitor.c | 6 +--
dlls/winex11.drv/Makefile.in | 1 +
dlls/winex11.drv/display.c | 77 ++++++++++++++++++++++++++++++++++
dlls/winex11.drv/x11drv.h | 15 +++++++
dlls/winex11.drv/x11drv_main.c | 1 +
dlls/winex11.drv/xinerama.c | 7 ++++
6 files changed, 104 insertions(+), 3 deletions(-)
create mode 100644 dlls/winex11.drv/display.c
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index c5e6745322..0a097cc85c 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -81,7 +81,7 @@ static int monitor_count = 0;
static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *device, DWORD flags)
{
- char video_name[16];
+ char video_name[32];
char video_value[128];
char buffer[128];
int number;
@@ -107,13 +107,13 @@ static void test_enumdisplaydevices_adapter(int index, const DISPLAY_DEVICEA *de
{
sprintf(video_name, "\\Device\\Video%d", index);
ls = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkey);
- todo_wine ok(!ls, "#%d: failed to open registry, error: %#x\n", index, ls);
+ ok(!ls, "#%d: failed to open registry, error: %#x\n", index, ls);
if (!ls)
{
memset(video_value, 0, sizeof(video_value));
size = sizeof(video_value);
ls = RegQueryValueExA(hkey, video_name, NULL, NULL, (unsigned char *)video_value, &size);
- ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls);
+ todo_wine ok(!ls, "#%d: failed to get registry value, error: %#x\n", index, ls);
RegCloseKey(hkey);
ok(!strcmp(video_value, device->DeviceKey), "#%d: wrong DeviceKey: %s\n", index, device->DeviceKey);
}
diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
index 747f509b44..9ca2fc6efe 100644
--- a/dlls/winex11.drv/Makefile.in
+++ b/dlls/winex11.drv/Makefile.in
@@ -9,6 +9,7 @@ C_SRCS = \
brush.c \
clipboard.c \
desktop.c \
+ display.c \
event.c \
graphics.c \
ime.c \
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
new file mode 100644
index 0000000000..e3e4dce84d
--- /dev/null
+++ b/dlls/winex11.drv/display.c
@@ -0,0 +1,77 @@
+/*
+ * X11DRV display device functions
+ *
+ * Copyright 2019 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "x11drv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
+
+static const WCHAR video_keyW[] = {
+ 'H','A','R','D','W','A','R','E','\\',
+ 'D','E','V','I','C','E','M','A','P','\\',
+ 'V','I','D','E','O',0};
+
+static struct x11drv_display_device_handler handler;
+
+void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *new_handler)
+{
+ if (new_handler->priority > handler.priority)
+ {
+ handler = *new_handler;
+ TRACE("Display device functions are now handled by: %s\n", handler.name);
+ }
+}
+
+void X11DRV_DisplayDevices_Init(void)
+{
+ static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
+ HANDLE mutex;
+ HKEY video_hkey = NULL;
+ DWORD disposition = 0;
+
+ mutex = CreateMutexW(NULL, FALSE, init_mutexW);
+ WaitForSingleObject(mutex, INFINITE);
+
+ if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &video_hkey,
+ &disposition))
+ {
+ ERR("Failed to create video device key\n");
+ goto done;
+ }
+
+ /* Avoid unnecessary reinit */
+ if (disposition != REG_CREATED_NEW_KEY)
+ goto done;
+
+ TRACE("via %s\n", wine_dbgstr_a(handler.name));
+
+done:
+ RegCloseKey(video_hkey);
+ ReleaseMutex(mutex);
+ CloseHandle(mutex);
+}
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index c633102a38..fbc5a104f6 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -665,6 +665,21 @@ struct x11drv_mode_info *X11DRV_Settings_SetHandlers(const char *name,
void X11DRV_XF86VM_Init(void) DECLSPEC_HIDDEN;
void X11DRV_XRandR_Init(void) DECLSPEC_HIDDEN;
+/* X11 display device handler. Used to initialize display device registry data */
+
+/* Required functions for display device registry initialization */
+struct x11drv_display_device_handler
+{
+ /* A name to tell what host driver is used */
+ CHAR name[MAX_PATH];
+
+ /* Higher priority can override handlers with lower proprity */
+ INT priority;
+};
+
+extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;
+extern void X11DRV_DisplayDevices_Init(void) DECLSPEC_HIDDEN;
+
/* XIM support */
extern BOOL X11DRV_InitXIM( const char *input_style ) DECLSPEC_HIDDEN;
extern XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index e67a3c05a9..69478741f1 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -597,6 +597,7 @@ static BOOL process_attach(void)
X11DRV_InitKeyboard( gdi_display );
if (use_xim) use_xim = X11DRV_InitXIM( input_style );
+ X11DRV_DisplayDevices_Init();
return TRUE;
}
diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c
index 739b139736..35dd36049b 100644
--- a/dlls/winex11.drv/xinerama.c
+++ b/dlls/winex11.drv/xinerama.c
@@ -30,6 +30,8 @@
#include "wine/library.h"
#include "x11drv.h"
#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
@@ -201,6 +203,7 @@ RECT get_primary_monitor_rect(void)
void xinerama_init( unsigned int width, unsigned int height )
{
+ struct x11drv_display_device_handler handler;
MONITORINFOEXW *primary;
int i;
RECT rect;
@@ -234,6 +237,10 @@ void xinerama_init( unsigned int width, unsigned int height )
(monitors[i].dwFlags & MONITORINFOF_PRIMARY) ? " (primary)" : "" );
}
+ strcpy( handler.name, "Xinerama" );
+ handler.priority = 100;
+ X11DRV_DisplayDevices_SetHandler( &handler );
+
TRACE( "virtual size: %s primary: %s\n",
wine_dbgstr_rect(&virtual_screen_rect), wine_dbgstr_rect(&primary->rcMonitor) );
}
--
2.20.1
2
1
[PATCH v9 1/2] ntdll/tests: Move NtAllocateVirtualMemory tests that were in kernel32
by Huw Davies 11 Jun '19
by Huw Davies 11 Jun '19
11 Jun '19
From: Rémi Bernon <rbernon(a)codeweavers.com>
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/kernel32/tests/virtual.c | 49 ----------------
dlls/ntdll/tests/Makefile.in | 3 +-
dlls/ntdll/tests/virtual.c | 107 ++++++++++++++++++++++++++++++++++
3 files changed, 109 insertions(+), 50 deletions(-)
create mode 100644 dlls/ntdll/tests/virtual.c
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index d797df26f6..0b718606d0 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -52,8 +52,6 @@ static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID);
static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *);
-static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
-static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
/* ############################### */
@@ -230,8 +228,6 @@ static void test_VirtualAlloc(void)
void *addr1, *addr2;
DWORD old_prot;
MEMORY_BASIC_INFORMATION info;
- NTSTATUS status;
- SIZE_T size;
SetLastError(0xdeadbeef);
addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS);
@@ -440,55 +436,12 @@ static void test_VirtualAlloc(void)
addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
ok(addr2 == addr1, "VirtualAlloc returned %p, expected %p\n", addr2, addr1);
- /* allocation conflicts because of 64k align */
- size = 0x1000;
- addr2 = (char *)addr1 + 0x1000;
- status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size,
- MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
-
- /* it should conflict, even when zero_bits is explicitly set */
- size = 0x1000;
- addr2 = (char *)addr1 + 0x1000;
- status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 12, &size,
- MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- todo_wine
- ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
- if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
-
- /* 21 zero bits never succeeds */
- size = 0x1000;
- addr2 = NULL;
- status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 21, &size,
- MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- todo_wine
- ok(status == STATUS_NO_MEMORY || status == STATUS_INVALID_PARAMETER,
- "NtAllocateVirtualMemory returned %08x\n", status);
- if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
-
- /* 22 zero bits is invalid */
- size = 0x1000;
- addr2 = NULL;
- status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 22, &size,
- MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- ok(status == STATUS_INVALID_PARAMETER_3 || status == STATUS_INVALID_PARAMETER,
- "NtAllocateVirtualMemory returned %08x\n", status);
- if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
-
/* AT_ROUND_TO_PAGE flag is not supported for VirtualAlloc */
SetLastError(0xdeadbeef);
addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
ok(!addr2, "VirtualAlloc unexpectedly succeeded\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
- /* AT_ROUND_TO_PAGE flag is not supported for NtAllocateVirtualMemory */
- size = 0x1000;
- addr2 = (char *)addr1 + 0x1000;
- status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, MEM_RESERVE |
- MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
- ok(status == STATUS_INVALID_PARAMETER_5 || status == STATUS_INVALID_PARAMETER,
- "NtAllocateVirtualMemory returned %08x\n", status);
-
ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
}
@@ -4438,8 +4391,6 @@ START_TEST(virtual)
pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" );
pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" );
pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" );
- pNtAllocateVirtualMemory = (void *)GetProcAddress( hntdll, "NtAllocateVirtualMemory" );
- pNtFreeVirtualMemory = (void *)GetProcAddress( hntdll, "NtFreeVirtualMemory" );
GetSystemInfo(&si);
trace("system page size %#x\n", si.dwPageSize);
diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in
index 5c70f3f01a..ed15c51339 100644
--- a/dlls/ntdll/tests/Makefile.in
+++ b/dlls/ntdll/tests/Makefile.in
@@ -22,4 +22,5 @@ C_SRCS = \
rtlstr.c \
string.c \
threadpool.c \
- time.c
+ time.c \
+ virtual.c
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c
new file mode 100644
index 0000000000..c1b46c959e
--- /dev/null
+++ b/dlls/ntdll/tests/virtual.c
@@ -0,0 +1,107 @@
+/*
+ * Unit test suite for the virtual memory APIs.
+ *
+ * Copyright 2019 Remi 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
+ */
+
+#include <stdio.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+#include "wine/test.h"
+
+static void test_AllocateVirtualMemory(void)
+{
+ void *addr1, *addr2;
+ NTSTATUS status;
+ SIZE_T size;
+
+ /* simple allocation should success */
+ size = 0x1000;
+ addr1 = NULL;
+ status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ ok(status == STATUS_SUCCESS, "NtAllocateVirtualMemory returned %08x\n", status);
+
+ /* allocation conflicts because of 64k align */
+ size = 0x1000;
+ addr2 = (char *)addr1 + 0x1000;
+ status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr2, 0, &size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
+
+ /* it should conflict, even when zero_bits is explicitly set */
+ size = 0x1000;
+ addr2 = (char *)addr1 + 0x1000;
+ status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr2, 12, &size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ todo_wine
+ ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
+ if (status == STATUS_SUCCESS)
+ {
+ size = 0;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_RELEASE);
+ ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory return %08x, addr2: %p\n", status, addr2);
+ }
+
+ /* 21 zero bits never succeeds */
+ size = 0x1000;
+ addr2 = NULL;
+ status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr2, 21, &size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ todo_wine
+ ok(status == STATUS_NO_MEMORY || status == STATUS_INVALID_PARAMETER,
+ "NtAllocateVirtualMemory returned %08x\n", status);
+ if (status == STATUS_SUCCESS)
+ {
+ size = 0;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), &addr2, &size, MEM_RELEASE);
+ ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory return %08x, addr2: %p\n", status, addr2);
+ }
+
+ /* 22 zero bits is invalid */
+ size = 0x1000;
+ addr2 = NULL;
+ status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr2, 22, &size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ ok(status == STATUS_INVALID_PARAMETER_3 || status == STATUS_INVALID_PARAMETER,
+ "NtAllocateVirtualMemory returned %08x\n", status);
+
+ /* AT_ROUND_TO_PAGE flag is not supported for NtAllocateVirtualMemory */
+ size = 0x1000;
+ addr2 = (char *)addr1 + 0x1000;
+ status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr2, 0, &size,
+ MEM_RESERVE | MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
+ ok(status == STATUS_INVALID_PARAMETER_5 || status == STATUS_INVALID_PARAMETER,
+ "NtAllocateVirtualMemory returned %08x\n", status);
+
+ size = 0;
+ status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE);
+ ok(status == STATUS_SUCCESS, "NtFreeVirtualMemory failed\n");
+}
+
+START_TEST(virtual)
+{
+ SYSTEM_BASIC_INFORMATION sbi;
+
+ NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL);
+ trace("system page size %#x\n", sbi.PageSize);
+
+ test_AllocateVirtualMemory();
+}
--
2.17.1
2
1