So I'm working on a plugin. The idea is that the plugin can run a command, and will return the output of the command as a string (rather like the 'exec' variable in Conky).
C# has a really handy little class called Process that is stunningly perfect for this and works swimmingly. (C# is also perfect because I don't know enough C++ to break an egg. I know I'll have to learn it eventually because everyone everywhere uses it, but I really hate it and would rather spend my free time learning, say, Go. But I digress.)
Anyway. Yesterday I got a little prototype working, and it was kind of exciting, except for the part where the plugin had to wait for the process to complete before returning the output. So if you ran, say, tracert, Rainmeter would hang for as long as it took to run tracert <ip>, which is rather undesirable behavior.
After some thought, it occurred to me that if the process was started by another thread, that thread could sit and wait for it to finish while the main thread kept chugging, thus keeping Rainmeter responsive. So I started to read some online about multi-threading, and my head exploded. I've managed to get to the point where I can spawn a new thread that starts the process and waits on it, and I've also got the process writing asynchronously to a StringBuilder that I can return in GetString() from the main thread (again, that Process class is a real hero). You can see what I have so far on GitHub.
The trick now is, um, stopping the thread.
This problem can be delightfully well-illustrated by running tracert through the plugin, then refreshing the skin a few times. Every refresh spawns a new thread, each thread is doing it's thing, and all of them are writing intermittently to the output string.
As such, can anyone with some multithreading experience point me to some mechanisms or a flow of control that might work here? In the end, I'd like to have the plugin run the command once on refresh (but then there's DynamicVariables. Yikes), or on demand using !CommandMeasure. The process has to be started by its own thread to keep Rainmeter from hanging, but there should only be one process thread at a time. Anyone have any suggestions on how to accomplish this? Any particular online reading I should be doing? (I've been slogging through this, and it's been very helpful, but golly is it a LOT.) I'm just really new to this, so any way to narrow down my thinking will help.
If you made it this far, thanks for reading and thanks in advance for any suggestions.
Postscript: Not distributing binaries yet since it's so rough, but if you want to build it yourself from the source on GitHub to play around with it, this is the skin I've been using to test:
C# has a really handy little class called Process that is stunningly perfect for this and works swimmingly. (C# is also perfect because I don't know enough C++ to break an egg. I know I'll have to learn it eventually because everyone everywhere uses it, but I really hate it and would rather spend my free time learning, say, Go. But I digress.)
Anyway. Yesterday I got a little prototype working, and it was kind of exciting, except for the part where the plugin had to wait for the process to complete before returning the output. So if you ran, say, tracert, Rainmeter would hang for as long as it took to run tracert <ip>, which is rather undesirable behavior.
After some thought, it occurred to me that if the process was started by another thread, that thread could sit and wait for it to finish while the main thread kept chugging, thus keeping Rainmeter responsive. So I started to read some online about multi-threading, and my head exploded. I've managed to get to the point where I can spawn a new thread that starts the process and waits on it, and I've also got the process writing asynchronously to a StringBuilder that I can return in GetString() from the main thread (again, that Process class is a real hero). You can see what I have so far on GitHub.
The trick now is, um, stopping the thread.
This problem can be delightfully well-illustrated by running tracert through the plugin, then refreshing the skin a few times. Every refresh spawns a new thread, each thread is doing it's thing, and all of them are writing intermittently to the output string.
As such, can anyone with some multithreading experience point me to some mechanisms or a flow of control that might work here? In the end, I'd like to have the plugin run the command once on refresh (but then there's DynamicVariables. Yikes), or on demand using !CommandMeasure. The process has to be started by its own thread to keep Rainmeter from hanging, but there should only be one process thread at a time. Anyone have any suggestions on how to accomplish this? Any particular online reading I should be doing? (I've been slogging through this, and it's been very helpful, but golly is it a LOT.) I'm just really new to this, so any way to narrow down my thinking will help.
If you made it this far, thanks for reading and thanks in advance for any suggestions.
Postscript: Not distributing binaries yet since it's so rough, but if you want to build it yourself from the source on GitHub to play around with it, this is the skin I've been using to test:
Code: Select all
[Rainmeter]
DynamicWindowSize=1
[Metadata]
Name=ExecTest
Author=Flying Hyrax | flyinghyrax.deviantart.com
Information=test skin for a plugin that aims to replicate the "exec" variable from conky. | Given a command and arguments, will run the command and return the console output as a string
Version=beta
License=CC BY-NC-SA 4.0
[Variables]
prog="tracert"
args="www.bbc.co.uk"
[mExec]
Measure=Plugin
Plugin="Exec.dll"
ExecFile=#prog#
Arguments=#args#
;WriteToFile="#CURRENTPATH#\output.txt"
;UpdateDivider=-1
[header]
Meter=String
X=0
Y=0
SolidColor=0,0,0,200
FontFace=Segoe UI
FontSize=12
FontColor=100,250,100
AntiAlias=1
Text="ExecTest #prog# #args#"
[string]
Meter=String
MeasureName=mExec
X=r
Y=R
SolidColor=0,0,0,200
FontFace=Lucida Console
FontSize=10
FontColor=250,250,250
AntiAlias=1
Text=%1