diff --git a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs
index 11b3e4a..1bd18e7 100644
--- a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs
+++ b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.Designer.cs
@@ -28,6 +28,7 @@
///
private void InitializeComponent()
{
+ this.components = new System.ComponentModel.Container();
this.txtPath = new System.Windows.Forms.TextBox();
this.lblPathTag = new System.Windows.Forms.Label();
this.btnChoosePath = new System.Windows.Forms.Button();
@@ -38,6 +39,8 @@
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
+ this.button1 = new System.Windows.Forms.Button();
+ this.mutexHandleCloseTimer = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.startNum)).BeginInit();
this.SuspendLayout();
//
@@ -94,7 +97,7 @@
0,
0});
this.startNum.Minimum = new decimal(new int[] {
- 2,
+ 1,
0,
0,
0});
@@ -102,7 +105,7 @@
this.startNum.Size = new System.Drawing.Size(55, 21);
this.startNum.TabIndex = 12;
this.startNum.Value = new decimal(new int[] {
- 2,
+ 1,
0,
0,
0});
@@ -146,11 +149,26 @@
this.label4.TabIndex = 16;
this.label4.Text = "注意:\r\n1. 使用本程序多开前不能存在正在运行的微信进程。\r\n2. 多开的成功率取决于你的机器性能,不保证每次都能成功";
//
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(369, 190);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(75, 23);
+ this.button1.TabIndex = 17;
+ this.button1.Text = "button1";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // mutexHandleCloseTimer
+ //
+ this.mutexHandleCloseTimer.Tick += new System.EventHandler(this.mutexHandleCloseTimer_Tick);
+ //
// FormMultiInstance
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(472, 133);
+ this.ClientSize = new System.Drawing.Size(472, 259);
+ this.Controls.Add(this.button1);
this.Controls.Add(this.label4);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.label3);
@@ -181,6 +199,8 @@
private System.Windows.Forms.LinkLabel linkLabel1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.Timer mutexHandleCloseTimer;
}
}
diff --git a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs
index 1f566ef..5508f15 100644
--- a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs
+++ b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.cs
@@ -47,25 +47,21 @@ namespace RevokeMsgPatcher.MultiInstance
{
if (File.Exists(txtPath.Text))
{
- // 检测微信进程是否存在
- Process[] ps = Process.GetProcessesByName("WeChat");
- if (ps.Length > 0)
- {
- DialogResult result = MessageBox.Show("当前存在运行中的微信进程,请先关闭当前微信才能使用该功能。点击【确定】强制关闭当前所有微信进程并进行多开,点击【取消】不做任何处理。", "当前存在运行中的微信进程", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
- if (result == DialogResult.OK)
- {
- foreach (Process p in ps)
- p.Kill();
- }
- else
- {
- return;
- }
- }
+ Process[] processes = Process.GetProcessesByName("WeChat");
+ ProcessUtil.CloseMutexHandle(processes);
// 启动多个实例
for (int i = 0; i < startNum.Value; i++)
{
- Process.Start(txtPath.Text);
+ //var t = new Task(() =>
+ //{
+ // Process newInstance = Process.Start(txtPath.Text);
+ // newInstance.WaitForInputIdle();
+ // ProcessUtil.CloseMutexHandle(newInstance);
+ //});
+ //t.Start();
+ Process newInstance = Process.Start(txtPath.Text);
+ //newInstance.WaitForInputIdle();
+ //ProcessUtil.CloseMutexHandle(newInstance);
}
}
}
@@ -107,5 +103,16 @@ namespace RevokeMsgPatcher.MultiInstance
}
return null;
}
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ Process[] processes = Process.GetProcessesByName("WeChat");
+ ProcessUtil.CloseMutexHandle(processes);
+ }
+
+ private void mutexHandleCloseTimer_Tick(object sender, EventArgs e)
+ {
+
+ }
}
}
diff --git a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx
index 1af7de1..06e74a4 100644
--- a/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx
+++ b/RevokeMsgPatcher.MultiInstance/FormMultiInstance.resx
@@ -117,4 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 17, 17
+
\ No newline at end of file
diff --git a/RevokeMsgPatcher.MultiInstance/ProcessUtil.cs b/RevokeMsgPatcher.MultiInstance/ProcessUtil.cs
new file mode 100644
index 0000000..7818c38
--- /dev/null
+++ b/RevokeMsgPatcher.MultiInstance/ProcessUtil.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RevokeMsgPatcher.MultiInstance
+{
+ ///
+ /// 微信多开原理:
+ /// https://mp.weixin.qq.com/s/bb7XMxop7e8rd7YqQ88nyA
+ /// 参考:
+ /// https://stackoverflow.com/questions/54872228/c-sharp-how-to-find-all-handles-associated-with-current-process
+ /// https://hintdesk.com/2010/05/22/c-get-all-handles-of-a-given-process-in-64-bits/
+ ///
+ public class ProcessUtil
+ {
+ ///
+ /// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/handle_table_entry.htm?ts=0,242
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct SYSTEM_HANDLE_INFORMATION
+ { // Information Class 16
+ public ushort ProcessID;
+ public ushort CreatorBackTrackIndex;
+ public byte ObjectType;
+ public byte HandleAttribute;
+ public ushort Handle;
+ public IntPtr Object_Pointer;
+ public IntPtr AccessMask;
+ }
+
+ private enum OBJECT_INFORMATION_CLASS : int
+ {
+ ObjectBasicInformation = 0,
+ ObjectNameInformation = 1,
+ ObjectTypeInformation = 2,
+ ObjectAllTypesInformation = 3,
+ ObjectHandleInformation = 4
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ private struct OBJECT_NAME_INFORMATION
+ { // Information Class 1
+ public UNICODE_STRING Name;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct UNICODE_STRING
+ {
+ public ushort Length;
+ public ushort MaximumLength;
+ public IntPtr Buffer;
+ }
+
+ [Flags]
+ private enum PROCESS_ACCESS_FLAGS : uint
+ {
+ All = 0x001F0FFF,
+ Terminate = 0x00000001,
+ CreateThread = 0x00000002,
+ VMOperation = 0x00000008,
+ VMRead = 0x00000010,
+ VMWrite = 0x00000020,
+ DupHandle = 0x00000040,
+ SetInformation = 0x00000200,
+ QueryInformation = 0x00000400,
+ Synchronize = 0x00100000
+ }
+
+ [DllImport("ntdll.dll")]
+ private static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int returnLength);
+
+ [DllImport("kernel32.dll")]
+ private static extern IntPtr OpenProcess(PROCESS_ACCESS_FLAGS dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
+
+ [DllImport("kernel32.dll")]
+ private static extern IntPtr GetCurrentProcess();
+
+ [DllImport("ntdll.dll")]
+ private static extern int NtQueryObject(IntPtr ObjectHandle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, ref int returnLength);
+
+ [DllImport("kernel32.dll")]
+ private static extern bool CloseHandle(IntPtr hObject);
+
+ [DllImport("kernel32.dll")]
+ private static extern bool GetHandleInformation(IntPtr hObject, out uint lpdwFlags);
+
+ private const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
+ private const int DUPLICATE_CLOSE_SOURCE = 0x1;
+ private const int DUPLICATE_SAME_ACCESS = 0x2;
+
+ private const int CNST_SYSTEM_HANDLE_INFORMATION = 0x10;
+ private const int OBJECT_TYPE_MUTANT = 17;
+
+ public static List GetHandles(Process process)
+ {
+ List aHandles = new List();
+ int handle_info_size = Marshal.SizeOf(new SYSTEM_HANDLE_INFORMATION()) * 20000;
+ IntPtr ptrHandleData = IntPtr.Zero;
+ try
+ {
+ ptrHandleData = Marshal.AllocHGlobal(handle_info_size);
+ int nLength = 0;
+
+ while (NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ptrHandleData, handle_info_size, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ handle_info_size = nLength;
+ Marshal.FreeHGlobal(ptrHandleData);
+ ptrHandleData = Marshal.AllocHGlobal(nLength);
+ }
+
+ long handle_count = Marshal.ReadIntPtr(ptrHandleData).ToInt64();
+ IntPtr ptrHandleItem = ptrHandleData + Marshal.SizeOf(ptrHandleData);
+
+ for (long lIndex = 0; lIndex < handle_count; lIndex++)
+ {
+ SYSTEM_HANDLE_INFORMATION oSystemHandleInfo = new SYSTEM_HANDLE_INFORMATION();
+ oSystemHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ptrHandleItem, oSystemHandleInfo.GetType());
+ ptrHandleItem += Marshal.SizeOf(new SYSTEM_HANDLE_INFORMATION());
+ if (oSystemHandleInfo.ProcessID != process.Id) { continue; }
+ aHandles.Add(oSystemHandleInfo);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(ptrHandleData);
+ }
+ return aHandles;
+ }
+
+ public static void FindAndCloseWeChatMutexHandle(SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process)
+ {
+ IntPtr ipHandle = IntPtr.Zero;
+ IntPtr openProcessHandle = IntPtr.Zero;
+ IntPtr hObjectName = IntPtr.Zero;
+ try
+ {
+ PROCESS_ACCESS_FLAGS flags = PROCESS_ACCESS_FLAGS.DupHandle | PROCESS_ACCESS_FLAGS.VMRead;
+ openProcessHandle = OpenProcess(flags, false, process.Id);
+ // 通过 DuplicateHandle 访问句柄
+ if (!DuplicateHandle(openProcessHandle, new IntPtr(systemHandleInformation.Handle), GetCurrentProcess(), out ipHandle, 0, false, DUPLICATE_SAME_ACCESS))
+ {
+ return;
+ }
+
+ int nLength = 0;
+ hObjectName = Marshal.AllocHGlobal(256 * 1024);
+
+ // 查询句柄名称
+ while ((uint)(NtQueryObject(ipHandle, (int)OBJECT_INFORMATION_CLASS.ObjectNameInformation, hObjectName, nLength, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ Marshal.FreeHGlobal(hObjectName);
+ if (nLength == 0)
+ {
+ Console.WriteLine("Length returned at zero!");
+ return;
+ }
+ hObjectName = Marshal.AllocHGlobal(nLength);
+ }
+ OBJECT_NAME_INFORMATION objObjectName = new OBJECT_NAME_INFORMATION();
+ objObjectName = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(hObjectName, objObjectName.GetType());
+
+ if (objObjectName.Name.Buffer != IntPtr.Zero)
+ {
+ string strObjectName = Marshal.PtrToStringUni(objObjectName.Name.Buffer);
+ Console.WriteLine(strObjectName);
+ // \Sessions\1\BaseNamedObjects\_WeChat_App_Instance_Identity_Mutex_Name
+ if (strObjectName.Contains("_Instance_Identity_Mutex_Name"))
+ {
+ // 通过 DuplicateHandle DUPLICATE_CLOSE_SOURCE 关闭句柄
+ IntPtr mHandle = IntPtr.Zero;
+ if (DuplicateHandle(openProcessHandle, new IntPtr(systemHandleInformation.Handle), GetCurrentProcess(), out mHandle, 0, false, DUPLICATE_CLOSE_SOURCE))
+ {
+ CloseHandle(mHandle);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(hObjectName);
+ CloseHandle(ipHandle);
+ CloseHandle(openProcessHandle);
+ }
+ }
+
+ ///
+ /// 关闭微信的互斥句柄
+ ///
+ /// 微信的进程
+ ///
+ public static void CloseMutexHandle(Process[] processes)
+ {
+ foreach (Process process in processes)
+ {
+ CloseMutexHandle(process);
+ }
+ }
+
+ public static void CloseMutexHandle(Process process)
+ {
+ List aHandles = GetHandles(process);
+ foreach (SYSTEM_HANDLE_INFORMATION handle in aHandles)
+ {
+ // Mutant 类型的句柄
+ if (handle.ObjectType == OBJECT_TYPE_MUTANT)
+ {
+ FindAndCloseWeChatMutexHandle(handle, process);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj b/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj
index 2ed2fcd..0f89bf3 100644
--- a/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj
+++ b/RevokeMsgPatcher.MultiInstance/RevokeMsgPatcher.MultiInstance.csproj
@@ -51,6 +51,7 @@
FormMultiInstance.cs
+