问题描述
当我想使用.ico
打开Process.Start
文件时,会引发错误System.ComponentModel.Win32Exception
,这是因为没有默认程序可以打开该文件。我需要显示窗口以选择默认程序,而不是引发异常。我该怎么办?
private void btnOpenFile_Click(object sender,EventArgs e)
{
Process.Start(txtSavedAs.Text);
}
解决方法
您想要做的是调用AssocQueryString
API。 Documentation here。
我使用该API来获取与Shell动词关联的命令字符串。因此,例如,如果我使用.txt
扩展名,它将返回:
C:\Windows\system32\NOTEPAD.EXE %1
现在,我们知道shell知道要执行哪个程序以及如何为该特定扩展名传递命令行参数。
因此,如果存在与该扩展名关联的“命令”,可以安全地假设Shell知道如何执行该类型的文件;因此,我们应该能够正常使用ShellExecute。
如果没有与该文件扩展名关联的“命令”,我们将显示“ openas”对话框,允许用户选择要打开文件的应用程序。
这是我一起做的一门课:
AppAssociation.cs
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
public static class AppAssociation
{
private static class Win32Native
{
public const int ASSOCF_NONE = 0;
public const int ASSOCSTR_COMMAND = 1;
[DllImport("shlwapi.dll",CharSet = CharSet.Unicode,EntryPoint = "AssocQueryStringW")]
public static extern uint AssocQueryString(int flags,int str,string pszAssoc,string pszExtra,StringBuilder pszOut,ref uint pcchOut);
}
public static Process StartProcessForFile(FileInfo file)
{
var command = GetCommandForFileExtention(file.Extension);
return Process.Start(new ProcessStartInfo()
{
WindowStyle = ProcessWindowStyle.Normal,FileName = file.FullName,Verb = string.IsNullOrEmpty(command) ? "openas" : null,UseShellExecute = true,ErrorDialog = true
});
}
private static string GetCommandForFileExtention(string ext)
{
// query length of the buffer we need
uint length = 0;
if (Win32Native.AssocQueryString(Win32Native.ASSOCF_NONE,Win32Native.ASSOCSTR_COMMAND,ext,null,ref length) == 1)
{
// build the buffer
var sb = new StringBuilder((int)length);
// ask for the actual command string with the right-sized buffer
if (Win32Native.AssocQueryString(Win32Native.ASSOCF_NONE,sb,ref length) == 0)
{
return sb.ToString();
}
}
return null;
}
}
您将这样称呼:
AppAssociation.StartProcessForFile(new FileInfo(@"c:\MyFiles\TheFile.txt"));