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.
This commit is contained in:
diniamo authored and Kacper Michajłow committed 2026-07-23 22:06:04 +02:00
1 parent 6f6c29b0b4
commit 0fb136f685
2 files changed
+19 -14

No files matched your search

+5 -3
View File
@@ -4555,14 +4555,16 @@ Input
.. admonition:: Example .. admonition:: Example
``--input-ipc-client=fd://123`` ``--input-ipc-client=fd://123``
``--input-ipc-client=handle://123``
.. note:: .. note::
To use this option on Windows, the fd must refer to a wrapped To use this option on Windows, the fd must refer to a wrapped
(created by ``_open_osfhandle``) named pipe server handle with a client (created by ``_open_osfhandle``) named pipe server handle with a client
already connected. The named pipe must be created duplex with overlapped already connected. Alternatively, the Windows HANDLE can be passed by
IO and inheritable handles. The program communicates with mpv through prefixing it with handle:// if mpv inherited it from the parent. The
the client handle. named pipe must be created duplex with overlapped IO and inheritable
handles. The program communicates with mpv through the client handle.
.. warning:: .. warning::
+14 -11
View File
@@ -17,6 +17,7 @@
#include <windows.h> #include <windows.h>
#include <sddl.h> #include <sddl.h>
#include <stdint.h>
#include "osdep/io.h" #include "osdep/io.h"
#include "osdep/threads.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]) { if (opts->ipc_client && opts->ipc_client[0]) {
int fd = -1; HANDLE h = INVALID_HANDLE_VALUE;
bstr str = bstr0(opts->ipc_client); bstr str = bstr0(opts->ipc_client);
if (bstr_eatstart0(&str, "fd://") && str.len) { if (bstr_eatstart0(&str, "fd://") && str.len) {
long long ll = bstrtoll(str, &str, 0); long long fd = bstrtoll(str, &str, 0);
if (!str.len && ll >= 0 && ll <= INT_MAX) if (!str.len && fd >= 0 && fd <= INT_MAX)
fd = ll; 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 { } else {
HANDLE h = (HANDLE)_get_osfhandle(fd); 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
MP_ERR(arg, "Invalid IPC client fd: '%d'\n", fd);
} }
} }