Changed IPC communication to use memory mapped memory instead of physical file to store the name of the DS4Form window class.

This commit is contained in:
mika-n 2019-07-03 00:02:29 +03:00
parent 75d08fe76c
commit c6daa18032
2 changed files with 64 additions and 17 deletions

View File

@ -87,9 +87,6 @@ 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)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
public DS4Form(string[] args) public DS4Form(string[] args)
{ {
Global.FindConfigLocation(); Global.FindConfigLocation();
@ -391,16 +388,7 @@ 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. Program.CreateIPCClassNameMMF(this.Handle);
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;

View File

@ -6,11 +6,16 @@ using Process = System.Diagnostics.Process;
using System.ComponentModel; using System.ComponentModel;
using System.Globalization; using System.Globalization;
using Microsoft.Win32.TaskScheduler; using Microsoft.Win32.TaskScheduler;
using System.IO.MemoryMappedFiles;
using System.Text;
namespace DS4Windows namespace DS4Windows
{ {
static class Program static class Program
{ {
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "FindWindow")] [DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string sClass, string sWindow); private static extern IntPtr FindWindow(string sClass, string sWindow);
@ -36,6 +41,9 @@ namespace DS4Windows
private static Thread controlThread; private static Thread controlThread;
private static Form ds4form; private static Form ds4form;
private static MemoryMappedFile ipcClassNameMMF = null; // MemoryMappedFile for inter-process communication used to hold className of DS4Form window
private static MemoryMappedViewAccessor ipcClassNameMMA = null;
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
@ -86,15 +94,14 @@ namespace DS4Windows
IntPtr hWndDS4WindowsForm = IntPtr.Zero; IntPtr hWndDS4WindowsForm = IntPtr.Zero;
Global.FindConfigLocation(); if (args[i].Length > 0 && args[i].Length <= 256)
if (args[i].Length > 0 && args[i].Length <= 256 && !string.IsNullOrEmpty(Global.appdatapath) && System.IO.File.Exists(Global.appdatapath + "\\IPCClassName.dat"))
{ {
// Find the main DS4Form window handle and post WM_COPYDATA inter-process message. IPCClasName.dat file was created by the main DS4Windows process // Find the main DS4Form window handle and post WM_COPYDATA inter-process message. IPCClasName.dat file was created by the main DS4Windows process
// and it contains the name of the DS4Form .NET window class name string (the hash key part of the string is dynamically generated by .NET engine and it may change, // and it contains the name of the DS4Form .NET window class name string (the hash key part of the string is dynamically generated by .NET engine and it may change,
// so that's why the main process re-creates the file if the window class name is changed by .NET framework). Finding the WND handle usig both class name and window name // so that's why the main process re-creates the file if the window class name is changed by .NET framework). Finding the WND handle usig both class name and window name
// limits chances that WM_COPYDATA message is sent to a wrong window. // limits chances that WM_COPYDATA message is sent to a wrong window.
hWndDS4WindowsForm = FindWindow(System.IO.File.ReadAllText(Global.appdatapath + "\\IPCClassName.dat"), "DS4Windows"); hWndDS4WindowsForm = FindWindow(ReadIPCClassNameMMF(), "DS4Windows");
if (hWndDS4WindowsForm != IntPtr.Zero) if (hWndDS4WindowsForm != IntPtr.Zero)
{ {
COPYDATASTRUCT cds; COPYDATASTRUCT cds;
@ -178,6 +185,9 @@ namespace DS4Windows
while (testThread.IsAlive) while (testThread.IsAlive)
Thread.SpinWait(500); Thread.SpinWait(500);
threadComEvent.Close(); threadComEvent.Close();
if (ipcClassNameMMA != null) ipcClassNameMMA.Dispose();
if (ipcClassNameMMF != null) ipcClassNameMMF.Dispose();
} }
private static void createControlService() private static void createControlService()
@ -233,5 +243,54 @@ namespace DS4Windows
temp.WindowState = FormWindowState.Normal; temp.WindowState = FormWindowState.Normal;
} }
} }
public static void CreateIPCClassNameMMF(IntPtr hWnd)
{
if (ipcClassNameMMA != null) return; // Already holding a handle to MMF file. No need to re-write the data
try
{
StringBuilder wndClassNameStr = new StringBuilder(128);
if (GetClassName(hWnd, wndClassNameStr, wndClassNameStr.Capacity) != 0 && wndClassNameStr.Length > 0)
{
byte[] buffer = ASCIIEncoding.ASCII.GetBytes(wndClassNameStr.ToString());
ipcClassNameMMF = MemoryMappedFile.CreateNew("DS4Windows_IPCClassName.dat", 128);
ipcClassNameMMA = ipcClassNameMMF.CreateViewAccessor(0, buffer.Length);
ipcClassNameMMA.WriteArray(0, buffer, 0, buffer.Length);
// The MMF file is alive as long this process holds the file handle open
}
}
catch (Exception)
{
/* Eat all exceptions because errors here are not fatal for DS4Win */
}
}
private static string ReadIPCClassNameMMF()
{
MemoryMappedFile mmf = null;
MemoryMappedViewAccessor mma = null;
try
{
byte[] buffer = new byte[128];
mmf = MemoryMappedFile.OpenExisting("DS4Windows_IPCClassName.dat");
mma = mmf.CreateViewAccessor(0, 128);
mma.ReadArray(0, buffer, 0, buffer.Length);
return ASCIIEncoding.ASCII.GetString(buffer);
}
catch (Exception)
{
// Eat all exceptions
}
finally
{
if (mma != null) mma.Dispose();
if (mmf != null) mmf.Dispose();
}
return null;
}
} }
} }