From 0fb136f685c21ec10943f682bec1c90220d2d90f Mon Sep 17 00:00:00 2001 From: diniamo Date: Fri, 10 Jul 2026 18:09:37 +0200 Subject: [PATCH] input/ipc-win: allow Windows handles for --input-ipc-client Previously, you could only provide a CRT FD, which works great for the most part, but when using CreateProcess on Windows, it requires the use of the reserved fields of STARTUPINFO to inherit the FD to a child mpv process. This becomes a problem for example if you use Go's os/exec API, which does not expose a way to set those reserved fields. Exposing a way to allow passing handles directly fixes the mentioned scenario, and makes --input-ipc-client more flexible at no cost. --- DOCS/man/options.rst | 8 +++++--- input/ipc-win.c | 25 ++++++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index f14254c6c6..f9f1763c05 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4555,14 +4555,16 @@ Input .. admonition:: Example ``--input-ipc-client=fd://123`` + ``--input-ipc-client=handle://123`` .. note:: To use this option on Windows, the fd must refer to a wrapped (created by ``_open_osfhandle``) named pipe server handle with a client - already connected. The named pipe must be created duplex with overlapped - IO and inheritable handles. The program communicates with mpv through - the client handle. + already connected. Alternatively, the Windows HANDLE can be passed by + prefixing it with handle:// if mpv inherited it from the parent. The + named pipe must be created duplex with overlapped IO and inheritable + handles. The program communicates with mpv through the client handle. .. warning:: diff --git a/input/ipc-win.c b/input/ipc-win.c index 5ed8347fb9..ba1544514d 100644 --- a/input/ipc-win.c +++ b/input/ipc-win.c @@ -17,6 +17,7 @@ #include #include +#include #include "osdep/io.h" #include "osdep/threads.h" @@ -471,21 +472,23 @@ struct mp_ipc_ctx *mp_init_ipc(struct mp_client_api *client_api, }; if (opts->ipc_client && opts->ipc_client[0]) { - int fd = -1; + HANDLE h = INVALID_HANDLE_VALUE; + bstr str = bstr0(opts->ipc_client); if (bstr_eatstart0(&str, "fd://") && str.len) { - long long ll = bstrtoll(str, &str, 0); - if (!str.len && ll >= 0 && ll <= INT_MAX) - fd = ll; + long long fd = bstrtoll(str, &str, 0); + if (!str.len && fd >= 0 && fd <= INT_MAX) + h = (HANDLE)_get_osfhandle(fd); + } else if (bstr_eatstart0(&str, "handle://") && str.len) { + long long handle = bstrtoll(str, &str, 0); + if (!str.len && handle >= 0 && handle <= UINT32_MAX) + h = (HANDLE)(uintptr_t)handle; } - if (fd < 0) { - MP_ERR(arg, "Invalid IPC client argument: '%s'\n", opts->ipc_client); + + if (h && h != INVALID_HANDLE_VALUE && (intptr_t)h != -2) { + ipc_start_client_json(arg, -1, h); } else { - HANDLE h = (HANDLE)_get_osfhandle(fd); - if (h && h != INVALID_HANDLE_VALUE && (intptr_t)h != -2) - ipc_start_client_json(arg, -1, h); - else - MP_ERR(arg, "Invalid IPC client fd: '%d'\n", fd); + MP_ERR(arg, "Invalid IPC client argument: '%s'\n", opts->ipc_client); } }