Reputation: 475
In my program I try to start a new process (open video file in a default player). This part works OK. Later when I try to close the process (player) I get an error:
System.InvalidOperationException: No process is associated with this object.
My code:
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();
}
What is wrong?
Upvotes: 5
Views: 20202
Reputation: 728
Process.Start
associates the Process
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.
Upvotes: 2
Reputation: 1504
to answer your question: "What is wrong?"
I can say the underline cause of this is related to Windows Apps that are launched to handle the type of file (.mp4
).
From what I can determine.. there isn't anything wrong with your code sample except that it doesn't account for this scenario (in which, admittingly, I do not understand why it behaves this way).
To replicate this, I used your code sample and a image file (.png
). the program launches with 'Photos' by default.
I changed .png
files to launch with Paint
application by default, then ran the program again. The code sample you've provided worked fine on the desktop application.
Upvotes: 0