在我的程序中,我尝试启动一个新进程(在默认播放器中打开视频文件)。这部分工作正常。后来当我尝试关闭进程(播放器)时出现错误:System.InvalidOperationException: No process is associated with this object.
我的代码:
string filename = "747225775.mp4";
var myProc = new Process()
{
StartInfo = new ProcessStartInfo(filename)
};
myProc.Start();
Thread.Sleep(5000);
try
{
myProc.Kill(); //Error is here
}
catch (Exception ex)
{
Debug.WriteLine(ex);
Debugger.Break();
}
有什么问题?
答案 0 :(得分:0)
回答你的问题:"出了什么问题?"
我可以说下划线的原因与为处理文件类型(.mp4
)而启动的Windows应用程序有关。
从我可以确定的...你的代码示例没有任何问题,除了它没有考虑到这种情况(其中,承认,我不明白为什么它的行为如此)
为了复制这一点,我使用了您的代码示例和图像文件(.png
)。该计划与“照片”一起发布。默认情况下。
我默认将.png
个文件更改为使用Paint
应用程序启动,然后再次运行该程序。您提供的代码示例在桌面应用程序上运行良好。
答案 1 :(得分:0)
Process.Start
对象直接生成新进程时,它才会将Process
对象与本机进程句柄相关联。当filename用作参数而不是可执行文件名时,Process
通过 shell32.dll 函数在注册表中搜索关联设置,确切的行为取决于它们。
当以传统方式配置关联时,要调用命令行并将文件名作为第一个参数(例如记事本),Process.Start
直接生成新进程并正确地将对象与本机句柄相关联。但是,当关联配置为执行COM对象(例如 Windows Media Player )时,Process.Start
仅创建一些RPC查询来执行COM对象方法并返回而不将对象与进程句柄关联。 (根据我的测试,实际的进程生成发生在 svchost.exe 上下文中)
此问题可以通过以下修改的流程启动方法来解决:
using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
namespace ProcessTest
{
public partial class Form1 : Form
{
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, ref uint pcchOut);
/*Modified Process.Start*/
public static Process TrueProcessStart(string filename)
{
ProcessStartInfo psi;
string ext = System.IO.Path.GetExtension(filename);//get extension
var sb = new StringBuilder(500);//buffer for exe file path
uint size = 500;//buffer size
/*Get associated app*/
uint res = AssocQueryString(AssocF.None, AssocStr.Executable, ext,null, sb, ref size);
if (res != 0)
{
Debug.WriteLine("AssocQueryString returned error: " + res.ToString("X"));
psi = new ProcessStartInfo(filename);//can't get app, use standard method
}
else
{
psi = new ProcessStartInfo(sb.ToString(), filename);
}
return Process.Start(psi);//actually start process
}
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
string filename = "c:\\images\\clip.wmv";
var myProc = TrueProcessStart(filename);
if (myProc == null)
{
MessageBox.Show("Process can't be killed");
return;
}
Thread.Sleep(5000);
try
{
myProc.Kill();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
[Flags]
enum AssocF : uint
{
None = 0,
Init_NoRemapCLSID = 0x1,
Init_ByExeName = 0x2,
Open_ByExeName = 0x2,
Init_DefaultToStar = 0x4,
Init_DefaultToFolder = 0x8,
NoUserSettings = 0x10,
NoTruncate = 0x20,
Verify = 0x40,
RemapRunDll = 0x80,
NoFixUps = 0x100,
IgnoreBaseClass = 0x200,
Init_IgnoreUnknown = 0x400,
Init_FixedProgId = 0x800,
IsProtocol = 0x1000,
InitForFile = 0x2000,
}
enum AssocStr
{
Command = 1,
Executable,
FriendlyDocName,
FriendlyAppName,
NoOpen,
ShellNewValue,
DDECommand,
DDEIfExec,
DDEApplication,
DDETopic,
InfoTip,
QuickTip,
TileInfo,
ContentType,
DefaultIcon,
ShellExtension,
DropTarget,
DelegateExecute,
SupportedUriProtocols,
Max,
}
}
这里我们通过AssocQueryString获取文件类型的相关应用程序。然后将返回的值传递给ProcessStartInfo
。然而,它并不总是有效,所以我们有时不得不采用标准方法。例如,图像文件没有任何关联的exe,它只是被加载到资源管理器的进程中。因此,在这种情况下,我们无法直接杀死进程。