如何用C#控制台程序实现记事本打开并自动保存文件?
问题:如何在C#中关闭记事本前自动保存文件?
我已经能通过C#打开并关闭指定的文本文件,代码如下:
using System.Diagnostics; class Program { static void Main(string[] args) { // 用记事本打开文件 Process.Start("notepad.exe", @"myfile.txt"); // 这里需要实现记事本自动保存文件的逻辑 // 关闭记事本进程 Process[] proc = Process.GetProcessesByName("notepad"); proc[0].Kill(); } }
但尝试发送Ctrl+S按键来实现自动保存时没有效果,请问有没有对应的.NET代码可以实现这个需求?谢谢。
解决方案
你遇到的问题其实挺常见的——直接模拟Ctrl+S经常因为记事本窗口没获得焦点而失效,这里给你两种更可靠的实现方式,尤其是第一种通过Windows API发送保存命令的方法,稳定性会高很多:
方式一:通过Windows API发送保存命令(推荐)
记事本的保存功能是通过窗口消息触发的,对应的是WM_COMMAND消息,命令ID为0x0006(也就是记事本内部的ID_FILE_SAVE)。我们可以直接找到记事本的窗口句柄,发送这个消息来触发保存,完全不需要模拟按键,也就不会有焦点问题。
先把需要的Win32 API导入进来,然后写逻辑:
using System; using System.Diagnostics; using System.Runtime.InteropServices; class Program { // 导入查找窗口的Win32 API [DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); // 导入发送消息的API [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); // 定义需要用到的常量 private const uint WM_COMMAND = 0x0111; private const int ID_FILE_SAVE = 0x0006; static void Main(string[] args) { // 启动记事本并打开目标文件 var notepadProcess = Process.Start("notepad.exe", @"myfile.txt"); // 等一等,让记事本窗口完全初始化 notepadProcess.WaitForInputIdle(); // 找到记事本的窗口句柄——窗口标题格式是「文件名 - Notepad」 IntPtr notepadWindow = FindWindow("Notepad", "myfile.txt - Notepad"); if (notepadWindow != IntPtr.Zero) { // 发送保存命令的消息 SendMessage(notepadWindow, WM_COMMAND, (IntPtr)ID_FILE_SAVE, IntPtr.Zero); Console.WriteLine("已经触发记事本保存啦"); } else { Console.WriteLine("没找到对应的记事本窗口哦"); } // 给保存留一点时间,根据文件大小可以调整这个延迟 System.Threading.Thread.Sleep(1000); // 关闭记事本进程 notepadProcess.Kill(); } }
方式二:激活窗口后模拟Ctrl+S按键
如果你还是想用模拟按键的方式,那一定要先把记事本窗口激活到前台,再发送按键。这里用SetForegroundWindow API来激活窗口,然后用SendKeys发送Ctrl+S:
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; class Program { // 导入激活窗口的API [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetForegroundWindow(IntPtr hWnd); static void Main(string[] args) { var notepadProcess = Process.Start("notepad.exe", @"myfile.txt"); notepadProcess.WaitForInputIdle(); // 把记事本窗口调到前台 SetForegroundWindow(notepadProcess.MainWindowHandle); // 等窗口完全激活 Thread.Sleep(500); // 发送Ctrl+S,^代表Ctrl键 System.Windows.Forms.SendKeys.SendWait("^s"); // 等保存完成 Thread.Sleep(1000); // 关闭记事本 notepadProcess.Kill(); } }
注意哦:用
SendKeys的话,在.NET Core或者.NET 5+的项目里,需要先安装System.Windows.Forms这个NuGet包才行,框架项目的话直接引用对应的程序集就好。
为什么你之前模拟Ctrl+S没用?
大概率是因为记事本窗口没处于活动状态,SendKeys会把按键发送给当前的前台窗口,而不是记事本。所以要么确保窗口激活,要么直接用窗口消息的方式,后者肯定更靠谱,毕竟不用依赖焦点状态。
内容的提问来源于stack exchange,提问作者Kate Chang
相关产品推荐
相关产品推荐

