Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- 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
August 2019
- 66 participants
- 1339 messages
Re: [PATCH 4/5] httpapi/tests: Add some tests for version 2 request queues.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=56010
Your paranoid android.
=== debian10 (32 bit Japanese:Japan report) ===
httpapi:
httpapi.c:1202: Test failed: Got error 31.
httpapi.c:87: Test failed: Failed to connect socket, error 10061.
httpapi.c:1211: Test failed: send() returned -1.
httpapi.c:1215: Test failed: Got error 258.
httpapi.c:1216: Test failed: OVERLAPPED pointers didn't match.
httpapi.c:1217: Test failed: Got unexpected key 3735928559.
httpapi.c:1228: Test failed: Got error 1229.
httpapi.c:1232: Test failed: Got error 1229.
httpapi.c:1240: Test failed: Got error 2.
=== debian10 (32 bit WoW report) ===
httpapi:
httpapi.c:402: Test failed: Got error 31.
httpapi.c:87: Test failed: Failed to connect socket, error 10061.
httpapi.c:416: Test failed: send() returned -1.
httpapi.c:419: Test failed: Got 258.
httpapi.c:87: Test failed: Failed to connect socket, error 10061.
httpapi.c:425: Test failed: send() returned -1.
httpapi.c:428: Test failed: Got 258.
httpapi.c:430: Test failed: Got 258.
httpapi.c:434: Test failed: Client addresses didn't match.
Unhandled exception: page fault on read access to 0x203a6874 in 32-bit code (0xf7c28a3a).
Report errors:
httpapi:httpapi crashed (c0000005)
Aug. 30, 2019
Re: [PATCH 3/5] httpapi: Implement HttpCreateRequestQueue() and HttpCloseRequestQueue().
by Zebediah Figura
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47476
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46549
On 8/29/19 7:58 PM, Zebediah Figura wrote:
> Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
> ---
> dlls/httpapi/httpapi.spec | 2 ++
> dlls/httpapi/httpapi_main.c | 42 ++++++++++++++++++++++++++++++++++++-
> include/http.h | 5 +++++
> 3 files changed, 48 insertions(+), 1 deletion(-)
>
> diff --git a/dlls/httpapi/httpapi.spec b/dlls/httpapi/httpapi.spec
> index ae3406f44ee..e2f165c6880 100644
> --- a/dlls/httpapi/httpapi.spec
> +++ b/dlls/httpapi/httpapi.spec
> @@ -7,8 +7,10 @@
> @ stub HttpCreateConfigGroup
> @ stub HttpCreateFilter
> @ stdcall HttpCreateHttpHandle(ptr long)
> +@ stdcall HttpCreateRequestQueue(long wstr ptr long ptr)
> @ stdcall HttpCreateServerSession(long ptr long)
> @ stdcall HttpCreateUrlGroup(int64 ptr long)
> +@ stdcall HttpCloseRequestQueue(ptr)
> @ stdcall HttpCloseServerSession(int64)
> @ stdcall HttpCloseUrlGroup(int64)
> @ stub HttpDeleteConfigGroup
> diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c
> index 79497087d31..20405d9ea3e 100644
> --- a/dlls/httpapi/httpapi_main.c
> +++ b/dlls/httpapi/httpapi_main.c
> @@ -27,6 +27,8 @@
>
> WINE_DEFAULT_DEBUG_CHANNEL(httpapi);
>
> +static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','H','t','t','p','\\','R','e','q','Q','u','e','u','e',0};
> +
> static WCHAR *heap_strdupW(const WCHAR *str)
> {
> int len = wcslen(str) + 1;
> @@ -207,7 +209,6 @@ ULONG WINAPI HttpSetServiceConfiguration( HANDLE handle, HTTP_SERVICE_CONFIG_ID
> */
> ULONG WINAPI HttpCreateHttpHandle(HANDLE *handle, ULONG reserved)
> {
> - static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','H','t','t','p','\\','R','e','q','Q','u','e','u','e',0};
> OBJECT_ATTRIBUTES attr = {sizeof(attr)};
> UNICODE_STRING string;
> IO_STATUS_BLOCK iosb;
> @@ -692,3 +693,42 @@ ULONG WINAPI HttpRemoveUrlFromUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, U
>
> return ERROR_SUCCESS;
> }
> +
> +/***********************************************************************
> + * HttpCreateRequestQueue (HTTPAPI.@)
> + */
> +ULONG WINAPI HttpCreateRequestQueue(HTTPAPI_VERSION version, const WCHAR *name,
> + SECURITY_ATTRIBUTES *sa, ULONG flags, HANDLE *handle)
> +{
> + OBJECT_ATTRIBUTES attr = {sizeof(attr)};
> + UNICODE_STRING string;
> + IO_STATUS_BLOCK iosb;
> +
> + TRACE("version %u.%u, name %s, sa %p, flags %#x, handle %p.\n",
> + version.HttpApiMajorVersion, version.HttpApiMinorVersion,
> + debugstr_w(name), sa, flags, handle);
> +
> + if (name)
> + FIXME("Unhandled name %s.\n", debugstr_w(name));
> + if (flags)
> + FIXME("Unhandled flags %#x.\n", flags);
> +
> + RtlInitUnicodeString(&string, device_nameW);
> + attr.ObjectName = &string;
> + if (sa && sa->bInheritHandle)
> + attr.Attributes |= OBJ_INHERIT;
> + attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
> + return RtlNtStatusToDosError(NtCreateFile(handle, 0, &attr, &iosb, NULL,
> + FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0));
> +}
> +
> +/***********************************************************************
> + * HttpCloseRequestQueue (HTTPAPI.@)
> + */
> +ULONG WINAPI HttpCloseRequestQueue(HANDLE handle)
> +{
> + TRACE("handle %p.\n", handle);
> + if (!CloseHandle(handle))
> + return GetLastError();
> + return ERROR_SUCCESS;
> +}
> diff --git a/include/http.h b/include/http.h
> index c4bb107dd18..7586d0cbe01 100644
> --- a/include/http.h
> +++ b/include/http.h
> @@ -37,6 +37,9 @@ typedef struct _HTTPAPI_VERSION
> #define HTTPAPI_VERSION_1 {1,0}
> #define HTTPAPI_VERSION_2 {2,0}
>
> +#define HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING 0x00000001
> +#define HTTP_CREATE_REQUEST_QUEUE_FLAG_CONTROLLER 0x00000002
> +
> #define HTTP_INITIALIZE_SERVER 0x00000001
> #define HTTP_INITIALIZE_CONFIG 0x00000002
>
> @@ -426,9 +429,11 @@ typedef struct _HTTP_BINDING_INFO
>
> ULONG WINAPI HttpAddUrl(HANDLE,PCWSTR,PVOID);
> ULONG WINAPI HttpAddUrlToUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, HTTP_URL_CONTEXT context, ULONG reserved);
> +ULONG WINAPI HttpCloseRequestQueue(HANDLE handle);
> ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id);
> ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id);
> ULONG WINAPI HttpCreateHttpHandle(PHANDLE,ULONG);
> +ULONG WINAPI HttpCreateRequestQueue(HTTPAPI_VERSION version, const WCHAR *name, SECURITY_ATTRIBUTES *sa, ULONG flags, HANDLE *handle);
> ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION,PHTTP_SERVER_SESSION_ID,ULONG);
> ULONG WINAPI HttpCreateUrlGroup(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id, ULONG reserved);
> ULONG WINAPI HttpDeleteServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,LPOVERLAPPED);
>
Aug. 30, 2019
[PATCH 5/5] httpapi: Prefer the builtin version.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/httpapi/httpapi_main.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c
index 20405d9ea3e..100aac2639d 100644
--- a/dlls/httpapi/httpapi_main.c
+++ b/dlls/httpapi/httpapi_main.c
@@ -37,19 +37,6 @@ static WCHAR *heap_strdupW(const WCHAR *str)
return ret;
}
-BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID lpv )
-{
- switch(reason)
- {
- case DLL_WINE_PREATTACH:
- return FALSE; /* prefer native version */
- case DLL_PROCESS_ATTACH:
- DisableThreadLibraryCalls( hinst );
- break;
- }
- return TRUE;
-}
-
/***********************************************************************
* HttpInitialize (HTTPAPI.@)
*
--
2.22.0
Aug. 30, 2019
[PATCH 4/5] httpapi/tests: Add some tests for version 2 request queues.
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/httpapi/tests/httpapi.c | 343 ++++++++++++++++++++++++++++++++---
1 file changed, 317 insertions(+), 26 deletions(-)
diff --git a/dlls/httpapi/tests/httpapi.c b/dlls/httpapi/tests/httpapi.c
index 2153361c59c..ff5884d72a1 100644
--- a/dlls/httpapi/tests/httpapi.c
+++ b/dlls/httpapi/tests/httpapi.c
@@ -33,23 +33,37 @@
static const WCHAR localhost_urlW[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
static const WCHAR localhost_url2W[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','1','/',0};
-
-static ULONG (WINAPI *pHttpCreateServerSession)(HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *session_id,
- ULONG reserved);
+static const WCHAR invalid_url1[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
+static const WCHAR invalid_url2[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
+static const WCHAR invalid_url3[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
+static const WCHAR invalid_url4[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t','/',0};
+static const WCHAR invalid_url5[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','/',0};
+static const WCHAR invalid_url6[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','0','/',0};
+
+static ULONG (WINAPI *pHttpAddUrlToUrlGroup)(HTTP_URL_GROUP_ID id, const WCHAR *url, HTTP_URL_CONTEXT context, ULONG reserved);
+static ULONG (WINAPI *pHttpCreateServerSession)(HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *session_id, ULONG reserved);
+static ULONG (WINAPI *pHttpCreateRequestQueue)(HTTPAPI_VERSION version, const WCHAR *name, SECURITY_ATTRIBUTES *sa, ULONG flags, HANDLE *handle);
+static ULONG (WINAPI *pHttpCreateUrlGroup)(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id, ULONG reserved);
+static ULONG (WINAPI *pHttpCloseRequestQueue)(HANDLE queue);
static ULONG (WINAPI *pHttpCloseServerSession)(HTTP_SERVER_SESSION_ID session_id);
-static ULONG (WINAPI *pHttpCreateUrlGroup)(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id,
- ULONG reserved);
static ULONG (WINAPI *pHttpCloseUrlGroup)(HTTP_URL_GROUP_ID group_id);
+static ULONG (WINAPI *pHttpRemoveUrlFromUrlGroup)(HTTP_URL_GROUP_ID id, const WCHAR *url, ULONG flags);
+static ULONG (WINAPI *pHttpSetUrlGroupProperty)(HTTP_URL_GROUP_ID id, HTTP_SERVER_PROPERTY property, void *value, ULONG length);
static void init(void)
{
HMODULE mod = GetModuleHandleA("httpapi.dll");
#define X(f) p##f = (void *)GetProcAddress(mod, #f)
+ X(HttpAddUrlToUrlGroup);
+ X(HttpCreateRequestQueue);
X(HttpCreateServerSession);
- X(HttpCloseServerSession);
X(HttpCreateUrlGroup);
+ X(HttpCloseRequestQueue);
+ X(HttpCloseServerSession);
X(HttpCloseUrlGroup);
+ X(HttpRemoveUrlFromUrlGroup);
+ X(HttpSetUrlGroupProperty);
#undef X
}
@@ -92,12 +106,6 @@ static void send_response_v1(HANDLE queue, HTTP_REQUEST_ID id, int s)
static void test_v1_server(void)
{
- static const WCHAR invalid_url1[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
- static const WCHAR invalid_url2[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
- static const WCHAR invalid_url3[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
- static const WCHAR invalid_url4[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t','/',0};
- static const WCHAR invalid_url5[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','/',0};
- static const WCHAR invalid_url6[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','0','/',0};
static const WCHAR cooked_urlW[] = {'h','t','t','p',':','/','/',
'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/','f','o','o','b','a','r',0};
@@ -879,12 +887,6 @@ static void test_HttpCreateServerSession(void)
HTTPAPI_VERSION version;
ULONG ret;
- if (!pHttpCreateServerSession || !pHttpCloseServerSession)
- {
- skip("HttpCreateServerSession() is not supported.\n");
- return;
- }
-
version.HttpApiMajorVersion = 1;
version.HttpApiMinorVersion = 0;
ret = pHttpCreateServerSession(version, NULL, 0);
@@ -925,12 +927,6 @@ static void test_HttpCreateUrlGroup(void)
HTTPAPI_VERSION version;
ULONG ret;
- if (!pHttpCreateUrlGroup)
- {
- skip("HttpCreateUrlGroup is not supported.\n");
- return;
- }
-
group_id = 1;
ret = pHttpCreateUrlGroup(0, &group_id, 0);
ok(ret == ERROR_INVALID_PARAMETER, "Unexpected return value %u.\n", ret);
@@ -970,6 +966,289 @@ static void test_HttpCreateUrlGroup(void)
ok(!ret, "Unexpected return value %u.\n", ret);
}
+static void test_v2_server(void)
+{
+ static const WCHAR cooked_urlW[] = {'h','t','t','p',':','/','/',
+ 'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/','f','o','o','b','a','r',0};
+
+ char DECLSPEC_ALIGN(8) req_buffer[2048], response_buffer[2048];
+ HTTP_REQUEST_V2 *reqv2 = (HTTP_REQUEST_V2 *)req_buffer;
+ static const HTTPAPI_VERSION version = {2, 0};
+ struct sockaddr_in sockaddr, *sin;
+ HTTP_REQUEST_V1 *req = &reqv2->s;
+ HTTP_SERVER_SESSION_ID session;
+ HTTP_RESPONSE_V2 response = {};
+ HTTP_BINDING_INFO binding;
+ HTTP_URL_GROUP_ID group;
+ unsigned int i;
+ OVERLAPPED ovl;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+ int len;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+
+ ret = pHttpCreateServerSession(version, &session, 0);
+ ok(!ret, "Failed to create session, error %u.\n", ret);
+ ret = pHttpCreateUrlGroup(session, &group, 0);
+ ok(!ret, "Failed to create URL group, error %u.\n", ret);
+ ret = pHttpCreateRequestQueue(version, NULL, NULL, 0, &queue);
+ ok(!ret, "Failed to create request queue, error %u.\n", ret);
+ binding.Flags.Present = 1;
+ binding.RequestQueueHandle = queue;
+ ret = pHttpSetUrlGroupProperty(group, HttpServerBindingProperty, &binding, sizeof(binding));
+ ok(!ret, "Failed to bind request queue, error %u.\n", ret);
+
+ ret = HttpReceiveHttpRequest(NULL, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_INVALID_HANDLE, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, 0xdeadbeef, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ ret = pHttpAddUrlToUrlGroup(group, localhost_urlW, 0xdeadbeef, 0);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, invalid_url1, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, invalid_url2, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, invalid_url3, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, invalid_url4, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, invalid_url5, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, invalid_url6, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, localhost_urlW, 0xdeadbeef, 0);
+ todo_wine ok(ret == ERROR_ALREADY_EXISTS, "Got error %u.\n", ret);
+ ret = pHttpAddUrlToUrlGroup(group, localhost_url2W, 0xdeadbeef, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ len = sizeof(sockaddr);
+ ret = getsockname(s, (struct sockaddr *)&sockaddr, &len);
+ ok(ret == 0, "getsockname() failed, error %u.\n", WSAGetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, TRUE);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ Sleep(100);
+
+ ok(!req->Flags, "Got flags %#x.\n", req->Flags);
+ ok(req->ConnectionId, "Expected nonzero connection ID.\n");
+ ok(req->RequestId, "Expected nonzero connection ID.\n");
+ ok(req->UrlContext == 0xdeadbeef, "Got URL context %s.\n", wine_dbgstr_longlong(req->UrlContext));
+ ok(req->Version.MajorVersion == 1, "Got major version %u.\n", req->Version.MajorVersion);
+ ok(req->Version.MinorVersion == 1, "Got major version %u.\n", req->Version.MinorVersion);
+ ok(req->Verb == HttpVerbGET, "Got verb %u.\n", req->Verb);
+ ok(!req->UnknownVerbLength, "Got unknown verb length %u.\n", req->UnknownVerbLength);
+ ok(req->RawUrlLength == 7, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!req->pUnknownVerb, "Got unknown verb %s.\n", req->pUnknownVerb);
+ ok(!strcmp(req->pRawUrl, "/foobar"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 58, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 14, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(!req->CookedUrl.QueryStringLength, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, cooked_urlW), "Got full URL %s.\n", wine_dbgstr_w(req->CookedUrl.pFullUrl));
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host %s.\n", wine_dbgstr_w(req->CookedUrl.pHost));
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path %s.\n", wine_dbgstr_w(req->CookedUrl.pAbsPath));
+ ok(!req->CookedUrl.pQueryString, "Got query string %s.\n", wine_dbgstr_w(req->CookedUrl.pQueryString));
+ ok(!memcmp(req->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ sin = (SOCKADDR_IN *)req->Address.pLocalAddress;
+ ok(sin->sin_family == AF_INET, "Got family %u.\n", sin->sin_family);
+ ok(ntohs(sin->sin_port) == 50000, "Got wrong port %u.\n", ntohs(sin->sin_port));
+ ok(sin->sin_addr.S_un.S_addr == inet_addr("127.0.0.1"), "Got address %08x.\n", sin->sin_addr.S_un.S_addr);
+ ok(!req->Headers.UnknownHeaderCount, "Got %u unknown headers.\n", req->Headers.UnknownHeaderCount);
+ ok(!req->Headers.pUnknownHeaders, "Got unknown headers %p.\n", req->Headers.pUnknownHeaders);
+ for (i = 0; i < ARRAY_SIZE(req->Headers.KnownHeaders); ++i)
+ {
+ if (i == HttpHeaderConnection)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 10, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "keep-alive"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else if (i == HttpHeaderHost)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 15, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "localhost:50000"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else if (i == HttpHeaderUserAgent)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 4, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "WINE"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else
+ {
+ ok(!req->Headers.KnownHeaders[i].RawValueLength, "Header %#x: got length %u.\n",
+ i, req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!req->Headers.KnownHeaders[i].pRawValue, "Header %#x: got value '%s'.\n",
+ i, req->Headers.KnownHeaders[i].pRawValue);
+ }
+ }
+ ok(req->BytesReceived == strlen(simple_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(!req->EntityChunkCount, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(!req->pEntityChunks, "Got entity chunks %p.\n", req->pEntityChunks);
+ ok(!req->RawConnectionId, "Got SSL connection ID %s.\n", wine_dbgstr_longlong(req->RawConnectionId));
+ ok(!req->pSslInfo, "Got SSL info %p.\n", req->pSslInfo);
+ ok(!reqv2->RequestInfoCount, "Got request info count %u.\n", reqv2->RequestInfoCount);
+ ok(!reqv2->pRequestInfo, "Got request info %p.\n", reqv2->pRequestInfo);
+
+ response.s.StatusCode = 418;
+ response.s.pReason = "I'm a teapot";
+ response.s.ReasonLength = 12;
+ response.s.Headers.KnownHeaders[HttpHeaderRetryAfter].pRawValue = "120";
+ response.s.Headers.KnownHeaders[HttpHeaderRetryAfter].RawValueLength = 3;
+ ret = HttpSendHttpResponse(queue, 0xdeadbeef, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(ret, "Got error %u.\n", GetLastError());
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret == ret_size, "Expected size %u, got %u.\n", ret_size, ret);
+
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nRetry-After: 120\r\n"), "Missing or malformed Retry-After header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+
+ ret = HttpReceiveHttpRequest(queue, req->RequestId, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+
+ ret = pHttpRemoveUrlFromUrlGroup(group, localhost_urlW, 0);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = pHttpRemoveUrlFromUrlGroup(group, localhost_urlW, 0);
+ ok(ret == ERROR_FILE_NOT_FOUND, "Got error %u.\n", ret);
+ ret = pHttpRemoveUrlFromUrlGroup(group, localhost_url2W, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+
+ closesocket(s);
+ CloseHandle(ovl.hEvent);
+ ret = pHttpCloseRequestQueue(queue);
+ ok(!ret, "Failed to close queue handle, error %u.\n", ret);
+ ret = pHttpCloseUrlGroup(group);
+ ok(!ret, "Failed to close group, error %u.\n", ret);
+ ret = pHttpCloseServerSession(session);
+ ok(!ret, "Failed to close group, error %u.\n", ret);
+}
+
+static void test_v2_completion_port(void)
+{
+ char DECLSPEC_ALIGN(8) req_buffer[2048], response_buffer[2048];
+ HTTP_REQUEST_V2 *req = (HTTP_REQUEST_V2 *)req_buffer;
+ static const HTTPAPI_VERSION version = {2, 0};
+ HTTP_SERVER_SESSION_ID session;
+ HTTP_RESPONSE_V2 response = {};
+ HTTP_BINDING_INFO binding;
+ HTTP_URL_GROUP_ID group;
+ OVERLAPPED ovl, *povl;
+ HANDLE queue, port;
+ DWORD ret_size;
+ ULONG_PTR key;
+ ULONG ret;
+ SOCKET s;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = pHttpCreateServerSession(version, &session, 0);
+ ok(!ret, "Failed to create session, error %u.\n", ret);
+ ret = pHttpCreateUrlGroup(session, &group, 0);
+ ok(!ret, "Failed to create URL group, error %u.\n", ret);
+ ret = pHttpCreateRequestQueue(version, NULL, NULL, 0, &queue);
+ ok(!ret, "Failed to create request queue, error %u.\n", ret);
+ binding.Flags.Present = 1;
+ binding.RequestQueueHandle = queue;
+ ret = pHttpSetUrlGroupProperty(group, HttpServerBindingProperty, &binding, sizeof(binding));
+ ok(!ret, "Failed to bind request queue, error %u.\n", ret);
+
+ port = CreateIoCompletionPort(queue, NULL, 123, 0);
+ ok(!!port, "Failed to create completion port, error %u.\n", GetLastError());
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ ret = pHttpAddUrlToUrlGroup(group, localhost_urlW, 0, 0);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret_size = key = 0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 1000);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(povl == &ovl, "OVERLAPPED pointers didn't match.\n");
+ ok(key == 123, "Got unexpected key %lu.\n", key);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ response.s.StatusCode = 418;
+ response.s.pReason = "I'm a teapot";
+ response.s.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, req->s.RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret_size = key = 0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 1000);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(povl == &ovl, "OVERLAPPED pointers didn't match.\n");
+ ok(key == 123, "Got unexpected key %lu.\n", key);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret == ret_size, "Expected size %u, got %u.\n", ret_size, ret);
+
+ ret = pHttpRemoveUrlFromUrlGroup(group, localhost_urlW, 0);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ CloseHandle(port);
+ CloseHandle(ovl.hEvent);
+ ret = pHttpCloseRequestQueue(queue);
+ ok(!ret, "Failed to close queue handle, error %u.\n", ret);
+ ret = pHttpCloseUrlGroup(group);
+ ok(!ret, "Failed to close group, error %u.\n", ret);
+ ret = pHttpCloseServerSession(session);
+ ok(!ret, "Failed to close group, error %u.\n", ret);
+}
+
START_TEST(httpapi)
{
HTTPAPI_VERSION version = { 1, 0 };
@@ -991,9 +1270,21 @@ START_TEST(httpapi)
test_v1_bad_request();
test_v1_cooked_url();
test_v1_unknown_tokens();
- test_HttpCreateServerSession();
- test_HttpCreateUrlGroup();
ret = HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
ok(!ret, "Failed to terminate, ret %u.\n", ret);
+
+ version.HttpApiMajorVersion = 2;
+ if (!HttpInitialize(version, HTTP_INITIALIZE_SERVER, NULL))
+ {
+ test_HttpCreateServerSession();
+ test_HttpCreateUrlGroup();
+ test_v2_server();
+ test_v2_completion_port();
+
+ ret = HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
+ ok(!ret, "Failed to terminate, ret %u.\n", ret);
+ }
+ else
+ win_skip("Version 2 is not supported.\n");
}
--
2.22.0
Aug. 30, 2019
[PATCH 3/5] httpapi: Implement HttpCreateRequestQueue() and HttpCloseRequestQueue().
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/httpapi/httpapi.spec | 2 ++
dlls/httpapi/httpapi_main.c | 42 ++++++++++++++++++++++++++++++++++++-
include/http.h | 5 +++++
3 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/dlls/httpapi/httpapi.spec b/dlls/httpapi/httpapi.spec
index ae3406f44ee..e2f165c6880 100644
--- a/dlls/httpapi/httpapi.spec
+++ b/dlls/httpapi/httpapi.spec
@@ -7,8 +7,10 @@
@ stub HttpCreateConfigGroup
@ stub HttpCreateFilter
@ stdcall HttpCreateHttpHandle(ptr long)
+@ stdcall HttpCreateRequestQueue(long wstr ptr long ptr)
@ stdcall HttpCreateServerSession(long ptr long)
@ stdcall HttpCreateUrlGroup(int64 ptr long)
+@ stdcall HttpCloseRequestQueue(ptr)
@ stdcall HttpCloseServerSession(int64)
@ stdcall HttpCloseUrlGroup(int64)
@ stub HttpDeleteConfigGroup
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c
index 79497087d31..20405d9ea3e 100644
--- a/dlls/httpapi/httpapi_main.c
+++ b/dlls/httpapi/httpapi_main.c
@@ -27,6 +27,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(httpapi);
+static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','H','t','t','p','\\','R','e','q','Q','u','e','u','e',0};
+
static WCHAR *heap_strdupW(const WCHAR *str)
{
int len = wcslen(str) + 1;
@@ -207,7 +209,6 @@ ULONG WINAPI HttpSetServiceConfiguration( HANDLE handle, HTTP_SERVICE_CONFIG_ID
*/
ULONG WINAPI HttpCreateHttpHandle(HANDLE *handle, ULONG reserved)
{
- static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','H','t','t','p','\\','R','e','q','Q','u','e','u','e',0};
OBJECT_ATTRIBUTES attr = {sizeof(attr)};
UNICODE_STRING string;
IO_STATUS_BLOCK iosb;
@@ -692,3 +693,42 @@ ULONG WINAPI HttpRemoveUrlFromUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, U
return ERROR_SUCCESS;
}
+
+/***********************************************************************
+ * HttpCreateRequestQueue (HTTPAPI.@)
+ */
+ULONG WINAPI HttpCreateRequestQueue(HTTPAPI_VERSION version, const WCHAR *name,
+ SECURITY_ATTRIBUTES *sa, ULONG flags, HANDLE *handle)
+{
+ OBJECT_ATTRIBUTES attr = {sizeof(attr)};
+ UNICODE_STRING string;
+ IO_STATUS_BLOCK iosb;
+
+ TRACE("version %u.%u, name %s, sa %p, flags %#x, handle %p.\n",
+ version.HttpApiMajorVersion, version.HttpApiMinorVersion,
+ debugstr_w(name), sa, flags, handle);
+
+ if (name)
+ FIXME("Unhandled name %s.\n", debugstr_w(name));
+ if (flags)
+ FIXME("Unhandled flags %#x.\n", flags);
+
+ RtlInitUnicodeString(&string, device_nameW);
+ attr.ObjectName = &string;
+ if (sa && sa->bInheritHandle)
+ attr.Attributes |= OBJ_INHERIT;
+ attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
+ return RtlNtStatusToDosError(NtCreateFile(handle, 0, &attr, &iosb, NULL,
+ FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0));
+}
+
+/***********************************************************************
+ * HttpCloseRequestQueue (HTTPAPI.@)
+ */
+ULONG WINAPI HttpCloseRequestQueue(HANDLE handle)
+{
+ TRACE("handle %p.\n", handle);
+ if (!CloseHandle(handle))
+ return GetLastError();
+ return ERROR_SUCCESS;
+}
diff --git a/include/http.h b/include/http.h
index c4bb107dd18..7586d0cbe01 100644
--- a/include/http.h
+++ b/include/http.h
@@ -37,6 +37,9 @@ typedef struct _HTTPAPI_VERSION
#define HTTPAPI_VERSION_1 {1,0}
#define HTTPAPI_VERSION_2 {2,0}
+#define HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING 0x00000001
+#define HTTP_CREATE_REQUEST_QUEUE_FLAG_CONTROLLER 0x00000002
+
#define HTTP_INITIALIZE_SERVER 0x00000001
#define HTTP_INITIALIZE_CONFIG 0x00000002
@@ -426,9 +429,11 @@ typedef struct _HTTP_BINDING_INFO
ULONG WINAPI HttpAddUrl(HANDLE,PCWSTR,PVOID);
ULONG WINAPI HttpAddUrlToUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, HTTP_URL_CONTEXT context, ULONG reserved);
+ULONG WINAPI HttpCloseRequestQueue(HANDLE handle);
ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id);
ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id);
ULONG WINAPI HttpCreateHttpHandle(PHANDLE,ULONG);
+ULONG WINAPI HttpCreateRequestQueue(HTTPAPI_VERSION version, const WCHAR *name, SECURITY_ATTRIBUTES *sa, ULONG flags, HANDLE *handle);
ULONG WINAPI HttpCreateServerSession(HTTPAPI_VERSION,PHTTP_SERVER_SESSION_ID,ULONG);
ULONG WINAPI HttpCreateUrlGroup(HTTP_SERVER_SESSION_ID session_id, HTTP_URL_GROUP_ID *group_id, ULONG reserved);
ULONG WINAPI HttpDeleteServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,LPOVERLAPPED);
--
2.22.0
Aug. 30, 2019
[PATCH 2/5] httpapi: Implement HttpAddUrlToUrlGroup() and HttpRemoveUrlFromUrlGroup().
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/httpapi/httpapi.spec | 2 +
dlls/httpapi/httpapi_main.c | 87 +++++++++++++++++++++++++++++++++----
include/http.h | 2 +
3 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/dlls/httpapi/httpapi.spec b/dlls/httpapi/httpapi.spec
index b3f3148acbc..ae3406f44ee 100644
--- a/dlls/httpapi/httpapi.spec
+++ b/dlls/httpapi/httpapi.spec
@@ -1,6 +1,7 @@
@ stub HttpAddFragmentToCache
@ stdcall HttpAddUrl(ptr wstr ptr)
@ stub HttpAddUrlToConfigGroup
+@ stdcall HttpAddUrlToUrlGroup(int64 wstr int64 long)
@ stub HttpCancelHttpRequest
@ stub HttpCreateAppPool
@ stub HttpCreateConfigGroup
@@ -40,6 +41,7 @@
@ stub HttpRemoveAllUrlsFromConfigGroup
@ stdcall HttpRemoveUrl(ptr wstr)
@ stub HttpRemoveUrlFromConfigGroup
+@ stdcall HttpRemoveUrlFromUrlGroup(int64 wstr long)
@ stub HttpSendHttpRequest
@ stdcall HttpSendHttpResponse(ptr int64 long ptr ptr ptr ptr long ptr ptr)
@ stub HttpSendRequestEntityBody
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c
index 29a8e70301f..79497087d31 100644
--- a/dlls/httpapi/httpapi_main.c
+++ b/dlls/httpapi/httpapi_main.c
@@ -27,6 +27,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(httpapi);
+static WCHAR *heap_strdupW(const WCHAR *str)
+{
+ int len = wcslen(str) + 1;
+ WCHAR *ret = heap_alloc(len * sizeof(WCHAR));
+ wcscpy(ret, str);
+ return ret;
+}
+
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID lpv )
{
switch(reason)
@@ -247,21 +255,13 @@ ULONG WINAPI HttpAddUrl(HANDLE queue, const WCHAR *url, void *reserved)
return add_url(queue, url, 0);
}
-/***********************************************************************
- * HttpRemoveUrl (HTTPAPI.@)
- */
-ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *urlW)
+static ULONG remove_url(HANDLE queue, const WCHAR *urlW)
{
ULONG ret = ERROR_SUCCESS;
OVERLAPPED ovl = {};
char *url;
int len;
- TRACE("queue %p, url %s.\n", queue, debugstr_w(urlW));
-
- if (!queue)
- return ERROR_INVALID_PARAMETER;
-
len = WideCharToMultiByte(CP_ACP, 0, urlW, -1, NULL, 0, NULL, NULL);
if (!(url = heap_alloc(len)))
return ERROR_OUTOFMEMORY;
@@ -276,6 +276,19 @@ ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *urlW)
return ret;
}
+/***********************************************************************
+ * HttpRemoveUrl (HTTPAPI.@)
+ */
+ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *url)
+{
+ TRACE("queue %p, url %s.\n", queue, debugstr_w(url));
+
+ if (!queue)
+ return ERROR_INVALID_PARAMETER;
+
+ return remove_url(queue, url);
+}
+
/***********************************************************************
* HttpReceiveHttpRequest (HTTPAPI.@)
*/
@@ -475,6 +488,8 @@ struct url_group
{
struct list entry, session_entry;
HANDLE queue;
+ WCHAR *url;
+ HTTP_URL_CONTEXT context;
};
static struct list url_groups = LIST_INIT(url_groups);
@@ -621,5 +636,59 @@ ULONG WINAPI HttpSetUrlGroupProperty(HTTP_URL_GROUP_ID id, HTTP_SERVER_PROPERTY
group->queue = info->RequestQueueHandle;
+ if (group->url)
+ add_url(group->queue, group->url, group->context);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * HttpAddUrlToUrlGroup (HTTPAPI.@)
+ */
+ULONG WINAPI HttpAddUrlToUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url,
+ HTTP_URL_CONTEXT context, ULONG reserved)
+{
+ struct url_group *group = get_url_group(id);
+
+ TRACE("id %s, url %s, context %s, reserved %#x.\n", wine_dbgstr_longlong(id),
+ debugstr_w(url), wine_dbgstr_longlong(context), reserved);
+
+ if (group->url)
+ {
+ FIXME("Multiple URLs are not handled!\n");
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ if (!(group->url = heap_strdupW(url)))
+ return ERROR_OUTOFMEMORY;
+ group->context = context;
+
+ if (group->queue)
+ return add_url(group->queue, url, context);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * HttpRemoveUrlFromUrlGroup (HTTPAPI.@)
+ */
+ULONG WINAPI HttpRemoveUrlFromUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, ULONG flags)
+{
+ struct url_group *group = get_url_group(id);
+
+ TRACE("id %s, url %s, flags %#x.\n", wine_dbgstr_longlong(id), debugstr_w(url), flags);
+
+ if (!group->url)
+ return ERROR_FILE_NOT_FOUND;
+
+ if (flags)
+ FIXME("Ignoring flags %#x.\n", flags);
+
+ heap_free(group->url);
+ group->url = NULL;
+
+ if (group->queue)
+ return remove_url(group->queue, url);
+
return ERROR_SUCCESS;
}
diff --git a/include/http.h b/include/http.h
index 60494a130f9..c4bb107dd18 100644
--- a/include/http.h
+++ b/include/http.h
@@ -425,6 +425,7 @@ typedef struct _HTTP_BINDING_INFO
} HTTP_BINDING_INFO, *PHTTP_BINDING_INFO;
ULONG WINAPI HttpAddUrl(HANDLE,PCWSTR,PVOID);
+ULONG WINAPI HttpAddUrlToUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, HTTP_URL_CONTEXT context, ULONG reserved);
ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id);
ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id);
ULONG WINAPI HttpCreateHttpHandle(PHANDLE,ULONG);
@@ -436,6 +437,7 @@ ULONG WINAPI HttpTerminate(ULONG flags, void *reserved);
ULONG WINAPI HttpQueryServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,PVOID,ULONG,PULONG,LPOVERLAPPED);
ULONG WINAPI HttpReceiveHttpRequest(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, HTTP_REQUEST *request, ULONG size, ULONG *ret_size, OVERLAPPED *ovl);
ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *url);
+ULONG WINAPI HttpRemoveUrlFromUrlGroup(HTTP_URL_GROUP_ID id, const WCHAR *url, ULONG flags);
ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, HTTP_RESPONSE *response, HTTP_CACHE_POLICY *cache_policy, ULONG *ret_size, void *reserved1, ULONG reserved2, OVERLAPPED *ovl, HTTP_LOG_DATA *log_data);
ULONG WINAPI HttpSetServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,LPOVERLAPPED);
ULONG WINAPI HttpSetUrlGroupProperty(HTTP_URL_GROUP_ID id, HTTP_SERVER_PROPERTY property, void *value, ULONG length);
--
2.22.0
Aug. 30, 2019
[PATCH 1/5] httpapi: Partially implement HttpSetUrlGroupProperty().
by Zebediah Figura
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/httpapi/httpapi.spec | 1 +
dlls/httpapi/httpapi_main.c | 25 +++++++++++++++++++++++++
include/http.h | 28 ++++++++++++++++++++++++++++
3 files changed, 54 insertions(+)
diff --git a/dlls/httpapi/httpapi.spec b/dlls/httpapi/httpapi.spec
index aad5d58437c..b3f3148acbc 100644
--- a/dlls/httpapi/httpapi.spec
+++ b/dlls/httpapi/httpapi.spec
@@ -49,6 +49,7 @@
@ stub HttpSetControlChannelInformation
@ stub HttpSetServerContextInformation
@ stdcall HttpSetServiceConfiguration(ptr long ptr long ptr)
+@ stdcall HttpSetUrlGroupProperty(int64 long ptr long)
@ stub HttpShutdownAppPool
@ stub HttpShutdownFilter
@ stdcall HttpTerminate(long ptr)
diff --git a/dlls/httpapi/httpapi_main.c b/dlls/httpapi/httpapi_main.c
index c7d95c9fbad..29a8e70301f 100644
--- a/dlls/httpapi/httpapi_main.c
+++ b/dlls/httpapi/httpapi_main.c
@@ -474,6 +474,7 @@ ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags,
struct url_group
{
struct list entry, session_entry;
+ HANDLE queue;
};
static struct list url_groups = LIST_INIT(url_groups);
@@ -598,3 +599,27 @@ ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id)
return ERROR_SUCCESS;
}
+
+/***********************************************************************
+ * HttpSetUrlGroupProperty (HTTPAPI.@)
+ */
+ULONG WINAPI HttpSetUrlGroupProperty(HTTP_URL_GROUP_ID id, HTTP_SERVER_PROPERTY property, void *value, ULONG length)
+{
+ struct url_group *group = get_url_group(id);
+ const HTTP_BINDING_INFO *info = value;
+
+ TRACE("id %s, property %u, value %p, length %u.\n",
+ wine_dbgstr_longlong(id), property, value, length);
+
+ if (property != HttpServerBindingProperty)
+ {
+ FIXME("Unhandled property %u.\n", property);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ TRACE("Binding to queue %p.\n", info->RequestQueueHandle);
+
+ group->queue = info->RequestQueueHandle;
+
+ return ERROR_SUCCESS;
+}
diff --git a/include/http.h b/include/http.h
index b07c3b03f93..60494a130f9 100644
--- a/include/http.h
+++ b/include/http.h
@@ -397,6 +397,33 @@ typedef struct _HTTP_LOG_DATA
HTTP_LOG_DATA_TYPE Type;
} HTTP_LOG_DATA, *PHTTP_LOG_DATA;
+typedef enum _HTTP_SERVER_PROPERTY
+{
+ HttpServerAuthenticationProperty,
+ HttpServerLoggingProperty,
+ HttpServerQosProperty,
+ HttpServerTimeoutsProperty,
+ HttpServerQueueLengthProperty,
+ HttpServerStateProperty,
+ HttpServer503VerbosityProperty,
+ HttpServerBindingProperty,
+ HttpServerExtendedAuthenticationProperty,
+ HttpServerListenEndpointProperty,
+ HttpServerChannelBindProperty,
+ HttpServerProtectionLevelProperty,
+} HTTP_SERVER_PROPERTY, *PHTTP_SERVER_PROPERTY;
+
+typedef struct _HTTP_PROPERTY_FLAGS
+{
+ ULONG Present : 1;
+} HTTP_PROPERTY_FLAGS, *PHTTP_PROPERTY_FLAGS;
+
+typedef struct _HTTP_BINDING_INFO
+{
+ HTTP_PROPERTY_FLAGS Flags;
+ HANDLE RequestQueueHandle;
+} HTTP_BINDING_INFO, *PHTTP_BINDING_INFO;
+
ULONG WINAPI HttpAddUrl(HANDLE,PCWSTR,PVOID);
ULONG WINAPI HttpCloseServerSession(HTTP_SERVER_SESSION_ID id);
ULONG WINAPI HttpCloseUrlGroup(HTTP_URL_GROUP_ID id);
@@ -411,6 +438,7 @@ ULONG WINAPI HttpReceiveHttpRequest(HANDLE queue, HTTP_REQUEST_ID id, ULONG flag
ULONG WINAPI HttpRemoveUrl(HANDLE queue, const WCHAR *url);
ULONG WINAPI HttpSendHttpResponse(HANDLE queue, HTTP_REQUEST_ID id, ULONG flags, HTTP_RESPONSE *response, HTTP_CACHE_POLICY *cache_policy, ULONG *ret_size, void *reserved1, ULONG reserved2, OVERLAPPED *ovl, HTTP_LOG_DATA *log_data);
ULONG WINAPI HttpSetServiceConfiguration(HANDLE,HTTP_SERVICE_CONFIG_ID,PVOID,ULONG,LPOVERLAPPED);
+ULONG WINAPI HttpSetUrlGroupProperty(HTTP_URL_GROUP_ID id, HTTP_SERVER_PROPERTY property, void *value, ULONG length);
#ifdef __cplusplus
}
--
2.22.0
Aug. 30, 2019
[PATCH 6/6 resend] winemac.drv: Use generic EnumDisplayMonitors and GetMonitorInfo.
by Ken Thomases
From: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Ken Thomases <ken(a)codeweavers.com>
---
dlls/winemac.drv/cocoa_display.m | 2 +
dlls/winemac.drv/display.c | 154 ++++--------------------------
dlls/winemac.drv/macdrv_cocoa.h | 4 +
dlls/winemac.drv/winemac.drv.spec | 2 -
4 files changed, 26 insertions(+), 136 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index 0459462f06c..3863557d96a 100644
--- a/dlls/winemac.drv/cocoa_display.m
+++ b/dlls/winemac.drv/cocoa_display.m
@@ -647,6 +647,8 @@ int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** new_monitor
strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor");
monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE;
+ monitors[monitor_count].rc_monitor = displays[j].frame;
+ monitors[monitor_count].rc_work = displays[j].work_frame;
monitor_count++;
break;
}
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index 236f63d5633..cb9f1ebcab9 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -53,6 +53,9 @@ BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW
/* 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 char initial_mode_key[] = "Initial Display Mode";
static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
@@ -64,6 +67,7 @@ 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','-',
@@ -128,18 +132,6 @@ static CRITICAL_SECTION modes_section = { &critsect_debug, -1, 0, 0, 0, 0 };
static BOOL inited_original_display_mode;
-
-static inline HMONITOR display_id_to_monitor(CGDirectDisplayID display_id)
-{
- return (HMONITOR)(UINT_PTR)display_id;
-}
-
-static inline CGDirectDisplayID monitor_to_display_id(HMONITOR handle)
-{
- return (CGDirectDisplayID)(UINT_PTR)handle;
-}
-
-
static BOOL get_display_device_reg_key(char *key, unsigned len)
{
static const char display_device_guid_prop[] = "__wine_display_device_guid";
@@ -969,76 +961,6 @@ better:
return ret;
}
-
-/***********************************************************************
- * EnumDisplayMonitors (MACDRV.@)
- */
-BOOL CDECL macdrv_EnumDisplayMonitors(HDC hdc, LPRECT rect, MONITORENUMPROC proc, LPARAM lparam)
-{
- struct macdrv_display *displays;
- int num_displays;
- int i;
- BOOL ret = TRUE;
-
- TRACE("%p, %s, %p, %#lx\n", hdc, wine_dbgstr_rect(rect), proc, lparam);
-
- if (hdc)
- {
- POINT origin;
- RECT limit;
-
- if (!GetDCOrgEx(hdc, &origin)) return FALSE;
- if (GetClipBox(hdc, &limit) == ERROR) return FALSE;
-
- if (rect && !IntersectRect(&limit, &limit, rect)) return TRUE;
-
- if (macdrv_get_displays(&displays, &num_displays))
- return FALSE;
-
- for (i = 0; i < num_displays; i++)
- {
- RECT monrect = rect_from_cgrect(displays[i].frame);
- OffsetRect(&monrect, -origin.x, -origin.y);
- if (IntersectRect(&monrect, &monrect, &limit))
- {
- HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
- TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
- if (!proc(monitor, hdc, &monrect, lparam))
- {
- ret = FALSE;
- break;
- }
- }
- }
- }
- else
- {
- if (macdrv_get_displays(&displays, &num_displays))
- return FALSE;
-
- for (i = 0; i < num_displays; i++)
- {
- RECT monrect = rect_from_cgrect(displays[i].frame);
- RECT unused;
- if (!rect || IntersectRect(&unused, &monrect, rect))
- {
- HMONITOR monitor = display_id_to_monitor(displays[i].displayID);
- TRACE("monitor %d handle %p @ %s\n", i, monitor, wine_dbgstr_rect(&monrect));
- if (!proc(monitor, 0, &monrect, lparam))
- {
- ret = FALSE;
- break;
- }
- }
- }
- }
-
- macdrv_free_displays(displays);
-
- return ret;
-}
-
-
/***********************************************************************
* EnumDisplaySettingsEx (MACDRV.@)
*
@@ -1323,58 +1245,6 @@ done:
return ret;
}
-
-/***********************************************************************
- * GetMonitorInfo (MACDRV.@)
- */
-BOOL CDECL macdrv_GetMonitorInfo(HMONITOR monitor, LPMONITORINFO info)
-{
- static const WCHAR adapter_name[] = { '\\','\\','.','\\','D','I','S','P','L','A','Y','1',0 };
- struct macdrv_display *displays;
- int num_displays;
- CGDirectDisplayID display_id;
- int i;
-
- TRACE("%p, %p\n", monitor, info);
-
- if (macdrv_get_displays(&displays, &num_displays))
- {
- ERR("couldn't get display list\n");
- SetLastError(ERROR_GEN_FAILURE);
- return FALSE;
- }
-
- display_id = monitor_to_display_id(monitor);
- for (i = 0; i < num_displays; i++)
- {
- if (displays[i].displayID == display_id)
- break;
- }
-
- if (i < num_displays)
- {
- info->rcMonitor = rect_from_cgrect(displays[i].frame);
- info->rcWork = rect_from_cgrect(displays[i].work_frame);
-
- info->dwFlags = (i == 0) ? MONITORINFOF_PRIMARY : 0;
-
- if (info->cbSize >= sizeof(MONITORINFOEXW))
- lstrcpyW(((MONITORINFOEXW*)info)->szDevice, adapter_name);
-
- TRACE(" -> rcMonitor %s rcWork %s dwFlags %08x\n", wine_dbgstr_rect(&info->rcMonitor),
- wine_dbgstr_rect(&info->rcWork), info->dwFlags);
- }
- else
- {
- ERR("invalid monitor handle\n");
- SetLastError(ERROR_INVALID_HANDLE);
- }
-
- macdrv_free_displays(displays);
- return (i < num_displays);
-}
-
-
/***********************************************************************
* SetDeviceGammaRamp (MACDRV.@)
*/
@@ -1640,6 +1510,7 @@ static BOOL macdrv_init_monitor(HDEVINFO devinfo, const struct macdrv_monitor *m
WCHAR nameW[MAX_PATH];
WCHAR bufferW[MAX_PATH];
HKEY hkey;
+ RECT rect;
BOOL ret = FALSE;
/* Create GUID_DEVCLASS_MONITOR instance */
@@ -1664,6 +1535,21 @@ static BOOL macdrv_init_monitor(HDEVINFO devinfo, const struct macdrv_monitor *m
if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, DEVPROP_TYPE_UINT32,
(const BYTE *)&monitor->state_flags, sizeof(monitor->state_flags), 0))
goto done;
+ /* RcMonitor */
+ rect = rect_from_cgrect(monitor->rc_monitor);
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, DEVPROP_TYPE_BINARY,
+ (const BYTE *)&rect, sizeof(rect), 0))
+ goto done;
+ /* RcWork */
+ rect = rect_from_cgrect(monitor->rc_work);
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, DEVPROP_TYPE_BINARY,
+ (const BYTE *)&rect, sizeof(rect), 0))
+ goto done;
+ /* Adapter name */
+ sprintfW(bufferW, adapter_name_fmtW, video_index + 1);
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, DEVPROP_TYPE_STRING,
+ (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR), 0))
+ goto done;
ret = TRUE;
done:
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index 96ebb97e764..676adb435bb 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -293,6 +293,10 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
{
/* Name, in UTF-8 encoding */
char name[128];
+ /* as RcMonitor in MONITORINFO struct after conversion by rect_from_cgrect */
+ CGRect rc_monitor;
+ /* as RcWork in MONITORINFO struct after conversion by rect_from_cgrect */
+ CGRect rc_work;
/* StateFlags in DISPLAY_DEVICE struct */
uint32_t state_flags;
};
diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec
index 6fa723a6904..39cf33370b4 100644
--- a/dlls/winemac.drv/winemac.drv.spec
+++ b/dlls/winemac.drv/winemac.drv.spec
@@ -12,14 +12,12 @@
@ cdecl CreateWindow(long) macdrv_CreateWindow
@ cdecl DestroyCursorIcon(long) macdrv_DestroyCursorIcon
@ cdecl DestroyWindow(long) macdrv_DestroyWindow
-@ cdecl EnumDisplayMonitors(long ptr ptr long) macdrv_EnumDisplayMonitors
@ cdecl EnumDisplaySettingsEx(ptr long ptr long) macdrv_EnumDisplaySettingsEx
@ cdecl GetCursorPos(ptr) macdrv_GetCursorPos
@ cdecl GetKeyboardLayout(long) macdrv_GetKeyboardLayout
@ cdecl GetKeyboardLayoutList(long ptr) macdrv_GetKeyboardLayoutList
@ cdecl GetKeyboardLayoutName(ptr) macdrv_GetKeyboardLayoutName
@ cdecl GetKeyNameText(long ptr long) macdrv_GetKeyNameText
-@ cdecl GetMonitorInfo(long ptr) macdrv_GetMonitorInfo
@ cdecl MapVirtualKeyEx(long long long) macdrv_MapVirtualKeyEx
@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) macdrv_MsgWaitForMultipleObjectsEx
@ cdecl RegisterHotKey(long long long) macdrv_RegisterHotKey
--
2.21.0
Aug. 29, 2019
[PATCH 5/6 resend] winemac.drv: Handle display device change events.
by Ken Thomases
From: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Ken Thomases <ken(a)codeweavers.com>
---
dlls/winemac.drv/display.c | 8 ++++++--
dlls/winemac.drv/macdrv.h | 2 +-
dlls/winemac.drv/macdrv_main.c | 2 +-
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index a953e0c5746..236f63d5633 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -946,6 +946,8 @@ better:
SendMessageW(GetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
MAKELPARAM(width, height));
ret = DISP_CHANGE_SUCCESSFUL;
+
+ macdrv_init_display_devices(TRUE);
}
else
{
@@ -1452,6 +1454,8 @@ void macdrv_displays_changed(const macdrv_event *event)
free_display_mode_descriptor(desc);
CGDisplayModeRelease(mode);
+ macdrv_init_display_devices(TRUE);
+
if (is_original && retina_enabled)
{
width *= 2;
@@ -1728,7 +1732,7 @@ static void cleanup_devices(void)
*
* Initialize display device registry data.
*/
-void macdrv_init_display_devices(void)
+void macdrv_init_display_devices(BOOL force)
{
static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
HANDLE mutex;
@@ -1755,7 +1759,7 @@ void macdrv_init_display_devices(void)
}
/* Avoid unnecessary reinit */
- if (disposition != REG_CREATED_NEW_KEY)
+ if (!force && disposition != REG_CREATED_NEW_KEY)
goto done;
TRACE("\n");
diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h
index b9f58b90da7..a7c0b4cac87 100644
--- a/dlls/winemac.drv/macdrv.h
+++ b/dlls/winemac.drv/macdrv.h
@@ -223,7 +223,7 @@ extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP
extern void macdrv_status_item_mouse_move(const macdrv_event *event) DECLSPEC_HIDDEN;
extern void check_retina_status(void) DECLSPEC_HIDDEN;
-extern void macdrv_init_display_devices(void) DECLSPEC_HIDDEN;
+extern void macdrv_init_display_devices(BOOL force) DECLSPEC_HIDDEN;
/**************************************************************************
* Mac IME driver
diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c
index 038578491f2..694a46b11e6 100644
--- a/dlls/winemac.drv/macdrv_main.c
+++ b/dlls/winemac.drv/macdrv_main.c
@@ -299,7 +299,7 @@ static BOOL process_attach(void)
return FALSE;
}
- macdrv_init_display_devices();
+ macdrv_init_display_devices(FALSE);
return TRUE;
}
--
2.21.0
Aug. 29, 2019
[PATCH 4/6 v3] winemac.drv: Add monitor initialization functions.
by Ken Thomases
From: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
Signed-off-by: Ken Thomases <ken(a)codeweavers.com>
---
v3: Fix which variable is used to index into which array.
Stop checking displays after finding a match.
Take advantage of the fact that the primary display is always index 0 in
the array returned from macdrv_get_displays().
dlls/winemac.drv/cocoa_display.m | 109 +++++++++++++++++++++++++++++++
dlls/winemac.drv/display.c | 103 +++++++++++++++++++++++++++--
dlls/winemac.drv/macdrv_cocoa.h | 14 ++++
dlls/winemac.drv/macdrv_main.c | 2 +
4 files changed, 223 insertions(+), 5 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m
index 284ffe0a535..0459462f06c 100644
--- a/dlls/winemac.drv/cocoa_display.m
+++ b/dlls/winemac.drv/cocoa_display.m
@@ -575,3 +575,112 @@ void macdrv_free_adapters(struct macdrv_adapter* adapters)
if (adapters)
free(adapters);
}
+
+/***********************************************************************
+ * macdrv_get_monitors
+ *
+ * Get a list of monitors under adapter_id. The first monitor is primary if adapter is primary.
+ * Call macdrv_free_monitors() when you are done using the data.
+ *
+ * Returns non-zero value on failure with parameters unchanged and zero on success.
+ */
+int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** new_monitors, int* count)
+{
+ struct macdrv_monitor* monitors = NULL;
+ struct macdrv_monitor* realloc_monitors;
+ struct macdrv_display* displays = NULL;
+ CGDirectDisplayID display_ids[16];
+ uint32_t display_id_count;
+ int primary_index = 0;
+ int monitor_count = 0;
+ int display_count;
+ int capacity;
+ int ret = -1;
+ int i, j;
+
+ /* 2 should be enough for most cases */
+ capacity = 2;
+ monitors = calloc(capacity, sizeof(*monitors));
+ if (!monitors)
+ return -1;
+
+ /* Report an inactive monitor */
+ if (!CGDisplayIsActive(adapter_id) && !CGDisplayIsInMirrorSet(adapter_id))
+ {
+ strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor");
+ monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
+ monitor_count++;
+ }
+ /* Report active and mirrored monitors in the same mirroring set */
+ else
+ {
+ if (CGGetOnlineDisplayList(sizeof(display_ids) / sizeof(display_ids[0]), display_ids, &display_id_count)
+ != kCGErrorSuccess)
+ goto done;
+
+ if (macdrv_get_displays(&displays, &display_count))
+ goto done;
+
+ for (i = 0; i < display_id_count; i++)
+ {
+ if (display_ids[i] != adapter_id && CGDisplayMirrorsDisplay(display_ids[i]) != adapter_id)
+ continue;
+
+ /* Find and fill in monitor info */
+ for (j = 0; j < display_count; j++)
+ {
+ if (displays[j].displayID == display_ids[i]
+ || CGDisplayMirrorsDisplay(display_ids[i]) == displays[j].displayID)
+ {
+ /* Allocate more space if needed */
+ if (monitor_count >= capacity)
+ {
+ capacity *= 2;
+ realloc_monitors = realloc(monitors, sizeof(*monitors) * capacity);
+ if (!realloc_monitors)
+ goto done;
+ monitors = realloc_monitors;
+ }
+
+ if (j == 0)
+ primary_index = monitor_count;
+
+ strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor");
+ monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE;
+ monitor_count++;
+ break;
+ }
+ }
+ }
+
+ /* Make sure the first monitor on primary adapter is primary */
+ if (primary_index)
+ {
+ struct macdrv_monitor tmp;
+ tmp = monitors[0];
+ monitors[0] = monitors[primary_index];
+ monitors[primary_index] = tmp;
+ }
+ }
+
+ *new_monitors = monitors;
+ *count = monitor_count;
+ ret = 0;
+done:
+ if (displays)
+ macdrv_free_displays(displays);
+ if (ret)
+ macdrv_free_monitors(monitors);
+ return ret;
+}
+
+/***********************************************************************
+ * macdrv_free_monitors
+ *
+ * Frees an monitor list allocated from macdrv_get_monitors()
+ */
+void macdrv_free_monitors(struct macdrv_monitor* monitors)
+{
+ if (monitors)
+ free(monitors);
+}
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index 97ebca22e57..a953e0c5746 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -51,15 +51,19 @@ struct display_mode_descriptor
BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags);
+/* Wine specific monitor properties */
+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
static const char initial_mode_key[] = "Initial Display Mode";
static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
static const WCHAR driver_date_dataW[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0};
static const WCHAR pciW[] = {'P','C','I',0};
static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
static const WCHAR symbolic_link_valueW[]= {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
+static const WCHAR mointor_id_fmtW[] = {'M','o','n','i','t','o','r','I','D','%','d',0};
static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
static const WCHAR guid_fmtW[] = {
'{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
@@ -101,6 +105,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 CFArrayRef modes;
@@ -1544,7 +1555,7 @@ done:
*
* Return FALSE on failure and TRUE on success.
*/
-static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index,
+static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index, int adapter_index, int monitor_count,
const struct macdrv_gpu *gpu, const WCHAR *guid_string, const WCHAR *gpu_driver,
const struct macdrv_adapter *adapter)
{
@@ -1554,6 +1565,7 @@ static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index,
HKEY hkey = NULL;
BOOL ret = FALSE;
LSTATUS ls;
+ INT i;
sprintfW(key_nameW, device_video_fmtW, video_index);
lstrcpyW(bufferW, machine_prefixW);
@@ -1588,6 +1600,15 @@ static BOOL macdrv_init_adapter(HKEY video_hkey, int video_index, int gpu_index,
if (RegSetValueExW(hkey, gpu_idW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
+ /* Write all monitor instances paths under this adapter */
+ for (i = 0; i < monitor_count; i++)
+ {
+ sprintfW(key_nameW, mointor_id_fmtW, i);
+ sprintfW(bufferW, monitor_instance_fmtW, video_index, i);
+ if (RegSetValueExW(hkey, key_nameW, 0, REG_SZ, (const BYTE *)bufferW, (lstrlenW(bufferW) + 1) * sizeof(WCHAR)))
+ goto done;
+ }
+
/* Write StateFlags */
if (RegSetValueExW(hkey, state_flagsW, 0, REG_DWORD, (const BYTE *)&adapter->state_flags,
sizeof(adapter->state_flags)))
@@ -1601,6 +1622,52 @@ done:
return ret;
}
+/***********************************************************************
+ * macdrv_init_monitor
+ *
+ * Initialize an monitor.
+ *
+ * Return FALSE on failure and TRUE on success.
+ */
+static BOOL macdrv_init_monitor(HDEVINFO devinfo, const struct macdrv_monitor *monitor, int monitor_index,
+ int video_index)
+{
+ SP_DEVINFO_DATA device_data = {sizeof(SP_DEVINFO_DATA)};
+ WCHAR nameW[MAX_PATH];
+ WCHAR bufferW[MAX_PATH];
+ HKEY hkey;
+ BOOL ret = FALSE;
+
+ /* Create GUID_DEVCLASS_MONITOR instance */
+ sprintfW(bufferW, monitor_instance_fmtW, video_index, monitor_index);
+ MultiByteToWideChar(CP_UTF8, 0, monitor->name, -1, nameW, ARRAY_SIZE(nameW));
+ SetupDiCreateDeviceInfoW(devinfo, bufferW, &GUID_DEVCLASS_MONITOR, nameW, NULL, 0, &device_data);
+ if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
+ goto done;
+
+ /* Write HardwareID registry property */
+ if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID,
+ (const BYTE *)monitor_hardware_idW, sizeof(monitor_hardware_idW)))
+ goto done;
+
+ /* Create driver key */
+ hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+ RegCloseKey(hkey);
+
+ /* FIXME:
+ * Following properties are Wine specific, see comments in macdrv_init_adapter for details */
+ /* StateFlags */
+ if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, DEVPROP_TYPE_UINT32,
+ (const BYTE *)&monitor->state_flags, sizeof(monitor->state_flags), 0))
+ goto done;
+
+ ret = TRUE;
+done:
+ if (!ret)
+ ERR("Failed to initialize monitor\n");
+ return ret;
+}
+
static void prepare_devices(HKEY video_hkey)
{
static const BOOL not_present = FALSE;
@@ -1608,6 +1675,15 @@ static void prepare_devices(HKEY video_hkey)
HDEVINFO devinfo;
DWORD i = 0;
+ /* Remove all monitors */
+ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, 0);
+ while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
+ {
+ if (!SetupDiRemoveDevice(devinfo, &device_data))
+ ERR("Failed to remove monitor\n");
+ }
+ SetupDiDestroyDeviceInfoList(devinfo);
+
/* Clean up old adapter keys for reinitialization */
RegDeleteTreeW(video_hkey, NULL);
@@ -1616,6 +1692,7 @@ static void prepare_devices(HKEY video_hkey)
* case application uses SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
* of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
* the same GUID for the same GPU. */
+ i = 0;
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, pciW, NULL, 0);
while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
{
@@ -1657,9 +1734,10 @@ void macdrv_init_display_devices(void)
HANDLE mutex;
struct macdrv_gpu *gpus = NULL;
struct macdrv_adapter *adapters = NULL;
- INT gpu_count, adapter_count;
- INT gpu, adapter;
- HDEVINFO gpu_devinfo = NULL;
+ struct macdrv_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;
@@ -1685,6 +1763,7 @@ void macdrv_init_display_devices(void)
prepare_devices(video_hkey);
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+ monitor_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_MONITOR, NULL);
/* Initialize GPUs */
if (macdrv_get_gpus(&gpus, &gpu_count))
@@ -1701,10 +1780,22 @@ void macdrv_init_display_devices(void)
for (adapter = 0; adapter < adapter_count; adapter++)
{
- if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, &gpus[gpu], guidW, driverW,
+ if (macdrv_get_monitors(adapters[adapter].id, &monitors, &monitor_count))
+ goto done;
+
+ if (!macdrv_init_adapter(video_hkey, video_index, gpu, adapter, monitor_count, &gpus[gpu], guidW, driverW,
&adapters[adapter]))
goto done;
+ /* Initialize monitors */
+ for (monitor = 0; monitor < monitor_count; monitor++)
+ {
+ if (!macdrv_init_monitor(monitor_devinfo, &monitors[monitor], monitor, video_index))
+ goto done;
+ }
+
+ macdrv_free_monitors(monitors);
+ monitors = NULL;
video_index++;
}
@@ -1714,6 +1805,7 @@ void macdrv_init_display_devices(void)
done:
cleanup_devices();
+ SetupDiDestroyDeviceInfoList(monitor_devinfo);
SetupDiDestroyDeviceInfoList(gpu_devinfo);
RegCloseKey(video_hkey);
@@ -1722,4 +1814,5 @@ done:
macdrv_free_gpus(gpus);
macdrv_free_adapters(adapters);
+ macdrv_free_monitors(monitors);
}
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index b960e902e3f..96ebb97e764 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -261,6 +261,9 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
/* Used DISPLAY_DEVICE.StateFlags for adapters */
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
+/* Used DISPLAY_DEVICE.StateFlags for monitors */
+#define DISPLAY_DEVICE_ACTIVE 0x00000001
+#define DISPLAY_DEVICE_ATTACHED 0x00000002
/* Represent a physical GPU in the PCI slots */
struct macdrv_gpu
@@ -285,6 +288,15 @@ static inline CGPoint cgpoint_win_from_mac(CGPoint point)
uint32_t state_flags;
};
+/* Represent a monitor in EnumDisplayDevices context */
+struct macdrv_monitor
+{
+ /* Name, in UTF-8 encoding */
+ char name[128];
+ /* StateFlags in DISPLAY_DEVICE struct */
+ uint32_t state_flags;
+};
+
extern int macdrv_get_displays(struct macdrv_display** displays, int* count) DECLSPEC_HIDDEN;
extern void macdrv_free_displays(struct macdrv_display* displays) DECLSPEC_HIDDEN;
extern int macdrv_set_display_mode(const struct macdrv_display* display,
@@ -293,6 +305,8 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
extern void macdrv_free_gpus(struct macdrv_gpu* gpus) DECLSPEC_HIDDEN;
extern int macdrv_get_adapters(uint64_t gpu_id, struct macdrv_adapter** adapters, int* count) DECLSPEC_HIDDEN;
extern void macdrv_free_adapters(struct macdrv_adapter* adapters) DECLSPEC_HIDDEN;
+extern int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** monitors, int* count) DECLSPEC_HIDDEN;
+extern void macdrv_free_monitors(struct macdrv_monitor* monitors) DECLSPEC_HIDDEN;
/* event */
diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c
index 544d448f9fa..038578491f2 100644
--- a/dlls/winemac.drv/macdrv_main.c
+++ b/dlls/winemac.drv/macdrv_main.c
@@ -299,6 +299,8 @@ static BOOL process_attach(void)
return FALSE;
}
+ macdrv_init_display_devices();
+
return TRUE;
}
--
2.21.0
Aug. 29, 2019