Process Start 相关
在自己的【CSharp语法之 Process.Start 相关】 文章中有详解
前言
偶然发现,如果想用如下代码在 .NET 6 中打开指定 URL:
1
| Process.Start("https://baidu.com");
|
会引发异常:
而同样的代码在 .NET Framework 中是可以正常执行的。
难道,.NET 6 下的实现逻辑不一样?
深入探究
通过调用堆栈,我们发现最后调用的是StartWithCreateProcess
方法:
对应的 .NET 6 源代码如下:
1 2 3 4 5 6 7 8
| private bool StartCore(ProcessStartInfo startInfo) { if (!startInfo.UseShellExecute) { return this.StartWithCreateProcess(startInfo); } return this.StartWithShellExecuteEx(startInfo); }
|
这和 .NET Framework 中的实现逻辑基本一致:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public bool Start() { this.Close(); ProcessStartInfo processStartInfo = this.StartInfo; if (processStartInfo.FileName.Length == 0) { throw new InvalidOperationException(SR.GetString("FileNameMissing")); } if (processStartInfo.UseShellExecute) { return this.StartWithShellExecuteEx(processStartInfo); } return this.StartWithCreateProcess(processStartInfo); }
|
那么问题出在哪呢?
通过 dnspy 调试 .NET Framework 版本的测试程序,我们发现,最后执行的是StartWithShellExecuteEx
而不是StartWithCreateProcess方法:
而之所以走不同的逻辑分支,是由processStartInfo.UseShellExecute
控制的。
所以,解决方案也很简单,设置UseShellExecute = true
:
1
| Process.Start(new ProcessStartInfo("https://baidu.com") { UseShellExecute = true });
|
结论
造成这样的原因,是因为UseShellExecute
在 .NET 6 上默认为 false:
1
| public bool UseShellExecute { get; set; }
|
而在 .NET Framework 上默认为 true:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| [DefaultValue(true)] [MonitoringDescription("ProcessUseShellExecute")] [NotifyParentProperty(true)] public bool UseShellExecute { get { return this.useShellExecute; } set { this.useShellExecute = value; } } private bool useShellExecute = true;
|
当UseShellExecute = false
时,代码会将传入参数作为文件名使用,从而引发“系统找不到指定的文件”异常。
打开邮件
打开outlook邮件窗口–打开软件,后边没使用
在C#中,要打开Outlook并执行操作,你可以使用Microsoft Outlook PIA (Primary Interop Assembly) 或者通过COM对象模型。以下是使用COM对象模型打开Outlook并创建一个新电子邮件的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| using System; using Outlook = Microsoft.Office.Interop.Outlook; class Program { static void Main(string[] args) { Outlook.Application outlookApp = new Outlook.Application(); Outlook.MailItem mailItem = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem); mailItem.To = "recipient@example.com"; mailItem.Subject = "Hello"; mailItem.Body = "This is a test email."; mailItem.Display(true); System.Runtime.InteropServices.Marshal.ReleaseComObject(mailItem); System.Runtime.InteropServices.Marshal.ReleaseComObject(outlookApp); Console.WriteLine("Email opened in Outlook."); } }
|
确保你的项目引用了Microsoft Outlook Object Library。如果你的开发环境是Visual Studio,你可以通过NuGet包管理器安装Microsoft.Office.Interop.Outlook。
请注意,由于COM对象的交互性质,这种方法可能会引发各种异常,比如Outlook没有安装或者COM对象访问被禁用等问题。在实际部署时,你可能需要处理这些异常。
报错找不到文件
我有一个用C#编写的简单应用程序。net 6.0。按下按钮后,我想打开一个Outlook窗口,其中包含文本框中的e-mail内容和文本框中的收件人。
问题是,该应用程序用于公司领域的计算机。我无法使用smtp以编程方式发送电子邮件。
必须从当前登录到计算机(窗口10)的用户的帐户中完全禁止邮件,该用户已配置Outlook帐户,以便将其分配给windows帐户。
我试图使用Microsoft.Office.Interop.Outlook,但我出错了
1
| Could not load file or assembly 'Microsoft.Office.Interop.Outlook, Version = 15.0.0.0, Culture = neutral, PublicKeyToken = 71e9bce111e9429c
|
您需要向该项目添加COM引用。右键单击项目的依赖项并选择Add COM references
:
在对话框窗口中,您可以找到Outlook的条目并将其选中。
维奥拉!单击Ok
按钮并在代码中使用OOM。
方法一、通过mailto标签发送邮件(常用)
通过mailto不是正真意义上的发送邮件,它只是会自动调用我们本地默认的邮件服务软件(这取决于我们本地安装了什么邮件软件,outlook,firemail等等),发送还是需要我们自己点击发送才能完成。
mailto标签有很多实用的方法,比如:加入邮件的默认主题、抄送地址、暗送(密件抄送)地址,邮件内容等待…..
1、为邮件加入发件人
格式:mailto:发件人地址
代码示例
1 2 3 4 5 6 7 8 9 10
| private void btnSendEmail_ItemClick(object sender, ItemClickEventArgs e) { string message = string.Format("mailto:{0}", sendFrom); System.Diagnostics.Process.Start(message); }
|
2、为邮件加入默认标题
格式:mailto:发件人地址?subject=邮件主题
代码示例
1 2 3 4 5 6 7 8 9 10 11
| private void btnSendEmail_ItemClick(object sender, ItemClickEventArgs e) { string message = string.Format("mailto:{0}?subject={1}", sendFrom, subjetc); System.Diagnostics.Process.Start(message); }
|
3、为邮件加入默认的抄送地址
格式:mailto:发件人地址?cc=抄送地址
代码示例
1 2 3 4 5 6 7 8 9 10 11
| private void btnSendEmail_ItemClick(object sender, ItemClickEventArgs e) { string message = string.Format("mailto:{0}?cc={1}", sendFrom, sendCC); System.Diagnostics.Process.Start(message); }
|
4、为邮件加入默认暗送(密件抄送)地址
格式:mailto:发件人地址?bcc=密送地址
代码示例
1 2 3 4 5 6 7 8 9 10 11
| private void btnSendEmail_ItemClick(object sender, ItemClickEventArgs e) { string message = string.Format("mailto:{0}?bcc={1}", sendFrom, sendBCC); System.Diagnostics.Process.Start(message); }
|
6、多个邮件地址
格式:mailto:发件人地址1,发件地址2,发件地址3(以逗号分隔)
7、综合型的:加入默认抄送地址,标题,内容
格式:mailto:发件人地址1,发件人地址2?cc=抄送地址&bcc=密送地址&subject=主题&body=邮件内容
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private void btnSendEmail_ItemClick(object sender, ItemClickEventArgs e) { string message = string.Format("mailto:{0}?cc={1}&bcc={2}&subject={3}&body={4}", sendFrom, sendCC, sendBCC, subjetc, content); System.Diagnostics.Process.Start(message); }
|
如图所示:
方法二、通过SMTP协议发送邮件
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public static bool SendMessage(string userEmailAddress, string userName, string password, string host, int port, string[] sendToList, string[] sendCCList, string subject, string body, string[] attachmentsPath, out string errorMessage) { errorMessage = string.Empty; SmtpClient client = new SmtpClient(); client.Credentials = new System.Net.NetworkCredential(userEmailAddress, password); client.DeliveryMethod = SmtpDeliveryMethod.Network; client.Host = host; client.Port = port; client.UseDefaultCredentials = true;
MailMessage msg = new MailMessage(); foreach (string send in sendToList) { msg.To.Add(send); } foreach (string cc in sendCCList) { msg.To.Add(cc); }
if (attachmentsPath != null && attachmentsPath.Length > 0) { foreach (string path in attachmentsPath) { var attachFile = new Attachment(path); msg.Attachments.Add(attachFile); } } msg.From = new MailAddress(userEmailAddress, userName); msg.Subject = subject; msg.Body = body; msg.BodyEncoding = System.Text.Encoding.UTF8; msg.IsBodyHtml = true; msg.Priority = MailPriority.High;
try { client.Send(msg); return true; } catch (System.Net.Mail.SmtpException ex) { errorMessage = ex.Message; return false; } }
|
如图所示:
计算器
1
| System.Diagnostics.Process.Start(@"calc.exe");
|
默认浏览器
示例界面:
方法一:从注册表中读取默认浏览器可执行文件路径
1 2 3 4 5 6 7 8 9
| private void button1_Click(object sender, EventArgs e) {
RegistryKey key = Registry.ClassesRoot.OpenSubKey(@"http\shell\open\command\"); string s = key.GetValue("").ToString();
System.Diagnostics.Process.Start(s.Substring(0, s.Length - 8), "http://blog.csdn.net/testcs_dn"); }
|
方法二:
1 2 3 4 5
| private void button2_Click(object sender, EventArgs e) {
System.Diagnostics.Process.Start("explorer.exe", "http://blog.csdn.net/testcs_dn"); }
|
方法三:
1 2 3 4 5
| private void button3_Click(object sender, EventArgs e) {
System.Diagnostics.Process.Start("http://blog.csdn.net/testcs_dn"); }
|
方法四:调用IE浏览器
1 2 3 4 5
| private void button4_Click(object sender, EventArgs e) {
System.Diagnostics.Process.Start("iexplore.exe", "http://blog.csdn.net/testcs_dn"); }
|
方法二和方法三一样,只不过方法三写法简便,
下面说一下方法四
1、所需环境
.NET环境、需要引用System.Diagnostics这个命名空间、 一个准备好的静态网页
2、实现
其实这个程序非常的简单,只是把调用程序的方法用在了这里而已,并且是用特定程序打开特定文件的的一种使用。
1
| System.Diagnostics.Process.Start(@"IExplore.exe", "http://blog.csdn.net/testcs_d");
|
这个函数Start里面有两个参数,第一个是指定的程序的地址,第二个参数是指定的文件的地址,一组合就出现了我们想要的效果(由于IE是系统应用且在环境变量中有了设置,可以直接写.exe的文件)。前提是我们要有上述的网页放在指定位置。
我们不能直接把这个函数写到控件事件中,否则会报错的。我写了一个方法然后调用实现的。如果要调用别的浏览器只要把例子中的”iexplore.exe”改为其他的浏览器程序名既可。
我们还可以用它来进行打开别的文件的操作,比如,用notpad++来打开一个文本文件了,在方法的第一参数上写上notpad++的主程序地址,后面写上文本文件名字就可以了。
相关链接(侵删)
- C# 如何通过mailto标签和SMTP协议两种方式发送邮件
- Process.Start 为什么会引发“系统找不到指定的文件”异常
- C# 打开应用程序或打开默认电子邮件应用程序
- C#打开outlook邮件窗口
- 【C#】调用默认浏览器打开网页的几种方法
=================我是分割线=================
欢迎到公众号来唠嗑: