MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Cannot kill process: "No process is associated with this object" error"
Answer 47299564
Process.Start
associates theProcess
object with native process handle only when it spawns new process directly. When filename is used as an argument instead of executable name,Process
searches registry for association settings via shell32.dll functions and the exact behavior depends on them.When association is configured in traditional way, to call command line and transfer file name as 1st argument (such as for Notepad),
Process.Start
spawns new process directly and correctly associates object with native handle. However, when association is configured to execute COM-object (such as for Windows Media Player),Process.Start
only creates some RPC query to execute COM object method and returns without associating object with process handle. (The actual process spawn occurs in svchost.exe context, according to my tests)This issue can be solved by following modified process start method:
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, } }
Here we get the file type's associated application via AssocQueryString. The returned value is then passed to
ProcessStartInfo
. However it does not always work, so we sometimes have to resort to standart method. For example, image files does not have any associated exe, it's just dll being loaded into explorer's process. So we can't outright kill process in this case.
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.