View Full Version : implementation to force player being single instance
stax76
15th June 2019, 15:49
I've received a feature request to mpv.net to force a single instance and replace and/or queue files to the playlist.
https://github.com/stax76/mpv.net/issues/24
How would I know that an instance is already running, I've read in the past that people use a file lock for this, does that make sense and which folder would this file be located?
Which options do I have for process communication? I guess I have to pass a single string or file, if I remember right then I need FindWindow and SendMessage, I can find stuff, only need some minor clues to ensure not going in the wrong direction. :)
I would like to keep the code being compact, fast and simple and reliable of course.
Groucho2004
15th June 2019, 16:09
Quite easy to do with the Win32 API:
::CreateMutex(NULL, TRUE, "__my__app__single__instance__lock__"); //make sure that string is unique
if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
printf("One instance of this program is already running");
return;
}
Should be easy to transpose to C#.
BTW, first hit on Google:https://stackoverflow.com/questions/34617940/single-instance-of-an-app-in-c-sharp
stax76
15th June 2019, 16:45
That looks good. :thanks:
Any suggestion on passing the playlist string?
mariush
15th June 2019, 16:59
You could make your own. Create an API and have your player listen on a tcp or udp port for commands, and have the second instance send a message to listening instance then quit
There's named pipes which may not work well with .net , there's also ways in Windows to pass messages between applications
You could easily download the source code from MPC-HC and check how it's done there.
stax76
15th June 2019, 19:57
I'll try window messages I guess, staxrip might do it that way, I don't remember it exactly.
stax76
16th June 2019, 06:04
There's named pipes which may not work well with .net
Why might it not work well in .NET? Named pipes is an ordinary WinAPI for which .NET has built-in library support.
.NET has awesome WinAPI support, both built-in library and custom C/COM interop is great.
Here is a C# project that uses named pipes:
https://github.com/stax76/wox-mpv-plugin
mpv.net has a built in command palette feature so for me the wox plugin is deprecated.
stax76
16th June 2019, 08:47
I settled to do the following:
Use a mutex to figure out if there is already a instance running.
use RegisterWindowMessage to register a unique window message
write data to registry :devil:
use SendMessage to send message to already running instance
in already running instance read and remove data from registry
LoRd_MuldeR
16th June 2019, 17:37
I settled to do the following:
Use a mutex to figure out if there is already a instance running.
use RegisterWindowMessage to register a unique window message
write data to registry :devil:
use SendMessage to send message to already running instance
in already running instance read and remove data from registry
Instead of passing data in the registry, I highly recommend you pass data (messages) in a shared memory region.
This is straightforward with CreateFileMapping() – just set hFile to INVALID_HANDLE_VALUE in order to create a memory mapping not backed by a physical file – and OpenFileMapping().
See here for some details:
https://docs.microsoft.com/en-us/windows/desktop/Memory/creating-named-shared-memory
I suggest you organize your shared memory as a ring-buffer and the "producer/consumer" model to pass messages between processes.
You will usually do that with a Mutex (https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createmutexw), to serialize all access to the shared memory, and with two Semaphores (https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createsemaphorew), one to count the "free" slots in the shared memory, one to count the "available" message.
This also eliminates the need for window messages, as the "consumer" thread simply waits on the proper Semaphore for the next incoming message to become available.
See also:
https://github.com/lordmulder/MUtilities/blob/master/src/IPCChannel.cpp (this is based on Qt's QSharedMemory, not "raw" Win32 API, but you get the idea!)
stax76
16th June 2019, 18:51
Are you sure you are not trying to overengineer this, my entire data sharing code is 5 lines and it's rock solid, the player has 6000 lines and I refuse to add much more.
https://github.com/stax76/mpv.net/blob/master/mpv.net/Misc/Program.cs#L41
https://github.com/stax76/mpv.net/blob/master/mpv.net/WinForms/MainForm.cs#L379
https://github.com/stax76/mpv.net/blob/master/mpv.net/Misc/Misc.cs#L366
Yes, I've counted megui (400% compared to staxrip) and your x264 launcher (25% compared to staxrip) lines of code in the past and I was surprised that so much code for so little features is needed.
LoRd_MuldeR
16th June 2019, 20:30
Are you sure you are not trying to overengineer this, my entire data sharing code is 5 lines and it's rock solid, the player has 6000 lines and I refuse to add much more.
Nope. Passing messages in a ring-buffer according to the "producer/consumer" model is a well-known standard pattern.
Of course, when using Win32 API, this will be a bit more verbose than with some "high level" language.
Anyway, I don't know if your implementation handles the case that n messages, each with its own separate payload (data), get sent to the "main" instance at the same time. But, for me, properly handling that case is a hard requirement. And, with the ring-buffer solution, we will be able to enqueue all those messages, as they are incoming and without blocking the sender process. Then our "main" instance will be able to properly process the enqueued messages, one by one.
stax76
16th June 2019, 21:10
Tell me as a user of a media player why and how you would start two files at the same time. :D
edit:
mpc uses wm_copydata
https://sourceforge.net/p/mpcbe/code/HEAD/tree/trunk/src/apps/mplayerc/mplayerc.cpp
mariush
17th June 2019, 00:55
select multiple files, right click, play/add to queue ... user expects filles to play one after another
or just accidental select multiple files, enter... launch 50 instances all trying read/write registry
stax76
17th June 2019, 10:53
It's not gonna end up like Chernobyl, I tried it:
Windows don't execute it for more than 15 files.
My player started in less than a second.
The playlist was alphabetically sorted.
No problem at all.
It's not making a real difference if I write this to registry, file or memory, in doubt I will always prefer simple and compact code. Chrome generates thousands of files, a angular app has 30 000 files...
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.