Skip to content

Instantly share code, notes, and snippets.

@rossy
Last active June 13, 2020 07:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rossy/4e2a588d4703d93b531ce9d544a11dde to your computer and use it in GitHub Desktop.
Save rossy/4e2a588d4703d93b531ce9d544a11dde to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <string.h>
#include <windows.h>
static CALLBACK DWORD discard_thread(void *arg)
{
HANDLE pipe = arg;
OVERLAPPED ol = { 0 };
ol.hEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
// Incoming messages are read into this buffer and discarded
char outbuf[128];
for (;;) {
DWORD r;
DWORD err = ReadFile(pipe, outbuf, 128, NULL, &ol) ? 0 : GetLastError();
// ERROR_IO_PENDING means GetOverlappedResult will block and wait for a
// response. If err is 0, GetOverlappedResult will return immediately.
if (err && err != ERROR_IO_PENDING)
break;
if (!GetOverlappedResult(pipe, &ol, &r, TRUE))
break;
}
CloseHandle(ol.hEvent);
return 0;
}
int main()
{
const char *command = "loadfile test.mp3\n";
const wchar_t *pipe_name = L"\\\\.\\pipe\\mpvsocket";
// If more than one program tries to open the pipe at the same time, only
// one program will be successful and the rest will get ERROR_PIPE_BUSY.
// Hence, a retry loop must be used to reliably connect to the pipe.
HANDLE pipe;
for (;;) {
pipe = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (pipe != INVALID_HANDLE_VALUE)
break;
// Abort if there was an error other than ERROR_PIPE_BUSY
if (GetLastError() != ERROR_PIPE_BUSY)
return 1;
// Abort if it takes too long for a pipe instance to become available.
// In practice, this will block for up to 50ms when waiting for a pipe
// instance, then fail if none were available.
if (!WaitNamedPipeW(pipe_name, NMPWAIT_USE_DEFAULT_WAIT))
return 1;
}
// Start a thread to read and discard pipe input, otherwise the pipe's
// input buffer will fill up and mpv will block when writing events
HANDLE thread = CreateThread(NULL, 0, discard_thread, pipe, 0, NULL);
// Write a command to the pipe every 300 milliseconds
OVERLAPPED ol = { 0 };
ol.hEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
for (;;) {
DWORD r;
DWORD err = WriteFile(pipe, command, strlen(command), NULL, &ol)
? 0 : GetLastError();
// ERROR_IO_PENDING means GetOverlappedResult must block and wait for
// the pipe to be writable before the write can be completed
if (err && err != ERROR_IO_PENDING)
break;
if (!GetOverlappedResult(pipe, &ol, &r, TRUE))
break;
Sleep(300);
}
// Wait for the read thread to finish. When mpv closes, both the read and
// write loops will exit at approximately the same time.
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
CloseHandle(pipe);
CloseHandle(ol.hEvent);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment