无法杀死进程:"没有进程与此对象相关联"错误

时间:2017-07-22 03:55:25

标签: c# process

在我的程序中,我尝试启动一个新进程(在默认播放器中打开视频文件)。这部分工作正常。后来当我尝试关闭进程(播放器)时出现错误: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();
        }

有什么问题?

2 个答案:

答案 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,它只是被加载到资源管理器的进程中。因此,在这种情况下,我们无法直接杀死进程。