diff --git a/player/lua.c b/player/lua.c
index 08c2b10445..9ffd28fbaa 100644
--- a/player/lua.c
+++ b/player/lua.c
@@ -15,6 +15,11 @@
* with mpv. If not, see .
*/
+#ifdef __MINGW32__
+#define _WIN32_WINNT 0x0600
+#include
+#endif
+
#include
#include
#include
@@ -25,6 +30,7 @@
#include
#include "osdep/io.h"
+#include "osdep/atomics.h"
#include
#include
@@ -1174,10 +1180,6 @@ static int script_join_path(lua_State *L)
typedef void (*read_cb)(void *ctx, char *data, size_t size);
#ifdef __MINGW32__
-#include
-#include "osdep/io.h"
-#include "osdep/atomics.h"
-
static void write_arg(bstr *cmdline, char *arg)
{
// If the string doesn't have characters that need to be escaped, it's best
@@ -1277,6 +1279,65 @@ error:
return -1;
}
+static void delete_handle_list(void *p)
+{
+ LPPROC_THREAD_ATTRIBUTE_LIST list = p;
+ VOID (WINAPI *pDeleteProcThreadAttributeList)(LPPROC_THREAD_ATTRIBUTE_LIST);
+
+ HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
+ pDeleteProcThreadAttributeList =
+ (VOID (WINAPI*)(LPPROC_THREAD_ATTRIBUTE_LIST))
+ GetProcAddress(kernel32, "DeleteProcThreadAttributeList");
+
+ if (pDeleteProcThreadAttributeList)
+ pDeleteProcThreadAttributeList(list);
+}
+
+// Create a PROC_THREAD_ATTRIBUTE_LIST that specifies exactly which handles are
+// inherited by the subprocess
+static LPPROC_THREAD_ATTRIBUTE_LIST create_handle_list(void *ctx,
+ HANDLE *handles, int num)
+{
+ WINBOOL (WINAPI *pInitializeProcThreadAttributeList)(
+ LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD, PSIZE_T);
+ WINBOOL (WINAPI *pUpdateProcThreadAttribute)(LPPROC_THREAD_ATTRIBUTE_LIST,
+ DWORD, DWORD_PTR, PVOID, SIZE_T, PVOID, PSIZE_T);
+
+ // Load Windows Vista functions, if available
+ HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
+ pInitializeProcThreadAttributeList =
+ (WINBOOL (WINAPI*)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD, PSIZE_T))
+ GetProcAddress(kernel32, "InitializeProcThreadAttributeList");
+ pUpdateProcThreadAttribute =
+ (WINBOOL (WINAPI*)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD_PTR,
+ PVOID, SIZE_T, PVOID, PSIZE_T))
+ GetProcAddress(kernel32, "UpdateProcThreadAttribute");
+ if (!pInitializeProcThreadAttributeList || !pUpdateProcThreadAttribute)
+ return NULL;
+
+ // Get required attribute list size
+ SIZE_T size = 0;
+ if (!pInitializeProcThreadAttributeList(NULL, 1, 0, &size)) {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return NULL;
+ }
+
+ // Allocate attribute list
+ LPPROC_THREAD_ATTRIBUTE_LIST list = talloc_size(ctx, size);
+ if (!pInitializeProcThreadAttributeList(list, 1, 0, &size))
+ goto error;
+ talloc_set_destructor(list, delete_handle_list);
+
+ if (!pUpdateProcThreadAttribute(list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ handles, num * sizeof(HANDLE), NULL, NULL))
+ goto error;
+
+ return list;
+error:
+ talloc_free(list);
+ return NULL;
+}
+
// Helper method similar to sparse_poll, skips NULL handles
static int sparse_wait(HANDLE *handles, unsigned num_handles)
{
@@ -1345,14 +1406,28 @@ static int subprocess(char **args, struct mp_cancel *cancel, void *ctx,
DWORD flags = CREATE_UNICODE_ENVIRONMENT;
PROCESS_INFORMATION pi = {0};
- STARTUPINFOW si = {
- .cb = sizeof(si),
- .dwFlags = STARTF_USESTDHANDLES,
- .hStdInput = NULL,
- .hStdOutput = pipes[0].write,
- .hStdError = pipes[1].write,
+ STARTUPINFOEXW si = {
+ .StartupInfo = {
+ .cb = sizeof(si),
+ .dwFlags = STARTF_USESTDHANDLES,
+ .hStdInput = NULL,
+ .hStdOutput = pipes[0].write,
+ .hStdError = pipes[1].write,
+ },
+
+ // Specify which handles are inherited by the subprocess. If this isn't
+ // specified, the subprocess inherits all inheritable handles, which
+ // could include handles created by other threads. See:
+ // http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx
+ .lpAttributeList = create_handle_list(tmp,
+ (HANDLE[]){ pipes[0].write, pipes[1].write }, 2),
};
+ // PROC_THREAD_ATTRIBUTE_LISTs are only supported in Vista and up. If not
+ // supported, create_handle_list will return NULL.
+ if (si.lpAttributeList)
+ flags |= EXTENDED_STARTUPINFO_PRESENT;
+
// If we have a console, the subprocess will automatically attach to it so
// it can receive Ctrl+C events. If we don't have a console, prevent the
// subprocess from creating its own console window by specifying
@@ -1362,9 +1437,10 @@ static int subprocess(char **args, struct mp_cancel *cancel, void *ctx,
flags |= CREATE_NO_WINDOW;
if (!CreateProcessW(NULL, cmdline, NULL, NULL, TRUE, flags, NULL, NULL,
- &si, &pi))
+ &si.StartupInfo, &pi))
goto done;
talloc_free(cmdline);
+ talloc_free(si.lpAttributeList);
CloseHandle(pi.hThread);
// Init is finished