Added cmdline options to send start/stop/shutdown/LoadProfile/LoadTempProfile commands to a background DS4Win app via IPC messaging interface.

This commit is contained in:
mika-n 2019-07-01 02:45:55 +03:00
parent a6ed8240df
commit 1c67d6145e
2 changed files with 115 additions and 0 deletions

View File

@ -85,6 +85,9 @@ namespace DS4Windows.Forms
[DllImport("psapi.dll")] [DllImport("psapi.dll")]
private static extern uint GetModuleFileNameEx(IntPtr hWnd, IntPtr hModule, StringBuilder lpFileName, int nSize); private static extern uint GetModuleFileNameEx(IntPtr hWnd, IntPtr hModule, StringBuilder lpFileName, int nSize);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
public DS4Form(string[] args) public DS4Form(string[] args)
{ {
Global.FindConfigLocation(); Global.FindConfigLocation();
@ -386,6 +389,17 @@ namespace DS4Windows.Forms
if (!(StartMinimized || mini)) if (!(StartMinimized || mini))
Form_Resize(null, null); Form_Resize(null, null);
// Write current window class name as InterProcessCommunication identifier. The IPC classname is used in WM_DATACOPY messaging interface. .NET WinForms creates a semi-random clas names per application.
StringBuilder wndClassNameStr = new StringBuilder(256);
if (GetClassName(this.Handle, wndClassNameStr, wndClassNameStr.Capacity) != 0 && wndClassNameStr.Length > 0)
{
if (System.IO.File.Exists(appdatapath + "\\IPCClassName.dat") && System.IO.File.ReadAllText(appdatapath + "\\IPCClassName.dat") == wndClassNameStr.ToString())
wndClassNameStr.Clear(); // The wnd classname is still the same, so no need to re-write it
if(wndClassNameStr.Length > 0)
System.IO.File.WriteAllText(appdatapath + "\\IPCClassName.dat", wndClassNameStr.ToString());
}
Program.rootHub.Debug += On_Debug; Program.rootHub.Debug += On_Debug;
AppLogger.GuiLog += On_Debug; AppLogger.GuiLog += On_Debug;
@ -1137,6 +1151,51 @@ Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question
systemShutdown = true; systemShutdown = true;
break; break;
} }
case Program.WM_COPYDATA:
{
// Received InterProcessCommunication (IPC) message. Handle the requested command
Program.COPYDATASTRUCT cds = (Program.COPYDATASTRUCT)m.GetLParam(typeof(Program.COPYDATASTRUCT));
if (cds.cbData >= 4)
{
int tdevice = -1;
byte[] buffer = new byte[cds.cbData];
Marshal.Copy(cds.lpData, buffer, 0, cds.cbData);
string[] strData = Encoding.ASCII.GetString(buffer).Split('.');
if (strData.Length >= 1)
{
strData[0] = strData[0].ToLower();
if (strData[0] == "start")
ServiceStartup(true);
else if (strData[0] == "stop")
ServiceShutdown(true);
else if (strData[0] == "shutdown")
ScpForm_Closing(this, new FormClosingEventArgs(CloseReason.ApplicationExitCall, false));
else if (strData[0] == "loadprofile" && strData.Length >= 3)
{
// Command syntax: LoadProfile.device#.profileName (fex LoadProfile.1.GameSnake)
if(int.TryParse(strData[1], out tdevice)) tdevice--;
if (tdevice >= 0 && tdevice < 4)
{
ProfilePath[tdevice] = strData[2];
LoadProfile(tdevice, true, Program.rootHub);
}
}
else if (strData[0] == "loadtempprofile" && strData.Length >= 3)
{
// Command syntax: LoadTempProfile.device#.profileName (fex LoadTempProfile.1.GameSnake)
if (int.TryParse(strData[1], out tdevice)) tdevice--;
if (tdevice >= 0 && tdevice < 4)
LoadTempProfile(tdevice, strData[2], true, Program.rootHub);
}
}
}
break;
}
default: break; default: break;
} }

View File

@ -11,6 +11,22 @@ namespace DS4Windows
{ {
static class Program static class Program
{ {
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string sClass, string sWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
public const int WM_COPYDATA = 0x004A;
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
// Add "global\" in front of the EventName, then only one instance is allowed on the // Add "global\" in front of the EventName, then only one instance is allowed on the
// whole system, including other users. But the application can not be brought // whole system, including other users. But the application can not be brought
// into view, of course. // into view, of course.
@ -66,6 +82,46 @@ namespace DS4Windows
Environment.ExitCode = 0; Environment.ExitCode = 0;
return; return;
} }
else if (s == "command" || s == "-command")
{
i++;
IntPtr hWndDS4WindowsForm = IntPtr.Zero;
Global.FindConfigLocation();
if (args[i].Length > 0 && !string.IsNullOrEmpty(Global.appdatapath) && System.IO.File.Exists(Global.appdatapath + "\\IPCClassName.dat"))
{
hWndDS4WindowsForm = FindWindow(System.IO.File.ReadAllText(Global.appdatapath + "\\IPCClassName.dat"), "DS4Windows");
if (hWndDS4WindowsForm != IntPtr.Zero)
{
COPYDATASTRUCT cds;
cds.lpData = IntPtr.Zero;
try
{
cds.dwData = IntPtr.Zero;
cds.cbData = args[i].Length;
cds.lpData = Marshal.StringToHGlobalAnsi(args[i]);
SendMessage(hWndDS4WindowsForm, WM_COPYDATA, IntPtr.Zero, ref cds);
}
finally
{
if(cds.lpData != IntPtr.Zero)
Marshal.FreeHGlobal(cds.lpData);
}
}
else
{
Environment.ExitCode = 2;
}
}
else
{
Environment.ExitCode = 1;
}
return;
}
} }
try try