Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 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
May 2019
- 96 participants
- 789 discussions
[PATCH 1/2] urlmon/tests: Add a test for ProtocolCF_CreateInstance not supporting aggregation.
by Jacek Caban 22 May '19
by Jacek Caban 22 May '19
22 May '19
From: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/urlmon/tests/protocol.c | 156 ++++++++++++++++++++++++++++-------
1 file changed, 128 insertions(+), 28 deletions(-)
2
1
[PATCH 2/2] urlmon: If ProtocolCF_CreateInstance doesn't support aggregation retry without it.
by Jacek Caban 22 May '19
by Jacek Caban 22 May '19
22 May '19
From: Dmitry Timoshkov <dmitry(a)baikal.ru>
This patch fixes regression caused by
097811f2513e457ebf4afb1d2d21ab90b8684325.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47190
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/urlmon/bindprot.c | 23 +++++++++++++++--------
dlls/urlmon/tests/protocol.c | 3 ---
2 files changed, 15 insertions(+), 11 deletions(-)
1
0
Signed-off-by: Andrew Eikum <aeikum(a)codeweavers.com>
---
v2: Add check for fma functions; add tests; add errno assigning.
configure.ac | 2 +
.../api-ms-win-crt-math-l1-1-0.spec | 4 +-
dlls/msvcr120/msvcr120.spec | 4 +-
dlls/msvcr120_app/msvcr120_app.spec | 4 +-
dlls/msvcrt/math.c | 32 ++++++++++
dlls/msvcrt/msvcrt.spec | 2 +
dlls/ucrtbase/tests/misc.c | 60 +++++++++++++++++++
dlls/ucrtbase/ucrtbase.spec | 4 +-
8 files changed, 104 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index 0490b53410a..83a8181f33c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2634,6 +2634,8 @@ AC_CHECK_FUNCS(\
exp2f \
expm1 \
expm1f \
+ fma \
+ fmaf \
ilogb \
ilogbf \
j0 \
diff --git a/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec b/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec
index 75ecaf1effc..3a5991f1246 100644
--- a/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec
+++ b/dlls/api-ms-win-crt-math-l1-1-0/api-ms-win-crt-math-l1-1-0.spec
@@ -241,8 +241,8 @@
@ stub fdiml
@ cdecl floor(double) ucrtbase.floor
@ cdecl -arch=arm,x86_64,arm64 floorf(float) ucrtbase.floorf
-@ stub fma
-@ stub fmaf
+@ cdecl fma(double double double) ucrtbase.fma
+@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) ucrtbase.fmaf
@ stub fmal
@ cdecl fmax(double double) ucrtbase.fmax
@ cdecl fmaxf(float float) ucrtbase.fmaxf
diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec
index 92ac3246e10..63dc44d32b3 100644
--- a/dlls/msvcr120/msvcr120.spec
+++ b/dlls/msvcr120/msvcr120.spec
@@ -2164,8 +2164,8 @@
@ cdecl fgetws(ptr long ptr) MSVCRT_fgetws
@ cdecl floor(double) MSVCRT_floor
@ cdecl -arch=arm,x86_64,arm64 floorf(float) MSVCRT_floorf
-@ stub fma
-@ stub fmaf
+@ cdecl fma(double double double) MSVCRT_fma
+@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) MSVCRT_fmaf
@ stub fmal
@ cdecl fmax(double double) MSVCR120_fmax
@ cdecl fmaxf(float float) MSVCR120_fmaxf
diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec
index af6b0fe369d..9b7727e233d 100644
--- a/dlls/msvcr120_app/msvcr120_app.spec
+++ b/dlls/msvcr120_app/msvcr120_app.spec
@@ -1830,8 +1830,8 @@
@ cdecl fgetws(ptr long ptr) msvcr120.fgetws
@ cdecl floor(double) msvcr120.floor
@ cdecl -arch=arm,x86_64,arm64 floorf(float) msvcr120.floorf
-@ stub fma
-@ stub fmaf
+@ cdecl fma(double double double) msvcr120.fma
+@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) msvcr120.fmaf
@ stub fmal
@ cdecl fmax(double double) msvcr120.fmax
@ cdecl fmaxf(float float) msvcr120.fmaxf
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index 049c3407321..63744e33e33 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -387,6 +387,22 @@ float CDECL MSVCRT_floorf( float x )
return floorf(x);
}
+/*********************************************************************
+ * fmaf (MSVCRT.@)
+ */
+float CDECL MSVCRT_fmaf( float x, float y, float z )
+{
+#ifdef HAVE_FMAF
+ float w = fmaf(x, y, z);
+#else
+ float w = x * y + z;
+#endif
+ if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *MSVCRT__errno() = MSVCRT_EDOM;
+ else if (isinf(x) && isinf(z) && x != z) *MSVCRT__errno() = MSVCRT_EDOM;
+ else if (isinf(y) && isinf(z) && y != z) *MSVCRT__errno() = MSVCRT_EDOM;
+ return w;
+}
+
/*********************************************************************
* frexpf (MSVCRT.@)
*/
@@ -863,6 +879,22 @@ double CDECL MSVCRT_floor( double x )
return floor(x);
}
+/*********************************************************************
+ * fma (MSVCRT.@)
+ */
+double CDECL MSVCRT_fma( double x, double y, double z )
+{
+#ifdef HAVE_FMA
+ double w = fma(x, y, z);
+#else
+ double w = x * y + z;
+#endif
+ if ((isinf(x) && y == 0) || (x == 0 && isinf(y))) *MSVCRT__errno() = MSVCRT_EDOM;
+ else if (isinf(x) && isinf(z) && x != z) *MSVCRT__errno() = MSVCRT_EDOM;
+ else if (isinf(y) && isinf(z) && y != z) *MSVCRT__errno() = MSVCRT_EDOM;
+ return w;
+}
+
/*********************************************************************
* fabs (MSVCRT.@)
*/
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index 952de55b49a..f464db2f9cc 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -1288,6 +1288,8 @@
@ cdecl fgetws(ptr long ptr) MSVCRT_fgetws
@ cdecl floor(double) MSVCRT_floor
@ cdecl -arch=arm,x86_64,arm64 floorf(float) MSVCRT_floorf
+@ cdecl fma(double double double) MSVCRT_fma
+@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) MSVCRT_fmaf
@ cdecl fmod(double double) MSVCRT_fmod
@ cdecl -arch=arm,x86_64,arm64 fmodf(float float) MSVCRT_fmodf
@ cdecl fopen(str str) MSVCRT_fopen
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c
index ddb793851ab..7559edecc33 100644
--- a/dlls/ucrtbase/tests/misc.c
+++ b/dlls/ucrtbase/tests/misc.c
@@ -64,6 +64,25 @@ static inline float __port_infinity(void)
}
#define INFINITY __port_infinity()
+static inline float __port_nan(void)
+{
+ static const unsigned __nan_bytes = 0x7fc00000;
+ return *(const float *)&__nan_bytes;
+}
+#define NAN __port_nan()
+
+static inline double __port_min_pos_double(void)
+{
+ static const UINT64 __min_pos_double = 0x10000000000000;
+ return *(const double *)&__min_pos_double;
+}
+
+static inline double __port_max_double(void)
+{
+ static const UINT64 __max_double = 0x7FEFFFFFFFFFFFFF;
+ return *(const double *)&__max_double;
+}
+
#define M_PI_2 1.57079632679489661923
#define FE_TONEAREST 0
@@ -747,6 +766,30 @@ static void test_math_errors(void)
{"pow", INFINITY, 1, -1, -1},
{"pow", INFINITY, 2, -1, -1},
};
+ const struct {
+ char func[16];
+ double a;
+ double b;
+ double c;
+ int error;
+ int exception;
+ } tests3d[] = {
+ /* 0 * inf --> EDOM */
+ {"fma", INFINITY, 0, 0, EDOM, -1},
+ {"fma", 0, INFINITY, 0, EDOM, -1},
+ /* inf - inf -> EDOM */
+ {"fma", INFINITY, 1, -INFINITY, EDOM, -1},
+ {"fma", -INFINITY, 1, INFINITY, EDOM, -1},
+ {"fma", 1, INFINITY, -INFINITY, EDOM, -1},
+ {"fma", 1, -INFINITY, INFINITY, EDOM, -1},
+ /* NaN */
+ {"fma", NAN, 0, 0, -1, -1},
+ {"fma", 0, NAN, 0, -1, -1},
+ {"fma", 0, 0, NAN, -1, -1},
+ /* over/underflow */
+ {"fma", __port_max_double(), __port_max_double(), __port_max_double(), -1, -1},
+ {"fma", __port_min_pos_double(), __port_min_pos_double(), 1, -1, -1},
+ };
const struct {
char func[16];
double a;
@@ -770,6 +813,7 @@ static void test_math_errors(void)
};
double (CDECL *p_funcd)(double);
double (CDECL *p_func2d)(double, double);
+ double (CDECL *p_func3d)(double, double, double);
double (CDECL *p_funcdl)(double, long);
int i;
@@ -808,6 +852,22 @@ static void test_math_errors(void)
"%s(%f, %f) got exception arg2 %f\n", tests2d[i].func, tests2d[i].a, tests2d[i].b, exception.arg2);
}
+ for(i = 0; i < ARRAY_SIZE(tests3d); i++) {
+ p_func3d = (void*)GetProcAddress(module, tests3d[i].func);
+ *p_errno() = -1;
+ exception.type = -1;
+ p_func3d(tests3d[i].a, tests3d[i].b, tests3d[i].c);
+ ok(*p_errno() == tests3d[i].error,
+ "%s(%f, %f, %f) got errno %d\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, *p_errno());
+ ok(exception.type == tests3d[i].exception,
+ "%s(%f, %f, %f) got exception type %d\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.type);
+ if(exception.type == -1) continue;
+ ok(exception.arg1 == tests3d[i].a,
+ "%s(%f, %f, %f) got exception arg1 %f\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.arg1);
+ ok(exception.arg2 == tests3d[i].b,
+ "%s(%f, %f, %f) got exception arg2 %f\n", tests3d[i].func, tests3d[i].a, tests3d[i].b, tests3d[i].c, exception.arg2);
+ }
+
for(i = 0; i < ARRAY_SIZE(testsdl); i++) {
p_funcdl = (void*)GetProcAddress(module, testsdl[i].func);
*p_errno() = -1;
diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec
index b7f814a4907..c64fee2b260 100644
--- a/dlls/ucrtbase/ucrtbase.spec
+++ b/dlls/ucrtbase/ucrtbase.spec
@@ -2305,8 +2305,8 @@
@ cdecl fgetws(ptr long ptr) MSVCRT_fgetws
@ cdecl floor(double) MSVCRT_floor
@ cdecl -arch=arm,x86_64,arm64 floorf(float) MSVCRT_floorf
-@ stub fma
-@ stub fmaf
+@ cdecl fma(double double double) MSVCRT_fma
+@ cdecl -arch=arm,x86_64,arm64 fmaf(float float float) MSVCRT_fmaf
@ stub fmal
@ cdecl fmax(double double) MSVCR120_fmax
@ cdecl fmaxf(float float) MSVCR120_fmaxf
--
2.21.0
2
1
22 May '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: Supersede 162308~162314, fix xinerama primary adapter reporting, fix registry data reinit failure.
v3: Rebase
v4: Merge patches. Rebase. Supersede 164594~164599, 164612~164613
v5: Fix explorer patch triggered user32 test failures. Supersede 165122~165128.
v6: Restructure patches. Supersede 165134~165140
dlls/winex11.drv/Makefile.in | 1 +
dlls/winex11.drv/display.c | 74 ++++++++++++++++++++++++++++++++++
dlls/winex11.drv/x11drv.h | 15 +++++++
dlls/winex11.drv/x11drv_main.c | 1 +
dlls/winex11.drv/xinerama.c | 7 ++++
5 files changed, 98 insertions(+)
create mode 100644 dlls/winex11.drv/display.c
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..7d81de09ac
--- /dev/null
+++ b/dlls/winex11.drv/display.c
@@ -0,0 +1,74 @@
+/*
+ * 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)
+{
+ HKEY video_hkey = NULL;
+ DWORD disposition = 0;
+ BOOL success = FALSE;
+
+ TRACE("via %s\n", wine_dbgstr_a(handler.name));
+
+ if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &video_hkey,
+ &disposition))
+ goto fail;
+
+ /* Ensure only one thread is initializing the registry and avoid unnecessary reinit */
+ if (disposition != REG_CREATED_NEW_KEY)
+ {
+ success = TRUE;
+ goto fail;
+ }
+
+ success = TRUE;
+fail:
+ RegCloseKey(video_hkey);
+ if (!success)
+ ERR("Failed to initialize display devices\n");
+}
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 3/4] d3d9/tests: Test IDirect3D9::CheckDepthStencilMatch() with D3DFMT_D32.
by Jactry Zeng 22 May '19
by Jactry Zeng 22 May '19
22 May '19
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/d3d9/tests/device.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index f5c89723cb..73ecae9804 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -11833,6 +11833,16 @@ static void test_check_device_format(void)
}
}
+ hr = IDirect3D9_CheckDepthStencilMatch(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
+ D3DFMT_A8R8G8B8, D3DFMT_D32);
+ ok(hr == D3DERR_NOTAVAILABLE || broken(hr == D3DERR_INVALIDCALL), /* Win10 */
+ "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3D9_CheckDepthStencilMatch(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
+ D3DFMT_R5G6B5, D3DFMT_D32);
+ ok(hr == D3DERR_NOTAVAILABLE || broken(hr == D3DERR_INVALIDCALL), /* Win10 */
+ "Got unexpected hr %#x.\n", hr);
+
IDirect3D9_Release(d3d);
}
--
2.20.1
3
2
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/misc.c | 223 ++++++++++++++++++++++++++++++++----
dlls/user32/tests/monitor.c | 26 ++---
2 files changed, 213 insertions(+), 36 deletions(-)
diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c
index 1a03d70dde..92d8a0ea1b 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,42 @@
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);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCWORK, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 4);
+
+static const WCHAR monitor_fmtW[] =
+ {'\\','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 nt_machine_prefixW[] =
+ {'\\','R','e','g','i','s','t','r','y','\\',
+ 'M','a','c','h','i','n','e','\\'};
+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;
@@ -243,11 +283,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.@)
@@ -285,28 +320,170 @@ BOOL WINAPI EnumDisplayDevicesA( LPCSTR lpDevice, DWORD i, LPDISPLAY_DEVICEA lpD
/***********************************************************************
* EnumDisplayDevicesW (USER32.@)
*/
-BOOL WINAPI EnumDisplayDevicesW( LPCWSTR lpDevice, DWORD i, LPDISPLAY_DEVICEW lpDisplayDevice,
- DWORD dwFlags )
+BOOL WINAPI EnumDisplayDevicesW(LPCWSTR name, DWORD index, LPDISPLAY_DEVICEW display_device, DWORD flags)
{
- FIXME("(%s,%d,%p,0x%08x), stub!\n",debugstr_w(lpDevice),i,lpDisplayDevice,dwFlags);
-
- if (i)
- return FALSE;
+ SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+ HDEVINFO set;
+ WCHAR key_nameW[MAX_PATH];
+ WCHAR instanceW[MAX_PATH];
+ WCHAR bufferW[1024];
+ WCHAR *next_charW;
+ DWORD size;
+ DWORD type;
+ long adapter_index;
+ BOOL ret = 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;
+ TRACE("%s %d %p 0x%08x\n", debugstr_w(name), index, display_device, flags);
- 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;
+ /* Find adapter */
+ if (!name)
+ {
+ sprintfW(key_nameW, video_value_fmtW, index);
+ size = sizeof(bufferW);
+ if (RegGetValueW(HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
+ bufferW, &size))
+ return FALSE;
+
+ /* DeviceKey */
+ if(display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(display_device->DeviceKey))
+ strcpyW(display_device->DeviceKey, bufferW);
+
+ /* DeviceName */
+ sprintfW(display_device->DeviceName, adapter_fmtW, index + 1);
+
+ /* Strip \Registry\Machine\ */
+ strcpyW(key_nameW, bufferW + ARRAY_SIZE(nt_machine_prefixW));
+
+ /* DeviceString */
+ size = sizeof(display_device->DeviceString);
+ if (RegGetValueW(HKEY_LOCAL_MACHINE, key_nameW, driver_descW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL,
+ display_device->DeviceString, &size))
+ return FALSE;
+
+ /* StateFlags */
+ size = sizeof(display_device->StateFlags);
+ if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, RRF_RT_REG_DWORD | RRF_ZEROONFAILURE, NULL,
+ &display_device->StateFlags, &size))
+ return FALSE;
+
+ /* DeviceID */
+ if (display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(display_device->DeviceID))
+ {
+ if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
+ display_device->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))
+ {
+ SetupDiDestroyDeviceInfoList(set);
+ return FALSE;
+ }
+ strcpyW(display_device->DeviceID, bufferW);
+ }
+ }
- return TRUE;
+ return TRUE;
+ }
+ /* Find monitor */
+ else
+ {
+ /* Check adapter name */
+ if (strncmpiW(name, displayW, ARRAY_SIZE(displayW)))
+ return FALSE;
+
+ adapter_index = strtolW(name + 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 | RRF_ZEROONFAILURE, NULL, bufferW,
+ &size))
+ return FALSE;
+
+ /* DeviceName */
+ sprintfW(display_device->DeviceName, adapter_fmtW, adapter_index);
+ sprintfW(display_device->DeviceName + strlenW(display_device->DeviceName), monitor_fmtW, index);
+
+ /* Get monitor instance */
+ /* Strip \Registry\Machine\ first */
+ strcpyW(key_nameW, bufferW + ARRAY_SIZE(nt_machine_prefixW));
+ sprintfW(bufferW, mointor_id_value_fmtW, index);
+
+ size = sizeof(instanceW);
+ if (RegGetValueW(HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ | RRF_ZEROONFAILURE,
+ NULL, instanceW, &size))
+ return FALSE;
+
+ set = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
+ if (!SetupDiOpenDeviceInfoW(set, instanceW, NULL, 0, &device_data))
+ goto fail;
+
+ /* StateFlags */
+ if (!SetupDiGetDevicePropertyW(set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
+ (BYTE *)&display_device->StateFlags, sizeof(display_device->StateFlags), NULL, 0))
+ goto fail;
+
+ /* DeviceString */
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DEVICEDESC, NULL,
+ (BYTE *)display_device->DeviceString,
+ sizeof(display_device->DeviceString), NULL))
+ goto fail;
+
+ /* DeviceKey */
+ if (display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(display_device->DeviceKey))
+ {
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
+ sizeof(bufferW), NULL))
+ goto fail;
+
+ strcpyW(display_device->DeviceKey, nt_classW);
+ strcatW(display_device->DeviceKey, bufferW);
+ }
+
+ /* DeviceID */
+ if (display_device->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(display_device->DeviceID))
+ {
+ if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
+ {
+ strcpyW(display_device->DeviceID, monitor_interface_prefixW);
+ strcatW(display_device->DeviceID, instanceW);
+ strcatW(display_device->DeviceID, guid_devinterface_monitorW);
+ /* Replace '\\' with '#' after prefix */
+ for (next_charW = display_device->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 fail;
+
+ strcpyW(display_device->DeviceID, bufferW);
+ strcatW(display_device->DeviceID, backslashW);
+
+ if (!SetupDiGetDeviceRegistryPropertyW(set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
+ sizeof(bufferW), NULL))
+ goto fail;
+
+ strcatW(display_device->DeviceID, bufferW);
+ }
+ }
+
+ ret = TRUE;
+ fail:
+ SetupDiDestroyDeviceInfoList(set);
+ return ret;
+ }
}
/***********************************************************************
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index bee1085a14..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
@@ -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,16 +201,16 @@ 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 */
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)
@@ -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
[PATCH v6 6/7] explorer: Create display device registry fallback data if necessary.
by Zhiyi Zhang 22 May '19
by Zhiyi Zhang 22 May '19
22 May '19
If user driver didn't initialize the display device registry data, create
some fallback data to at least make EnumDisplayDevice report a primary
adapter. Otherwise, report back the primary adapter GUID to store in the
desktop HWND atom, instead of creating a new one.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/user32/desktop.c | 11 +--
dlls/user32/tests/monitor.c | 6 +-
programs/explorer/Makefile.in | 2 +-
programs/explorer/desktop.c | 167 ++++++++++++++++++++++++++++------
4 files changed, 143 insertions(+), 43 deletions(-)
diff --git a/dlls/user32/desktop.c b/dlls/user32/desktop.c
index fe6649446e..3662a68976 100644
--- a/dlls/user32/desktop.c
+++ b/dlls/user32/desktop.c
@@ -101,28 +101,21 @@ LRESULT WINAPI DesktopWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lP
static const WCHAR display_device_guid_propW[] = {
'_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
'd','e','v','i','c','e','_','g','u','i','d',0 };
- static const WCHAR guid_formatW[] = {
- '%','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};
switch (message)
{
case WM_NCCREATE:
{
CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
- const GUID *guid = cs->lpCreateParams;
+ WCHAR *guid = cs->lpCreateParams;
if (guid)
{
ATOM atom;
- WCHAR buffer[37];
if (GetAncestor( hwnd, GA_PARENT )) return FALSE; /* refuse to create non-desktop window */
- sprintfW( buffer, guid_formatW, 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] );
- atom = GlobalAddAtomW( buffer );
+ atom = GlobalAddAtomW( guid );
SetPropW( hwnd, display_device_guid_propW, ULongToHandle( atom ) );
}
return TRUE;
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index c5e6745322..bee1085a14 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,7 +107,7 @@ 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));
@@ -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);
- 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/programs/explorer/Makefile.in b/programs/explorer/Makefile.in
index 374c6aaebe..13b0ed3dfa 100644
--- a/programs/explorer/Makefile.in
+++ b/programs/explorer/Makefile.in
@@ -1,5 +1,5 @@
MODULE = explorer.exe
-IMPORTS = rpcrt4 user32 gdi32 advapi32
+IMPORTS = rpcrt4 user32 gdi32 advapi32 setupapi
DELAYIMPORTS = comctl32 shell32 oleaut32 ole32 shlwapi
EXTRADLLFLAGS = -mwindows -municode -mno-cygwin
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
index d4925f7c5b..48b97cb137 100644
--- a/programs/explorer/desktop.c
+++ b/programs/explorer/desktop.c
@@ -27,6 +27,11 @@
#include <rpc.h>
#include <shlobj.h>
#include <shellapi.h>
+#include <wingdi.h>
+#include <initguid.h>
+#include <devguid.h>
+#include <devpkey.h>
+#include <setupapi.h>
#include "exdisp.h"
#include "wine/debug.h"
@@ -748,24 +753,143 @@ static BOOL get_default_enable_shell( const WCHAR *name )
return result;
}
-static HMODULE load_graphics_driver( const WCHAR *driver, const GUID *guid )
-{
- static const WCHAR device_keyW[] = {
+/* Initialize the display device registry if user driver didn't do it,
+ * and report the primary adapter guid in paramter guid_string. */
+static BOOL initialize_fallback_display_devices( const WCHAR *driver_path, WCHAR *guid_string )
+{
+ 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 device_video0W[] = {
+ '\\','D','e','v','i','c','e','\\',
+ 'V','i','d','e','o','0',0};
+ static const WCHAR device_video_prefixW[] = {
+ '\\','R','e','g','i','s','t','r','y','\\',
+ 'M','a','c','h','i','n','e','\\',0};
+ static const WCHAR gpu_instanceW[] = {
+ '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','0','0','0','0','0','0','0',0};
+ static const WCHAR gpu_hardware_idW[] = {
+ '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,0};
+ static const WCHAR device_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','\\',
- '{','%','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','0','0','0',0};
+ '{','%','s','}','\\',
+ '0','0','0','0',0};
+ static const WCHAR guid_formatW[] = {
+ '%','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 graphics_driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0};
+ static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+ static const WCHAR wine_gpuW[] = {'W','i','n','e',' ','G','P','U',0};
+ static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
+ static const DWORD primary_state_flags = DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
+ HDEVINFO devinfo;
+ SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+ WCHAR adapter_keyW[MAX_PATH];
+ WCHAR bufferW[MAX_PATH];
+ DWORD disposition = 0;
+ DWORD size;
+ GUID guid;
+ HKEY hkey = NULL;
+ BOOL ret = FALSE;
+
+ /* Create HKLM\HARDWARE\DEVICEMAP\VIDEO key if user drivers didn't do it */
+ RegCreateKeyExW( HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition );
+
+ /* User driver did create it. Report back primary adapter guid */
+ if (disposition != REG_CREATED_NEW_KEY)
+ {
+ size = sizeof(bufferW);
+ if (!RegQueryValueExW( hkey, device_video0W, NULL, NULL, (BYTE *)bufferW, &size ))
+ {
+ /* Skip over \Registry\Machine\System\CurrentControlSet\Control\Video\{ to get guid string */
+ memcpy( guid_string, bufferW + 58, 36 * sizeof(WCHAR) );
+ guid_string[36] = 0;
+ RegCloseKey( hkey );
+ return TRUE;
+ }
+ /* Falling through */
+ }
+
+ /* Create basic display device registry data so that functions like EnumDisplayDevice can at least report
+ * a primary adapter */
+ /* Init GPU */
+ devinfo = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL );
+ if (!SetupDiOpenDeviceInfoW( devinfo, gpu_instanceW, NULL, 0, &device_data ))
+ {
+ SetupDiCreateDeviceInfoW( devinfo, gpu_instanceW, &GUID_DEVCLASS_DISPLAY, NULL, NULL, 0, &device_data );
+ if (!SetupDiRegisterDeviceInfo( devinfo, &device_data, 0, NULL, NULL, NULL ))
+ goto fail;
+ }
+
+ /* Write HardwareID */
+ if (!SetupDiSetDeviceRegistryPropertyW( devinfo, &device_data, SPDRP_HARDWAREID, (const BYTE *)(gpu_hardware_idW),
+ sizeof(gpu_hardware_idW) ))
+ goto fail;
+
+ /* Init primary adapter */
+ UuidCreate( &guid );
+ swprintf( guid_string, 37, guid_formatW, 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] );
+ swprintf( adapter_keyW, ARRAY_SIZE(adapter_keyW), device_key_fmtW, guid_string );
+ lstrcpyW( bufferW, device_video_prefixW );
+ lstrcatW( bufferW, adapter_keyW );
+
+ /* Write value of \Device\Video0 in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
+ if (RegSetValueExW( hkey, device_video0W, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) ))
+ goto fail;
+ RegCloseKey( hkey );
+ hkey = NULL;
+
+ /* Write GraphicsDriver */
+ RegCreateKeyExW( HKEY_LOCAL_MACHINE, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL );
+ if (RegSetValueExW( hkey, graphics_driverW, 0, REG_SZ, (const BYTE *)driver_path, (lstrlenW( driver_path ) + 1) * sizeof(WCHAR) ))
+ goto fail;
+
+ /* Write DriverDesc */
+ if (RegSetValueExW( hkey, driver_descW, 0, REG_SZ, (const BYTE *)wine_gpuW, (lstrlenW( wine_gpuW ) + 1) * sizeof(WCHAR) ))
+ goto fail;
+
+ RegCloseKey( hkey );
+ hkey = NULL;
+
+ RegCreateKeyExW( HKEY_CURRENT_CONFIG, adapter_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkey, NULL );
+ /* Write StateFlags */
+ if (RegSetValueExW( hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&primary_state_flags,
+ sizeof(primary_state_flags) ))
+ goto fail;
+
+ ret = TRUE;
+fail:
+ RegCloseKey( hkey );
+ SetupDiDestroyDeviceInfoList( devinfo );
+ if (!ret)
+ ERR("Failed to initialize fallback display device registry data\n");
+ return ret;
+}
+
+/* Load graphics driver, return its module handle in hmodule and report primary adapter guid in guid */
+static void load_graphics_driver( const WCHAR *driver, HMODULE *hmodule, WCHAR *guid )
+{
static const WCHAR driversW[] = {'S','o','f','t','w','a','r','e','\\',
'W','i','n','e','\\','D','r','i','v','e','r','s',0};
static const WCHAR graphicsW[] = {'G','r','a','p','h','i','c','s',0};
static const WCHAR drv_formatW[] = {'w','i','n','e','%','s','.','d','r','v',0};
WCHAR buffer[MAX_PATH], libname[32], *name, *next;
- WCHAR key[ARRAY_SIZE( device_keyW ) + 39];
HMODULE module = 0;
HKEY hkey;
char error[80];
@@ -808,27 +932,12 @@ static HMODULE load_graphics_driver( const WCHAR *driver, const GUID *guid )
}
if (module)
- {
GetModuleFileNameW( module, buffer, MAX_PATH );
- TRACE( "display %s driver %s\n", debugstr_guid(guid), debugstr_w(buffer) );
- }
- swprintf( key, ARRAY_SIZE(key), device_keyW, 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] );
+ initialize_fallback_display_devices( buffer, guid );
+ TRACE( "display %s driver %s\n", debugstr_w(guid), debugstr_w(buffer) );
- if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, key, 0, NULL,
- REG_OPTION_VOLATILE, KEY_SET_VALUE, NULL, &hkey, NULL ))
- {
- if (module)
- RegSetValueExW( hkey, graphics_driverW, 0, REG_SZ,
- (BYTE *)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR) );
- else
- RegSetValueExA( hkey, "DriverError", 0, REG_SZ, (BYTE *)error, strlen(error) + 1 );
- RegCloseKey( hkey );
- }
-
- return module;
+ *hmodule = module;
}
static void initialize_display_settings(void)
@@ -887,7 +996,7 @@ void manage_desktop( WCHAR *arg )
{
static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
HDESK desktop = 0;
- GUID guid;
+ WCHAR guid[37] = {0};
MSG msg;
HWND hwnd;
HMODULE graphics_driver;
@@ -939,13 +1048,11 @@ void manage_desktop( WCHAR *arg )
SetThreadDesktop( desktop );
}
- UuidCreate( &guid );
- TRACE( "display guid %s\n", debugstr_guid(&guid) );
- graphics_driver = load_graphics_driver( driver, &guid );
+ load_graphics_driver( driver, &graphics_driver, guid );
/* create the desktop window */
hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL,
- WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, &guid );
+ WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, guid );
if (hwnd)
{
--
2.20.1
2
1
22 May '19
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/kernelbase/kernelbase.spec | 26 +-
dlls/kernelbase/path.c | 1144 +++++++++++++++++++++++++++++++
2 files changed, 1157 insertions(+), 13 deletions(-)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 874db20c9c..f9f9f2487b 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1018,8 +1018,8 @@
# @ stub PackageSidFromFamilyName
# @ stub PackageSidFromProductId
# @ stub ParseApplicationUserModelId
-@ stdcall ParseURLA(str ptr) shlwapi.ParseURLA
-@ stdcall ParseURLW(wstr ptr) shlwapi.ParseURLW
+@ stdcall ParseURLA(str ptr)
+@ stdcall ParseURLW(wstr ptr)
@ stdcall PathAddBackslashA(str)
@ stdcall PathAddBackslashW(wstr)
@ stdcall PathAddExtensionA(str str)
@@ -1053,9 +1053,9 @@
@ stdcall PathCombineW(ptr wstr wstr)
@ stdcall PathCommonPrefixA(str str ptr)
@ stdcall PathCommonPrefixW(wstr wstr ptr)
-@ stdcall PathCreateFromUrlA(str ptr ptr long) shlwapi.PathCreateFromUrlA
-@ stdcall PathCreateFromUrlAlloc(wstr ptr long) shlwapi.PathCreateFromUrlAlloc
-@ stdcall PathCreateFromUrlW(wstr ptr ptr long) shlwapi.PathCreateFromUrlW
+@ stdcall PathCreateFromUrlA(str ptr ptr long)
+@ stdcall PathCreateFromUrlAlloc(wstr ptr long)
+@ stdcall PathCreateFromUrlW(wstr ptr ptr long)
@ stdcall PathFileExistsA(str)
@ stdcall PathFileExistsW(wstr)
@ stdcall PathFindExtensionA(str)
@@ -1089,8 +1089,8 @@
@ stdcall PathIsUNCServerShareW(wstr)
@ stdcall PathIsUNCServerW(wstr)
@ stdcall PathIsUNCW(wstr)
-@ stdcall PathIsURLA(str) shlwapi.PathIsURLA
-@ stdcall PathIsURLW(wstr) shlwapi.PathIsURLW
+@ stdcall PathIsURLA(str)
+@ stdcall PathIsURLW(wstr)
@ stdcall PathIsValidCharA(long long)
@ stdcall PathIsValidCharW(long long)
@ stdcall PathMatchSpecA(str str)
@@ -1630,16 +1630,16 @@
@ stdcall UpdateProcThreadAttribute(ptr long long ptr long ptr ptr) kernel32.UpdateProcThreadAttribute
@ stdcall UrlApplySchemeA(str ptr ptr long) shlwapi.UrlApplySchemeA
@ stdcall UrlApplySchemeW(wstr ptr ptr long) shlwapi.UrlApplySchemeW
-@ stdcall UrlCanonicalizeA(str ptr ptr long) shlwapi.UrlCanonicalizeA
-@ stdcall UrlCanonicalizeW(wstr ptr ptr long) shlwapi.UrlCanonicalizeW
+@ stdcall UrlCanonicalizeA(str ptr ptr long)
+@ stdcall UrlCanonicalizeW(wstr ptr ptr long)
@ stdcall UrlCombineA(str str ptr ptr long) shlwapi.UrlCombineA
@ stdcall UrlCombineW(wstr wstr ptr ptr long) shlwapi.UrlCombineW
@ stdcall UrlCompareA(str str long) shlwapi.UrlCompareA
@ stdcall UrlCompareW(wstr wstr long) shlwapi.UrlCompareW
@ stdcall UrlCreateFromPathA(str ptr ptr long) shlwapi.UrlCreateFromPathA
@ stdcall UrlCreateFromPathW(wstr ptr ptr long) shlwapi.UrlCreateFromPathW
-@ stdcall UrlEscapeA(str ptr ptr long) shlwapi.UrlEscapeA
-@ stdcall UrlEscapeW(wstr ptr ptr long) shlwapi.UrlEscapeW
+@ stdcall UrlEscapeA(str ptr ptr long)
+@ stdcall UrlEscapeW(wstr ptr ptr long)
@ stdcall UrlFixupW(wstr wstr long) shlwapi.UrlFixupW
@ stdcall UrlGetLocationA(str) shlwapi.UrlGetLocationA
@ stdcall UrlGetLocationW(wstr) shlwapi.UrlGetLocationW
@@ -1653,8 +1653,8 @@
@ stdcall UrlIsOpaqueA(str) shlwapi.UrlIsOpaqueA
@ stdcall UrlIsOpaqueW(wstr) shlwapi.UrlIsOpaqueW
@ stdcall UrlIsW(wstr long) shlwapi.UrlIsW
-@ stdcall UrlUnescapeA(str ptr ptr long) shlwapi.UrlUnescapeA
-@ stdcall UrlUnescapeW(wstr ptr ptr long) shlwapi.UrlUnescapeW
+@ stdcall UrlUnescapeA(str ptr ptr long)
+@ stdcall UrlUnescapeW(wstr ptr ptr long)
@ stdcall VerFindFileA(long str str str ptr ptr ptr ptr) version.VerFindFileA
@ stdcall VerFindFileW(long wstr wstr wstr ptr ptr ptr ptr) version.VerFindFileW
@ stdcall VerLanguageNameA(long str long) kernel32.VerLanguageNameA
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index ca951cfd3f..44d58ea73b 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -24,12 +24,34 @@
#include "pathcch.h"
#include "strsafe.h"
#include "shlwapi.h"
+#include "wininet.h"
+#include "intshcut.h"
+#include "winternl.h"
#include "wine/debug.h"
+#include "wine/heap.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(path);
+static const char hexDigits[] = "0123456789ABCDEF";
+
+static WCHAR *heap_strdupAtoW(const char *str)
+{
+ WCHAR *ret = NULL;
+
+ if (str)
+ {
+ DWORD len;
+
+ len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ ret = heap_alloc(len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+ }
+
+ return ret;
+}
+
static char *char_next(const char *ptr)
{
if (!*ptr) return (LPSTR)ptr;
@@ -2598,3 +2620,1125 @@ BOOL WINAPI PathFileExistsW(const WCHAR *path)
SetErrorMode(prev_mode);
return attrs != INVALID_FILE_ATTRIBUTES;
}
+
+static const struct
+{
+ URL_SCHEME scheme_number;
+ WCHAR scheme_name[12];
+}
+url_schemes[] =
+{
+ { URL_SCHEME_FTP, {'f','t','p',0}},
+ { URL_SCHEME_HTTP, {'h','t','t','p',0}},
+ { URL_SCHEME_GOPHER, {'g','o','p','h','e','r',0}},
+ { URL_SCHEME_MAILTO, {'m','a','i','l','t','o',0}},
+ { URL_SCHEME_NEWS, {'n','e','w','s',0}},
+ { URL_SCHEME_NNTP, {'n','n','t','p',0}},
+ { URL_SCHEME_TELNET, {'t','e','l','n','e','t',0}},
+ { URL_SCHEME_WAIS, {'w','a','i','s',0}},
+ { URL_SCHEME_FILE, {'f','i','l','e',0}},
+ { URL_SCHEME_MK, {'m','k',0}},
+ { URL_SCHEME_HTTPS, {'h','t','t','p','s',0}},
+ { URL_SCHEME_SHELL, {'s','h','e','l','l',0}},
+ { URL_SCHEME_SNEWS, {'s','n','e','w','s',0}},
+ { URL_SCHEME_LOCAL, {'l','o','c','a','l',0}},
+ { URL_SCHEME_JAVASCRIPT, {'j','a','v','a','s','c','r','i','p','t',0}},
+ { URL_SCHEME_VBSCRIPT, {'v','b','s','c','r','i','p','t',0}},
+ { URL_SCHEME_ABOUT, {'a','b','o','u','t',0}},
+ { URL_SCHEME_RES, {'r','e','s',0}},
+};
+
+static DWORD get_scheme_code(const WCHAR *scheme, DWORD scheme_len)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(url_schemes); ++i)
+ {
+ if (scheme_len == strlenW(url_schemes[i].scheme_name)
+ && !strncmpiW(scheme, url_schemes[i].scheme_name, scheme_len))
+ return url_schemes[i].scheme_number;
+ }
+
+ return URL_SCHEME_UNKNOWN;
+}
+
+HRESULT WINAPI ParseURLA(const char *url, PARSEDURLA *result)
+{
+ WCHAR scheme[INTERNET_MAX_SCHEME_LENGTH];
+ const char *ptr = url;
+ int len;
+
+ TRACE("%s, %p\n", wine_dbgstr_a(url), result);
+
+ if (result->cbSize != sizeof(*result))
+ return E_INVALIDARG;
+
+ while (*ptr && (isalnum(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.'))
+ ptr++;
+
+ if (*ptr != ':' || ptr <= url + 1)
+ {
+ result->pszProtocol = NULL;
+ return URL_E_INVALID_SYNTAX;
+ }
+
+ result->pszProtocol = url;
+ result->cchProtocol = ptr - url;
+ result->pszSuffix = ptr + 1;
+ result->cchSuffix = strlen(result->pszSuffix);
+
+ len = MultiByteToWideChar(CP_ACP, 0, url, ptr - url, scheme, ARRAY_SIZE(scheme));
+ result->nScheme = get_scheme_code(scheme, len);
+
+ return S_OK;
+}
+
+HRESULT WINAPI ParseURLW(const WCHAR *url, PARSEDURLW *result)
+{
+ const WCHAR *ptr = url;
+
+ TRACE("%s, %p\n", wine_dbgstr_w(url), result);
+
+ if (result->cbSize != sizeof(*result))
+ return E_INVALIDARG;
+
+ while (*ptr && (isalnumW(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.'))
+ ptr++;
+
+ if (*ptr != ':' || ptr <= url + 1)
+ {
+ result->pszProtocol = NULL;
+ return URL_E_INVALID_SYNTAX;
+ }
+
+ result->pszProtocol = url;
+ result->cchProtocol = ptr - url;
+ result->pszSuffix = ptr + 1;
+ result->cchSuffix = strlenW(result->pszSuffix);
+ result->nScheme = get_scheme_code(url, ptr - url);
+
+ return S_OK;
+}
+
+HRESULT WINAPI UrlUnescapeA(char *url, char *unescaped, DWORD *unescaped_len, DWORD flags)
+{
+ BOOL stop_unescaping = FALSE;
+ const char *src;
+ char *dst, next;
+ DWORD needed;
+ HRESULT hr;
+
+ TRACE("%s, %p, %p, %#x\n", wine_dbgstr_a(url), unescaped, unescaped_len, flags);
+
+ if (!url)
+ return E_INVALIDARG;
+
+ if (flags & URL_UNESCAPE_INPLACE)
+ dst = url;
+ else
+ {
+ if (!unescaped || !unescaped_len) return E_INVALIDARG;
+ dst = unescaped;
+ }
+
+ for (src = url, needed = 0; *src; src++, needed++)
+ {
+ if (flags & URL_DONT_UNESCAPE_EXTRA_INFO && (*src == '#' || *src == '?'))
+ {
+ stop_unescaping = TRUE;
+ next = *src;
+ }
+ else if (*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) && !stop_unescaping)
+ {
+ INT ih;
+ char buf[3];
+ memcpy(buf, src + 1, 2);
+ buf[2] = '\0';
+ ih = strtol(buf, NULL, 16);
+ next = (CHAR) ih;
+ src += 2; /* Advance to end of escape */
+ }
+ else
+ next = *src;
+
+ if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
+ *dst++ = next;
+ }
+
+ if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
+ {
+ *dst = '\0';
+ hr = S_OK;
+ }
+ else
+ {
+ needed++; /* add one for the '\0' */
+ hr = E_POINTER;
+ }
+
+ if (!(flags & URL_UNESCAPE_INPLACE))
+ *unescaped_len = needed;
+
+ if (hr == S_OK)
+ TRACE("result %s\n", flags & URL_UNESCAPE_INPLACE ? wine_dbgstr_a(url) : wine_dbgstr_a(unescaped));
+
+ return hr;
+}
+
+HRESULT WINAPI UrlUnescapeW(WCHAR *url, WCHAR *unescaped, DWORD *unescaped_len, DWORD flags)
+{
+ BOOL stop_unescaping = FALSE;
+ const WCHAR *src;
+ WCHAR *dst, next;
+ DWORD needed;
+ HRESULT hr;
+
+ TRACE("%s, %p, %p, %#x\n", wine_dbgstr_w(url), unescaped, unescaped_len, flags);
+
+ if (!url)
+ return E_INVALIDARG;
+
+ if (flags & URL_UNESCAPE_INPLACE)
+ dst = url;
+ else
+ {
+ if (!unescaped || !unescaped_len) return E_INVALIDARG;
+ dst = unescaped;
+ }
+
+ for (src = url, needed = 0; *src; src++, needed++)
+ {
+ if (flags & URL_DONT_UNESCAPE_EXTRA_INFO && (*src == '#' || *src == '?'))
+ {
+ stop_unescaping = TRUE;
+ next = *src;
+ }
+ else if (*src == '%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) && !stop_unescaping)
+ {
+ INT ih;
+ WCHAR buf[5] = {'0','x',0};
+ memcpy(buf + 2, src + 1, 2*sizeof(WCHAR));
+ buf[4] = 0;
+ StrToIntExW(buf, STIF_SUPPORT_HEX, &ih);
+ next = (WCHAR) ih;
+ src += 2; /* Advance to end of escape */
+ }
+ else
+ next = *src;
+
+ if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
+ *dst++ = next;
+ }
+
+ if (flags & URL_UNESCAPE_INPLACE || needed < *unescaped_len)
+ {
+ *dst = '\0';
+ hr = S_OK;
+ }
+ else
+ {
+ needed++; /* add one for the '\0' */
+ hr = E_POINTER;
+ }
+
+ if (!(flags & URL_UNESCAPE_INPLACE))
+ *unescaped_len = needed;
+
+ if (hr == S_OK)
+ TRACE("result %s\n", flags & URL_UNESCAPE_INPLACE ? wine_dbgstr_w(url) : wine_dbgstr_w(unescaped));
+
+ return hr;
+}
+
+HRESULT WINAPI PathCreateFromUrlA(const char *pszUrl, char *pszPath, DWORD *pcchPath, DWORD dwReserved)
+{
+ WCHAR bufW[MAX_PATH];
+ WCHAR *pathW = bufW;
+ UNICODE_STRING urlW;
+ HRESULT ret;
+ DWORD lenW = ARRAY_SIZE(bufW), lenA;
+
+ if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
+ return E_INVALIDARG;
+
+ if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
+ return E_INVALIDARG;
+ if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) {
+ pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
+ ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved);
+ }
+ if(ret == S_OK) {
+ RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR));
+ if(*pcchPath > lenA) {
+ RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR));
+ pszPath[lenA] = 0;
+ *pcchPath = lenA;
+ } else {
+ *pcchPath = lenA + 1;
+ ret = E_POINTER;
+ }
+ }
+ if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW);
+ RtlFreeUnicodeString(&urlW);
+ return ret;
+}
+
+HRESULT WINAPI PathCreateFromUrlW(const WCHAR *url, WCHAR *path, DWORD *pcchPath, DWORD dwReserved)
+{
+ static const WCHAR file_colon[] = { 'f','i','l','e',':',0 };
+ static const WCHAR localhost[] = { 'l','o','c','a','l','h','o','s','t',0 };
+ DWORD nslashes, unescape, len;
+ const WCHAR *src;
+ WCHAR *tpath, *dst;
+ HRESULT hr = S_OK;
+
+ TRACE("%s, %p, %p, %#x\n", wine_dbgstr_w(url), path, pcchPath, dwReserved);
+
+ if (!url || !path || !pcchPath || !*pcchPath)
+ return E_INVALIDARG;
+
+ if (lstrlenW(url) < 5)
+ return E_INVALIDARG;
+
+ if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, url, 5, file_colon, 5) != CSTR_EQUAL)
+ return E_INVALIDARG;
+
+ url += 5;
+
+ src = url;
+ nslashes = 0;
+ while (*src == '/' || *src == '\\')
+ {
+ nslashes++;
+ src++;
+ }
+
+ /* We need a temporary buffer so we can compute what size to ask for.
+ * We know that the final string won't be longer than the current pszUrl
+ * plus at most two backslashes. All the other transformations make it
+ * shorter.
+ */
+ len = 2 + lstrlenW(url) + 1;
+ if (*pcchPath < len)
+ tpath = heap_alloc(len * sizeof(WCHAR));
+ else
+ tpath = path;
+
+ len = 0;
+ dst = tpath;
+ unescape = 1;
+ switch (nslashes)
+ {
+ case 0:
+ /* 'file:' + escaped DOS path */
+ break;
+ case 1:
+ /* 'file:/' + escaped DOS path */
+ /* fall through */
+ case 3:
+ /* 'file:///' (implied localhost) + escaped DOS path */
+ if (!isalphaW(*src) || (src[1] != ':' && src[1] != '|'))
+ src -= 1;
+ break;
+ case 2:
+ if (lstrlenW(src) >= 10 && CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE,
+ src, 9, localhost, 9) == CSTR_EQUAL && (src[9] == '/' || src[9] == '\\'))
+ {
+ /* 'file://localhost/' + escaped DOS path */
+ src += 10;
+ }
+ else if (isalphaW(*src) && (src[1] == ':' || src[1] == '|'))
+ {
+ /* 'file://' + unescaped DOS path */
+ unescape = 0;
+ }
+ else
+ {
+ /* 'file://hostname:port/path' (where path is escaped)
+ * or 'file:' + escaped UNC path (\\server\share\path)
+ * The second form is clearly specific to Windows and it might
+ * even be doing a network lookup to try to figure it out.
+ */
+ while (*src && *src != '/' && *src != '\\')
+ src++;
+ len = src - url;
+ StrCpyNW(dst, url, len + 1);
+ dst += len;
+ if (*src && isalphaW(src[1]) && (src[2] == ':' || src[2] == '|'))
+ {
+ /* 'Forget' to add a trailing '/', just like Windows */
+ src++;
+ }
+ }
+ break;
+ case 4:
+ /* 'file://' + unescaped UNC path (\\server\share\path) */
+ unescape = 0;
+ if (isalphaW(*src) && (src[1] == ':' || src[1] == '|'))
+ break;
+ /* fall through */
+ default:
+ /* 'file:/...' + escaped UNC path (\\server\share\path) */
+ src -= 2;
+ }
+
+ /* Copy the remainder of the path */
+ len += lstrlenW(src);
+ strcpyW(dst, src);
+
+ /* First do the Windows-specific path conversions */
+ for (dst = tpath; *dst; dst++)
+ if (*dst == '/') *dst = '\\';
+ if (isalphaW(*tpath) && tpath[1] == '|')
+ tpath[1] = ':'; /* c| -> c: */
+
+ /* And only then unescape the path (i.e. escaped slashes are left as is) */
+ if (unescape)
+ {
+ hr = UrlUnescapeW(tpath, NULL, &len, URL_UNESCAPE_INPLACE);
+ if (hr == S_OK)
+ {
+ /* When working in-place UrlUnescapeW() does not set len */
+ len = lstrlenW(tpath);
+ }
+ }
+
+ if (*pcchPath < len + 1)
+ {
+ hr = E_POINTER;
+ *pcchPath = len + 1;
+ }
+ else
+ {
+ *pcchPath = len;
+ if (tpath != path)
+ strcpyW(path, tpath);
+ }
+ if (tpath != path)
+ heap_free(tpath);
+
+ TRACE("Returning (%u) %s\n", *pcchPath, wine_dbgstr_w(path));
+ return hr;
+}
+
+HRESULT WINAPI PathCreateFromUrlAlloc(const WCHAR *url, WCHAR **path, DWORD reserved)
+{
+ WCHAR pathW[MAX_PATH];
+ DWORD size;
+ HRESULT hr;
+
+ size = MAX_PATH;
+ hr = PathCreateFromUrlW(url, pathW, &size, reserved);
+ if (SUCCEEDED(hr))
+ {
+ /* Yes, this is supposed to crash if 'path' is NULL */
+ *path = StrDupW(pathW);
+ }
+
+ return hr;
+}
+
+BOOL WINAPI PathIsURLA(const char *path)
+{
+ PARSEDURLA base;
+ HRESULT hr;
+
+ TRACE("%s\n", wine_dbgstr_a(path));
+
+ if (!path || !*path)
+ return FALSE;
+
+ /* get protocol */
+ base.cbSize = sizeof(base);
+ hr = ParseURLA(path, &base);
+ return hr == S_OK && (base.nScheme != URL_SCHEME_INVALID);
+}
+
+BOOL WINAPI PathIsURLW(const WCHAR *path)
+{
+ PARSEDURLW base;
+ HRESULT hr;
+
+ TRACE("%s\n", wine_dbgstr_w(path));
+
+ if (!path || !*path)
+ return FALSE;
+
+ /* get protocol */
+ base.cbSize = sizeof(base);
+ hr = ParseURLW(path, &base);
+ return hr == S_OK && (base.nScheme != URL_SCHEME_INVALID);
+}
+
+#define WINE_URL_BASH_AS_SLASH 0x01
+#define WINE_URL_COLLAPSE_SLASHES 0x02
+#define WINE_URL_ESCAPE_SLASH 0x04
+#define WINE_URL_ESCAPE_HASH 0x08
+#define WINE_URL_ESCAPE_QUESTION 0x10
+#define WINE_URL_STOP_ON_HASH 0x20
+#define WINE_URL_STOP_ON_QUESTION 0x40
+
+static BOOL url_needs_escape(WCHAR ch, DWORD flags, DWORD int_flags)
+{
+ if (flags & URL_ESCAPE_SPACES_ONLY)
+ return ch == ' ';
+
+ if ((flags & URL_ESCAPE_PERCENT) && (ch == '%'))
+ return TRUE;
+
+ if ((flags & URL_ESCAPE_AS_UTF8) && (ch >= 0x80))
+ return TRUE;
+
+ if (ch <= 31 || (ch >= 127 && ch <= 255) )
+ return TRUE;
+
+ if (isalnumW(ch))
+ return FALSE;
+
+ switch (ch) {
+ case ' ':
+ case '<':
+ case '>':
+ case '\"':
+ case '{':
+ case '}':
+ case '|':
+ case '\\':
+ case '^':
+ case ']':
+ case '[':
+ case '`':
+ case '&':
+ return TRUE;
+ case '/':
+ return !!(int_flags & WINE_URL_ESCAPE_SLASH);
+ case '?':
+ return !!(int_flags & WINE_URL_ESCAPE_QUESTION);
+ case '#':
+ return !!(int_flags & WINE_URL_ESCAPE_HASH);
+ default:
+ return FALSE;
+ }
+}
+
+HRESULT WINAPI UrlEscapeA(const char *url, char *escaped, DWORD *escaped_len, DWORD flags)
+{
+ WCHAR bufW[INTERNET_MAX_URL_LENGTH];
+ WCHAR *escapedW = bufW;
+ UNICODE_STRING urlW;
+ HRESULT hr;
+ DWORD lenW = ARRAY_SIZE(bufW), lenA;
+
+ if (!escaped || !escaped_len || !*escaped_len)
+ return E_INVALIDARG;
+
+ if (!RtlCreateUnicodeStringFromAsciiz(&urlW, url))
+ return E_INVALIDARG;
+
+ if (flags & URL_ESCAPE_AS_UTF8)
+ {
+ RtlFreeUnicodeString(&urlW);
+ return E_NOTIMPL;
+ }
+
+ if ((hr = UrlEscapeW(urlW.Buffer, escapedW, &lenW, flags)) == E_POINTER)
+ {
+ escapedW = heap_alloc(lenW * sizeof(WCHAR));
+ hr = UrlEscapeW(urlW.Buffer, escapedW, &lenW, flags);
+ }
+
+ if (hr == S_OK)
+ {
+ RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR));
+ if (*escaped_len > lenA)
+ {
+ RtlUnicodeToMultiByteN(escaped, *escaped_len - 1, &lenA, escapedW, lenW * sizeof(WCHAR));
+ escaped[lenA] = 0;
+ *escaped_len = lenA;
+ }
+ else
+ {
+ *escaped_len = lenA + 1;
+ hr = E_POINTER;
+ }
+ }
+ if (escapedW != bufW)
+ heap_free(escapedW);
+ RtlFreeUnicodeString(&urlW);
+ return hr;
+}
+
+HRESULT WINAPI UrlEscapeW(const WCHAR *url, WCHAR *escaped, DWORD *escaped_len, DWORD flags)
+{
+ static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0};
+ DWORD needed = 0, slashes = 0, int_flags;
+ WCHAR next[12], *dst, *dst_ptr;
+ BOOL stop_escaping = FALSE;
+ PARSEDURLW parsed_url;
+ const WCHAR *src;
+ INT i, len;
+ HRESULT hr;
+
+ TRACE("%p, %s, %p, %p, %#x\n", url, wine_dbgstr_w(url), escaped, escaped_len, flags);
+
+ if (!url || !escaped_len || !escaped || *escaped_len == 0)
+ return E_INVALIDARG;
+
+ if (flags & ~(URL_ESCAPE_SPACES_ONLY | URL_ESCAPE_SEGMENT_ONLY | URL_DONT_ESCAPE_EXTRA_INFO |
+ URL_ESCAPE_PERCENT | URL_ESCAPE_AS_UTF8))
+ {
+ FIXME("Unimplemented flags: %08x\n", flags);
+ }
+
+ dst_ptr = dst = heap_alloc(*escaped_len * sizeof(WCHAR));
+ if (!dst_ptr)
+ return E_OUTOFMEMORY;
+
+ /* fix up flags */
+ if (flags & URL_ESCAPE_SPACES_ONLY)
+ /* if SPACES_ONLY specified, reset the other controls */
+ flags &= ~(URL_DONT_ESCAPE_EXTRA_INFO | URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY);
+ else
+ /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
+ flags |= URL_DONT_ESCAPE_EXTRA_INFO;
+
+ int_flags = 0;
+ if (flags & URL_ESCAPE_SEGMENT_ONLY)
+ int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
+ else
+ {
+ parsed_url.cbSize = sizeof(parsed_url);
+ if (ParseURLW(url, &parsed_url) != S_OK)
+ parsed_url.nScheme = URL_SCHEME_INVALID;
+
+ TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
+
+ if (flags & URL_DONT_ESCAPE_EXTRA_INFO)
+ int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
+
+ switch(parsed_url.nScheme) {
+ case URL_SCHEME_FILE:
+ int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
+ int_flags &= ~WINE_URL_STOP_ON_HASH;
+ break;
+
+ case URL_SCHEME_HTTP:
+ case URL_SCHEME_HTTPS:
+ int_flags |= WINE_URL_BASH_AS_SLASH;
+ if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\')
+ int_flags |= WINE_URL_ESCAPE_SLASH;
+ break;
+
+ case URL_SCHEME_MAILTO:
+ int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH;
+ int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH);
+ break;
+
+ case URL_SCHEME_INVALID:
+ break;
+
+ case URL_SCHEME_FTP:
+ default:
+ if(parsed_url.pszSuffix[0] != '/')
+ int_flags |= WINE_URL_ESCAPE_SLASH;
+ break;
+ }
+ }
+
+ for (src = url; *src; )
+ {
+ WCHAR cur = *src;
+ len = 0;
+
+ if ((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == url + parsed_url.cchProtocol + 1)
+ {
+ int localhost_len = ARRAY_SIZE(localhost) - 1;
+ while (cur == '/' || cur == '\\')
+ {
+ slashes++;
+ cur = *++src;
+ }
+ if (slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */
+ if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\')
+ src += localhost_len + 1;
+ slashes = 3;
+ }
+
+ switch (slashes)
+ {
+ case 1:
+ case 3:
+ next[0] = next[1] = next[2] = '/';
+ len = 3;
+ break;
+ case 0:
+ len = 0;
+ break;
+ default:
+ next[0] = next[1] = '/';
+ len = 2;
+ break;
+ }
+ }
+ if (len == 0)
+ {
+ if (cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH))
+ stop_escaping = TRUE;
+
+ if (cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION))
+ stop_escaping = TRUE;
+
+ if (cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
+
+ if (url_needs_escape(cur, flags, int_flags) && !stop_escaping)
+ {
+ if (flags & URL_ESCAPE_AS_UTF8)
+ {
+ char utf[16];
+
+ if ((cur >= 0xd800 && cur <= 0xdfff) && (src[1] >= 0xdc00 && src[1] <= 0xdfff))
+ {
+ len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, 2, utf, sizeof(utf), NULL, NULL);
+ src++;
+ }
+ else
+ len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &cur, 1, utf, sizeof(utf), NULL, NULL);
+
+ if (!len)
+ {
+ utf[0] = 0xef;
+ utf[1] = 0xbf;
+ utf[2] = 0xbd;
+ len = 3;
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ next[i*3+0] = '%';
+ next[i*3+1] = hexDigits[(utf[i] >> 4) & 0xf];
+ next[i*3+2] = hexDigits[utf[i] & 0xf];
+ }
+ len *= 3;
+ }
+ else
+ {
+ next[0] = '%';
+ next[1] = hexDigits[(cur >> 4) & 0xf];
+ next[2] = hexDigits[cur & 0xf];
+ len = 3;
+ }
+ }
+ else
+ {
+ next[0] = cur;
+ len = 1;
+ }
+ src++;
+ }
+
+ if (needed + len <= *escaped_len)
+ {
+ memcpy(dst, next, len*sizeof(WCHAR));
+ dst += len;
+ }
+ needed += len;
+ }
+
+ if (needed < *escaped_len)
+ {
+ *dst = '\0';
+ memcpy(escaped, dst_ptr, (needed+1)*sizeof(WCHAR));
+ hr = S_OK;
+ }
+ else
+ {
+ needed++; /* add one for the '\0' */
+ hr = E_POINTER;
+ }
+ *escaped_len = needed;
+
+ heap_free(dst_ptr);
+ return hr;
+}
+
+HRESULT WINAPI UrlCanonicalizeA(const char *src_url, char *canonicalized, DWORD *canonicalized_len, DWORD flags)
+{
+ LPWSTR url, canonical;
+ HRESULT hr;
+
+ TRACE("%s, %p, %p, %#x\n", wine_dbgstr_a(src_url), canonicalized, canonicalized_len, flags);
+
+ if (!src_url || !canonicalized || !canonicalized_len || !*canonicalized_len)
+ return E_INVALIDARG;
+
+ url = heap_strdupAtoW(src_url);
+ canonical = heap_alloc(*canonicalized_len * sizeof(WCHAR));
+ if (!url || !canonical)
+ {
+ heap_free(url);
+ heap_free(canonical);
+ return E_OUTOFMEMORY;
+ }
+
+ hr = UrlCanonicalizeW(url, canonical, canonicalized_len, flags);
+ if (hr == S_OK)
+ WideCharToMultiByte(CP_ACP, 0, canonical, -1, canonicalized, *canonicalized_len + 1, NULL, NULL);
+
+ heap_free(url);
+ heap_free(canonical);
+ return hr;
+}
+
+HRESULT WINAPI UrlCanonicalizeW(const WCHAR *src_url, WCHAR *canonicalized, DWORD *canonicalized_len, DWORD flags)
+{
+ static const WCHAR wszFile[] = {'f','i','l','e',':'};
+ static const WCHAR wszRes[] = {'r','e','s',':'};
+ static const WCHAR wszHttp[] = {'h','t','t','p',':'};
+ static const WCHAR wszLocalhost[] = {'l','o','c','a','l','h','o','s','t'};
+ static const WCHAR wszFilePrefix[] = {'f','i','l','e',':','/','/','/'};
+ WCHAR *url_copy, *url, *wk2, *mp, *mp2;
+ DWORD nByteLen, nLen, nWkLen;
+ const WCHAR *wk1, *root;
+ DWORD escape_flags;
+ WCHAR slash = '\0';
+ HRESULT hr = S_OK;
+ BOOL is_file_url;
+ INT state;
+
+ TRACE("%s, %p, %p, %#x\n", wine_dbgstr_w(src_url), canonicalized, canonicalized_len, flags);
+
+ if (!src_url || !canonicalized || !canonicalized || !*canonicalized_len)
+ return E_INVALIDARG;
+
+ if (!*src_url)
+ {
+ *canonicalized = 0;
+ return S_OK;
+ }
+
+ /* Remove '\t' characters from URL */
+ nByteLen = (strlenW(src_url) + 1) * sizeof(WCHAR); /* length in bytes */
+ url = HeapAlloc(GetProcessHeap(), 0, nByteLen);
+ if(!url)
+ return E_OUTOFMEMORY;
+
+ wk1 = src_url;
+ wk2 = url;
+ do
+ {
+ while(*wk1 == '\t')
+ wk1++;
+ *wk2++ = *wk1;
+ } while (*wk1++);
+
+ /* Allocate memory for simplified URL (before escaping) */
+ nByteLen = (wk2-url)*sizeof(WCHAR);
+ url_copy = heap_alloc(nByteLen + sizeof(wszFilePrefix) + sizeof(WCHAR));
+ if (!url_copy)
+ {
+ heap_free(url);
+ return E_OUTOFMEMORY;
+ }
+
+ is_file_url = !strncmpW(wszFile, url, ARRAY_SIZE(wszFile));
+
+ if ((nByteLen >= sizeof(wszHttp) && !memcmp(wszHttp, url, sizeof(wszHttp))) || is_file_url)
+ slash = '/';
+
+ if ((flags & (URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY)) && is_file_url)
+ slash = '\\';
+
+ if (nByteLen >= sizeof(wszRes) && !memcmp(wszRes, url, sizeof(wszRes)))
+ {
+ flags &= ~URL_FILE_USE_PATHURL;
+ slash = '\0';
+ }
+
+ /*
+ * state =
+ * 0 initial 1,3
+ * 1 have 2[+] alnum 2,3
+ * 2 have scheme (found :) 4,6,3
+ * 3 failed (no location)
+ * 4 have // 5,3
+ * 5 have 1[+] alnum 6,3
+ * 6 have location (found /) save root location
+ */
+
+ wk1 = url;
+ wk2 = url_copy;
+ state = 0;
+
+ /* Assume path */
+ if (url[1] == ':')
+ {
+ memcpy(wk2, wszFilePrefix, sizeof(wszFilePrefix));
+ wk2 += ARRAY_SIZE(wszFilePrefix);
+ if (flags & (URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY))
+ {
+ slash = '\\';
+ --wk2;
+ }
+ else
+ flags |= URL_ESCAPE_UNSAFE;
+ state = 5;
+ is_file_url = TRUE;
+ }
+ else if (url[0] == '/')
+ {
+ state = 5;
+ is_file_url = TRUE;
+ }
+
+ while (*wk1)
+ {
+ switch (state)
+ {
+ case 0:
+ if (!isalnumW(*wk1)) {state = 3; break;}
+ *wk2++ = *wk1++;
+ if (!isalnumW(*wk1)) {state = 3; break;}
+ *wk2++ = *wk1++;
+ state = 1;
+ break;
+ case 1:
+ *wk2++ = *wk1;
+ if (*wk1++ == ':') state = 2;
+ break;
+ case 2:
+ *wk2++ = *wk1++;
+ if (*wk1 != '/') {state = 6; break;}
+ *wk2++ = *wk1++;
+ if ((flags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszLocalhost) && is_file_url
+ && !memcmp(wszLocalhost, wk1, sizeof(wszLocalhost)))
+ {
+ wk1 += ARRAY_SIZE(wszLocalhost);
+ while (*wk1 == '\\' && (flags & URL_FILE_USE_PATHURL))
+ wk1++;
+ }
+
+ if (*wk1 == '/' && (flags & URL_FILE_USE_PATHURL))
+ wk1++;
+ else if (is_file_url)
+ {
+ const WCHAR *body = wk1;
+
+ while (*body == '/')
+ ++body;
+
+ if (isalnumW(*body) && *(body+1) == ':')
+ {
+ if (!(flags & (URL_WININET_COMPATIBILITY | URL_FILE_USE_PATHURL)))
+ {
+ if (slash)
+ *wk2++ = slash;
+ else
+ *wk2++ = '/';
+ }
+ }
+ else
+ {
+ if (flags & URL_WININET_COMPATIBILITY)
+ {
+ if (*wk1 == '/' && *(wk1 + 1) != '/')
+ {
+ *wk2++ = '\\';
+ }
+ else
+ {
+ *wk2++ = '\\';
+ *wk2++ = '\\';
+ }
+ }
+ else
+ {
+ if (*wk1 == '/' && *(wk1+1) != '/')
+ {
+ if (slash)
+ *wk2++ = slash;
+ else
+ *wk2++ = '/';
+ }
+ }
+ }
+ wk1 = body;
+ }
+ state = 4;
+ break;
+ case 3:
+ nWkLen = strlenW(wk1);
+ memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR));
+ mp = wk2;
+ wk1 += nWkLen;
+ wk2 += nWkLen;
+
+ if (slash)
+ {
+ while (mp < wk2)
+ {
+ if (*mp == '/' || *mp == '\\')
+ *mp = slash;
+ mp++;
+ }
+ }
+ break;
+ case 4:
+ if (!isalnumW(*wk1) && (*wk1 != '-') && (*wk1 != '.') && (*wk1 != ':'))
+ {
+ state = 3;
+ break;
+ }
+ while (isalnumW(*wk1) || (*wk1 == '-') || (*wk1 == '.') || (*wk1 == ':'))
+ *wk2++ = *wk1++;
+ state = 5;
+ if (!*wk1)
+ {
+ if (slash)
+ *wk2++ = slash;
+ else
+ *wk2++ = '/';
+ }
+ break;
+ case 5:
+ if (*wk1 != '/' && *wk1 != '\\')
+ {
+ state = 3;
+ break;
+ }
+ while (*wk1 == '/' || *wk1 == '\\')
+ {
+ if (slash)
+ *wk2++ = slash;
+ else
+ *wk2++ = *wk1;
+ wk1++;
+ }
+ state = 6;
+ break;
+ case 6:
+ if (flags & URL_DONT_SIMPLIFY)
+ {
+ state = 3;
+ break;
+ }
+
+ /* Now at root location, cannot back up any more. */
+ /* "root" will point at the '/' */
+
+ root = wk2-1;
+ while (*wk1)
+ {
+ mp = strchrW(wk1, '/');
+ mp2 = strchrW(wk1, '\\');
+ if (mp2 && (!mp || mp2 < mp))
+ mp = mp2;
+ if (!mp)
+ {
+ nWkLen = strlenW(wk1);
+ memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR));
+ wk1 += nWkLen;
+ wk2 += nWkLen;
+ continue;
+ }
+ nLen = mp - wk1;
+ if (nLen)
+ {
+ memcpy(wk2, wk1, nLen * sizeof(WCHAR));
+ wk2 += nLen;
+ wk1 += nLen;
+ }
+ if (slash)
+ *wk2++ = slash;
+ else
+ *wk2++ = *wk1;
+ wk1++;
+
+ while (*wk1 == '.')
+ {
+ TRACE("found '/.'\n");
+ if (wk1[1] == '/' || wk1[1] == '\\')
+ {
+ /* case of /./ -> skip the ./ */
+ wk1 += 2;
+ }
+ else if (wk1[1] == '.' && (wk1[2] == '/' || wk1[2] == '\\' || wk1[2] == '?'
+ || wk1[2] == '#' || !wk1[2]))
+ {
+ /* case /../ -> need to backup wk2 */
+ TRACE("found '/../'\n");
+ *(wk2-1) = '\0'; /* set end of string */
+ mp = strrchrW(root, '/');
+ mp2 = strrchrW(root, '\\');
+ if (mp2 && (!mp || mp2 < mp))
+ mp = mp2;
+ if (mp && (mp >= root))
+ {
+ /* found valid backup point */
+ wk2 = mp + 1;
+ if(wk1[2] != '/' && wk1[2] != '\\')
+ wk1 += 2;
+ else
+ wk1 += 3;
+ }
+ else
+ {
+ /* did not find point, restore '/' */
+ *(wk2-1) = slash;
+ break;
+ }
+ }
+ else
+ break;
+ }
+ }
+ *wk2 = '\0';
+ break;
+ default:
+ FIXME("how did we get here - state=%d\n", state);
+ heap_free(url_copy);
+ heap_free(url);
+ return E_INVALIDARG;
+ }
+ *wk2 = '\0';
+ TRACE("Simplified, orig <%s>, simple <%s>\n", wine_dbgstr_w(src_url), wine_dbgstr_w(url_copy));
+ }
+ nLen = lstrlenW(url_copy);
+ while ((nLen > 0) && ((url_copy[nLen-1] <= ' ')))
+ url_copy[--nLen]=0;
+
+ if ((flags & URL_UNESCAPE) || ((flags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile)
+ && !memcmp(wszFile, url, sizeof(wszFile))))
+ {
+ UrlUnescapeW(url_copy, NULL, &nLen, URL_UNESCAPE_INPLACE);
+ }
+
+ escape_flags = flags & (URL_ESCAPE_UNSAFE | URL_ESCAPE_SPACES_ONLY | URL_ESCAPE_PERCENT |
+ URL_DONT_ESCAPE_EXTRA_INFO | URL_ESCAPE_SEGMENT_ONLY);
+
+ if (escape_flags)
+ {
+ escape_flags &= ~URL_ESCAPE_UNSAFE;
+ hr = UrlEscapeW(url_copy, canonicalized, canonicalized_len, escape_flags);
+ }
+ else
+ {
+ /* No escaping needed, just copy the string */
+ nLen = lstrlenW(url_copy);
+ if (nLen < *canonicalized_len)
+ memcpy(canonicalized, url_copy, (nLen + 1)*sizeof(WCHAR));
+ else
+ {
+ hr = E_POINTER;
+ nLen++;
+ }
+ *canonicalized_len = nLen;
+ }
+
+ heap_free(url_copy);
+ heap_free(url);
+
+ if (hr == S_OK)
+ TRACE("result %s\n", wine_dbgstr_w(canonicalized));
+
+ return hr;
+}
--
2.20.1
1
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/desktop.c | 2 ++
dlls/winex11.drv/display.c | 7 +++++--
dlls/winex11.drv/x11drv.h | 2 +-
dlls/winex11.drv/x11drv_main.c | 2 +-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index d478cbdcb3..c69c2122ab 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( "Xinerama", TRUE );
/* initialize the available resolutions */
dd_modes = X11DRV_Settings_SetHandlers("desktop",
@@ -303,6 +304,7 @@ void X11DRV_resize_desktop( unsigned int width, unsigned int height )
resize_data.old_virtual_rect = get_virtual_screen_rect();
xinerama_init( width, height );
+ X11DRV_DisplayDevices_Init( "Xinerama", TRUE );
resize_data.new_virtual_rect = get_virtual_screen_rect();
if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId())
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index 2cc36763db..7a96822a7f 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -374,7 +374,7 @@ static void cleanup_devices(void)
SetupDiDestroyDeviceInfoList(devinfo);
}
-void X11DRV_DisplayDevices_Init(void)
+void X11DRV_DisplayDevices_Init(const char *name, BOOL force)
{
struct x11drv_gpu *gpus = NULL;
struct x11drv_adapter *adapters = NULL;
@@ -391,12 +391,15 @@ void X11DRV_DisplayDevices_Init(void)
TRACE("via %s\n", wine_dbgstr_a(handler.name));
+ if (name && strcmp(handler.name, name))
+ TRACE("Wrong handler name %s, ignoring\n", name);
+
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &video_hkey,
&disposition))
goto fail;
/* Ensure only one thread is initializing the registry and avoid unnecessary reinit */
- if (disposition != REG_CREATED_NEW_KEY)
+ if (!force && disposition != REG_CREATED_NEW_KEY)
{
success = TRUE;
goto fail;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 40392b03c0..035d7cc9ab 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -740,7 +740,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(const char *name, 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..b0fa225565 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(NULL, FALSE);
return TRUE;
}
--
2.20.1
1
0
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/display.c | 120 ++++++++++++++++++++++++++++++++++--
dlls/winex11.drv/x11drv.h | 22 +++++++
dlls/winex11.drv/xinerama.c | 53 ++++++++++++++++
3 files changed, 190 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index 300a05e8c0..2cc36763db 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -39,11 +39,19 @@
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);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCWORK, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 4);
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 5);
+
static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
static const WCHAR graphics_driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',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 adapter_name_fmtW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','%','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','-',
@@ -90,6 +98,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;
@@ -185,7 +200,7 @@ fail:
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)
{
@@ -195,6 +210,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);
strcpyW(bufferW, machine_prefixW);
@@ -229,6 +245,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 fail;
+ /* 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 fail;
+ }
+
/* Write StateFlags */
if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags,
sizeof(adapter->state_flags)))
@@ -242,6 +267,64 @@ fail:
return ret;
}
+static BOOL X11DRV_InitMonitor(HDEVINFO devinfo, const struct x11drv_monitor *monitor, int monitor_index,
+ int video_index)
+{
+ WCHAR bufferW[MAX_PATH];
+ SP_DEVINFO_DATA device_data = {sizeof(SP_DEVINFO_DATA)};
+ HKEY hkey = NULL;
+ 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 fail;
+
+ /* Write HaredwareID registry property */
+ if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID,
+ (const BYTE *)monitor_hardware_idW, sizeof(monitor_hardware_idW)))
+ goto fail;
+
+ /* Open driver key */
+ hkey = SetupDiOpenDevRegKey(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+ if (hkey == INVALID_HANDLE_VALUE)
+ 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 *)monitor->name,
+ (strlenW(monitor->name) + 1) * sizeof(WCHAR)))
+ goto fail;
+
+ /* 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 fail;
+ /* RcMonitor */
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, DEVPROP_TYPE_BINARY,
+ (const BYTE *)&monitor->rc_monitor, sizeof(monitor->rc_monitor), 0))
+ goto fail;
+ /* RcWork */
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, DEVPROP_TYPE_BINARY,
+ (const BYTE *)&monitor->rc_work, sizeof(monitor->rc_work), 0))
+ goto fail;
+
+ sprintfW(bufferW, adapter_name_fmtW, video_index + 1);
+ /* Adapter name */
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, DEVPROP_TYPE_STRING,
+ (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR), 0))
+ goto fail;
+
+ ret = TRUE;
+fail:
+ RegCloseKey(hkey);
+ if (!ret)
+ ERR("Failed to initialize monitor\n");
+ return ret;
+}
+
static void prepare_devices(void)
{
static const BOOL not_present = FALSE;
@@ -249,8 +332,18 @@ static void prepare_devices(void)
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);
+
/* Set all GPUs as not present. We can't simply delete them because we need to keep the GUID consistent with
* each initialization run. We clean up non present GPUs at the end of initialization */
+ i = 0;
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
{
@@ -285,9 +378,10 @@ void X11DRV_DisplayDevices_Init(void)
{
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;
@@ -316,6 +410,7 @@ void X11DRV_DisplayDevices_Init(void)
prepare_devices();
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+ monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
/* Initialize GPUs */
if (!handler.pGetGpus(&gpus, &gpu_count))
@@ -332,10 +427,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 fail;
+
+ if (!X11DRV_InitAdapter(video_hkey, video_index, gpu, adapter, monitor_count,
&gpus[gpu], guidW, driverW, &adapters[adapter]))
goto fail;
+ /* Initialize monitors */
+ for (monitor = 0; monitor < monitor_count; monitor++)
+ {
+ if (!X11DRV_InitMonitor(monitor_devinfo, &monitors[monitor], monitor, video_index))
+ goto fail;
+ }
+
+ handler.pFreeMonitors(monitors);
+ monitors = NULL;
video_index++;
}
@@ -346,12 +453,15 @@ void X11DRV_DisplayDevices_Init(void)
success = TRUE;
fail:
cleanup_devices();
+ SetupDiDestroyDeviceInfoList(monitor_devinfo);
SetupDiDestroyDeviceInfoList(gpu_devinfo);
RegCloseKey(video_hkey);
if (gpus)
handler.pFreeGpus(gpus);
if (adapters)
handler.pFreeAdapters(adapters);
+ if (monitors)
+ handler.pFreeMonitors(monitors);
if (!success)
ERR("Failed to initialize display devices\n");
}
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 5d99d69eff..40392b03c0 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -690,6 +690,19 @@ struct x11drv_adapter
DWORD state_flags;
};
+/* Represent a monitor in EnumDisplayDevices context */
+struct x11drv_monitor
+{
+ /* Name */
+ WCHAR name[128];
+ /* as RcMonitor in MONITORINFO struct */
+ RECT rc_monitor;
+ /* as RcWork in MONITORINFO struct */
+ RECT rc_work;
+ /* StateFlags in DISPLAY_DEVICE struct */
+ DWORD state_flags;
+};
+
/* Required functions for display device registry initialization */
struct x11drv_display_device_handler
{
@@ -710,11 +723,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 3f6fdebb1e..49427890cb 100644
--- a/dlls/winex11.drv/xinerama.c
+++ b/dlls/winex11.drv/xinerama.c
@@ -291,6 +291,57 @@ 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 )))
+ {
+ strcpyW( monitor[index].name, generic_nonpnp_monitorW );
+ monitor[index].rc_monitor = monitors[i].rcMonitor;
+ monitor[index].rc_work = monitors[i].rcWork;
+ /* 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 +382,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
1
0