我正在尝试创建一个在默认图像查看器中打开图像的简短方法,并在time
毫秒后关闭它。
现在它看起来像这样:
public static async void OpenImage(string path, int time)
{
var process = new Process();
process.StartInfo.FileName = path;
process.Start();
await Task.Delay(time);
process.Kill()
process.Close()
}
我可以看到图片,但随后process.Kill()
会抛出InvalidOperationException
,“没有进程与此对象相关联。”
我是否错过了某些内容或有其他方法可以做到这一点?
更新:
现在也测试了这个:
public static async void OpenImage(string path, int time)
{
var process = Process.Start(path)
await Task.Delay(time);
process.Kill()
process.Close()
}
然后Process.Start()
返回null
。所以也许我必须像faljbour一样直接打电话给.exe
?
答案 0 :(得分:5)
这里的问题是你并没有真正启动进程,而是将文件路径传递给Windows Shell(explorer.exe
)来处理。 shell计算出如何打开文件, it 启动该过程。
当发生这种情况时,您的代码不会返回进程ID,因此它不知道要杀死哪个进程。
你应该做的是找到该文件的默认应用程序,然后显式启动该应用程序(而不是让shell弄清楚它)。
我能想到找到文件默认应用程序的最紧凑的方法是使用Win32 API FindExecutable()
。
当默认应用程序包含在dll中时,事情变得复杂一些。这是默认Windows照片查看器(C:\Program Files (x86)\Windows Photo Viewer\PhotoViewer.dll
)的情况。由于它不是exe
,您无法直接启动,但可以使用rundll32
启动应用程序。
这应该适合你:
[DllImport("shell32.dll")]
static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult);
public static async void OpenImage(string imagePath, int time)
{
var exePathReturnValue = new StringBuilder();
FindExecutable(Path.GetFileName(imagePath), Path.GetDirectoryName(imagePath), exePathReturnValue);
var exePath = exePathReturnValue.ToString();
var arguments = "\"" + imagePath + "\"";
// Handle cases where the default application is photoviewer.dll.
if (Path.GetFileName(exePath).Equals("photoviewer.dll", StringComparison.InvariantCultureIgnoreCase))
{
arguments = "\"" + exePath + "\", ImageView_Fullscreen " + imagePath;
exePath = "rundll32";
}
var process = new Process();
process.StartInfo.FileName = exePath;
process.StartInfo.Arguments = arguments;
process.Start();
await Task.Delay(time);
process.Kill();
process.Close();
}
此代码演示了这个概念,但是如果您想要使用不常见的参数格式来满足更多默认应用程序(如photoviewer.dll
所示),您应该搜索registry yourself或使用第三方库来找到要使用的正确命令行。
例如,