Last active
June 13, 2020 07:55
-
-
Save rossy/4e2a588d4703d93b531ce9d544a11dde to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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