成品截图

使用自动化库

发送逻辑*sender.cs
*
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsInput;
using WindowsInput.Native;
namespace WechatSend
{
public class WindowUtil
{
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_SHOWWINDOW = 0x0040;
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public static bool SetWindowTop(IntPtr hWnd, bool isTop)
{
if (isTop)
{
return SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
else
{
return SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
}
}
public class Sender
{
static int ScreenHeight = Screen.PrimaryScreen.Bounds.Height;
static int ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
static FlaUI.Core.AutomationElements.Window wechatWindow;
static FlaUI.Core.AutomationElements.ListBox listBox;
static FlaUI.Core.Application app;
static int scrollDelta = 3;
static Process attachWechatProcess;
static string content = "";
static bool EndingFlag = false;
static volatile bool InterruptFlag = false;
static HashSet<String> wechatScanHistory = new HashSet<String>();
static InputSimulator sim = new InputSimulator();
public static String[] SplitFlag = { "\n----------------\n" };
public static void SendImage(string path)
{
CS.RunInMainContext(() =>
{
var img = Image.FromFile(path);
Clipboard.SetImage(img);
});
Thread.Sleep(1500);
sim.Keyboard.KeyDown(VirtualKeyCode.CONTROL);
sim.Keyboard.KeyPress(VirtualKeyCode.VK_V);
sim.Keyboard.KeyUp(VirtualKeyCode.CONTROL);
SubmitSend();
}
public static void SendText(string text)
{
wechatWindow.FindFirstDescendant(cf => cf.ByName("输入"))?.AsTextBox().Enter(text);
Thread.Sleep(3000);
SubmitSend();
}
public static void EnterEditView()
{
wechatWindow.FindFirstDescendant(cf => cf.ByName("发消息"))?.Click();
}
public static void BackContactView()
{
wechatWindow.FindFirstDescendant(cf => cf.ByName("通讯录"))?.Click();
}
public static void SubmitSend()
{
Thread.Sleep(600);
wechatWindow.FindFirstDescendant(cf => cf.ByName("sendBtn"))?.Click();
}
public static bool HandleInterval(string text)
{
if (text.StartsWith("间隔") && text.EndsWith("秒"))
{
var retPattern = new Regex(@"间隔(\d+)秒", RegexOptions.Compiled);
string s = retPattern.Match(text).Groups[1].Captures[0].Value;
if (int.Parse(s) > 0)
{
Thread.Sleep(int.Parse(s) * 1000);
Debug.WriteLine(@"等待间隔秒数:" + int.Parse(s));
return true;
}
}
return false;
}
public static void Scan()
{
foreach (ListBoxItem item in listBox.Items)
{
if (InterruptFlag)
{
Debug.WriteLine("中止发送==");
break;
}
else
{
Debug.WriteLine("继续发送==");
}
if (item.Name.Length == 0 || item.Name == "新的朋友" || item.Name == "公众号" || item.Name == "微信团队" || item.Name == "文件传输助手") continue;
item.Click();
Thread.Sleep(2000);
var childs = wechatWindow.FindFirstDescendant(cf => cf.ByName("微信号:"))?.Parent.FindAllChildren();
var wechatNumItem = childs[childs.Length - 1];
var wechatNumText = wechatNumItem.Name;
if (wechatScanHistory.Contains(wechatNumText))
{
if (EndingFlag)
{
continue;
}
break;
}
else
{
scrollDelta = 3;
wechatScanHistory.Add(wechatNumText);
Debug.WriteLine(item.Name + "\t" + wechatNumText);
EnterEditView();
SplitMsgContent(content);
Thread.Sleep(1500);
BackContactView();
Thread.Sleep(1000);
}
}
if (EndingFlag)
{
EndingFlag = false;
}
}
public static void InitApp()
{
var wechatProcess = Process.GetProcessesByName("WeChat");
if (wechatProcess.Length != 1)
{
MessageBox.Show("未找到微信或者微信在多开环境运行 " + wechatProcess.Length, "提示",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Debug.WriteLine($"寻找进程:{wechatProcess.Length}");
attachWechatProcess = wechatProcess.First();
app = FlaUI.Core.Application.Attach(attachWechatProcess.Id);
}
public static void NotifyStop()
{
InterruptFlag = true;
}
public static void StartSend(string richText)
{
wechatScanHistory.Clear();
content = richText;
InitApp();
WindowUtil.SetWindowTop(attachWechatProcess.MainWindowHandle, true);
InterruptFlag = false;
using (var automation = new UIA3Automation())
{
wechatWindow = app.GetMainWindow(automation);
wechatWindow.FocusNative();
Debug.WriteLine("附加到进程:" + wechatWindow.Title);
BackContactView();
Thread.Sleep(2000);
var i = wechatWindow.FindFirstDescendant(cf => cf.ByName("联系人"));
i.Click();
i.FocusNative();
var x = i.BoundingRectangle.X;
var y = i.BoundingRectangle.Y;
var w = i.BoundingRectangle.Width;
var h = i.BoundingRectangle.Height;
listBox = i.AsListBox();
Debug.WriteLine($"Screen: {Screen.PrimaryScreen.Bounds.Height}");
while (true)
{
if (InterruptFlag) break;
Scan();
if (scrollDelta < -10)
{
EndingFlag = true;
Scan();
break;
}
else
{
if (InterruptFlag) break;
BackContactView();
Debug.WriteLine($"滑动~~~{scrollDelta}");
sim.Mouse.MoveMouseTo((x + w / 2) * 65536 / ScreenWidth, (y + h / 2) * 65536 / ScreenHeight);
sim.Mouse.VerticalScroll(-(Math.Max(scrollDelta--, 1)));
Thread.Sleep(1500);
}
}
}
CS.RunInMainContext(() =>
{
if (InterruptFlag)
{
MessageBox.Show("执行中断", "微信群发 - 提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("执行完毕", "微信群发 - 提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
});
WindowUtil.SetWindowTop(attachWechatProcess.MainWindowHandle, false);
app.Dispose();
Debug.WriteLine("-----执行结束");
}
public static void TestSend(string content)
{
InitApp();
using (var automation = new UIA3Automation())
{
wechatWindow = app.GetMainWindow(automation);
EnterEditView();
SplitMsgContent(content);
BackContactView();
}
}
public static void SplitMsgContent(string text)
{
Debug.WriteLine("输入文本:" + text);
if (text.EndsWith(SplitFlag[0]))
{
text = text.Substring(0, text.Length - SplitFlag[0].Length);
}
if (text.StartsWith(SplitFlag[0]))
{
text = text.Substring(SplitFlag[0].Length);
}
String[] lines = text.Split(SplitFlag, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
if (HandleInterval(line))
{
continue;
}
if (File.Exists(line))
{
Debug.WriteLine("发送图片:" + line);
SendImage(line);
continue;
}
Debug.WriteLine("发送文本:" + line);
SendText(line);
}
}
}
}
界面逻辑 Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WechatSend
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Sender.StartSend(this.richTextBoxContent.Text);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
CS.InitMainContext(SynchronizationContext.Current);
GlobalHotKey.RegisterHotKey("Ctrl + Shift + Q", () => {
string text = this.richTextBoxContent.Text;
CS.runInBackground(() =>
{
Sender.StartSend(text);
});
});
GlobalHotKey.RegisterHotKey("Ctrl + Shift + E", () => {
System.Environment.Exit(0);
});
GlobalHotKey.RegisterHotKey("Ctrl + Shift + S", () =>
{
Debug.WriteLine("中断发送");
Sender.NotifyStop();
});
Debug.WriteLine($"Screen: {Screen.PrimaryScreen.Bounds.Height}x{Screen.PrimaryScreen.Bounds.Width}");
}
private void buttonAddImage_Click(object sender, EventArgs e)
{
}
private void Form1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.All;
}
else
{
String[] strGetFormats = e.Data.GetFormats();
e.Effect = DragDropEffects.None;
}
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach (string file in files)
{
this.richTextBoxContent.AppendText(file);
this.richTextBoxContent.AppendText(Sender.SplitFlag[0]);
}
}
private void richTextBoxContent_DoubleClick(object sender, EventArgs e)
{
if (!this.richTextBoxContent.Text.EndsWith("\n"))
{
this.richTextBoxContent.AppendText(Sender.SplitFlag[0]);
}
}
}
}
快捷键注册 GlobakHotkey.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WechatSend
{
public class GlobalHotKey : IDisposable
{
public static bool RegisterHotKey(string aKeyGestureString, Action aAction)
{
var c = new KeyGestureConverter();
KeyGesture aKeyGesture = (KeyGesture)c.ConvertFrom(aKeyGestureString);
return RegisterHotKey(aKeyGesture.Modifiers, aKeyGesture.Key, aAction);
}
public static bool RegisterHotKey(ModifierKeys aModifier, Key aKey, Action aAction)
{
if (aModifier == ModifierKeys.None)
{
throw new ArgumentException("Modifier must not be ModifierKeys.None");
}
if (aAction is null)
{
throw new ArgumentNullException(nameof(aAction));
}
System.Windows.Forms.Keys aVirtualKeyCode = (System.Windows.Forms.Keys)KeyInterop.VirtualKeyFromKey(aKey);
currentID = currentID + 1;
bool aRegistered = RegisterHotKey(window.Handle, currentID,
(uint)aModifier | MOD_NOREPEAT,
(uint)aVirtualKeyCode);
if (aRegistered)
{
registeredHotKeys.Add(new HotKeyWithAction(aModifier, aKey, aAction));
}
return aRegistered;
}
public void Dispose()
{
for (int i = currentID; i > 0; i--)
{
UnregisterHotKey(window.Handle, i);
}
window.Dispose();
}
static GlobalHotKey()
{
window.KeyPressed += (s, e) =>
{
registeredHotKeys.ForEach(x =>
{
if (e.Modifier == x.Modifier && e.Key == x.Key)
{
x.Action();
}
});
};
}
private static readonly InvisibleWindowForMessages window = new InvisibleWindowForMessages();
private static int currentID;
private static uint MOD_NOREPEAT = 0x4000;
private static List<HotKeyWithAction> registeredHotKeys = new List<HotKeyWithAction>();
private class HotKeyWithAction
{
public HotKeyWithAction(ModifierKeys modifier, Key key, Action action)
{
Modifier = modifier;
Key = key;
Action = action;
}
public ModifierKeys Modifier { get; }
public Key Key { get; }
public Action Action { get; }
}
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private class InvisibleWindowForMessages : System.Windows.Forms.NativeWindow, IDisposable
{
public InvisibleWindowForMessages()
{
CreateHandle(new System.Windows.Forms.CreateParams());
}
private static int WM_HOTKEY = 0x0312;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_HOTKEY)
{
var aWPFKey = KeyInterop.KeyFromVirtualKey(((int)m.LParam >> 16) & 0xFFFF);
ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF);
if (KeyPressed != null)
{
KeyPressed(this, new HotKeyPressedEventArgs(modifier, aWPFKey));
}
}
}
public class HotKeyPressedEventArgs : EventArgs
{
private ModifierKeys _modifier;
private Key _key;
internal HotKeyPressedEventArgs(ModifierKeys modifier, Key key)
{
_modifier = modifier;
_key = key;
}
public ModifierKeys Modifier
{
get { return _modifier; }
}
public Key Key
{
get { return _key; }
}
}
public event EventHandler<HotKeyPressedEventArgs> KeyPressed;
#region IDisposable Members
public void Dispose()
{
this.DestroyHandle();
}
#endregion
}
}
}