c#中用System.Diagnostics.Process.Start(Path.GetFullPath(“vlc.exe.l
vlc.exe.lnk雙擊這個(gè)文件,能正常打開(kāi)vlc,但是用System.Diagnostics.Process.Start(Path.GetFullPath("vlc.exe.lnk"), url);沒(méi)有任何反應(yīng)。根據(jù)常理,不應(yīng)該出現(xiàn)這個(gè)問(wèn)題。但是現(xiàn)實(shí)就是這么魔幻,偏偏有這個(gè)問(wèn)題。

根據(jù)上面圖,根據(jù)快捷方式是可以獲取到vlc可執(zhí)行文件的路徑的,然后在網(wǎng)上搜索到這段代碼,如下:
//?引用→添加引用→左側(cè)菜單的?COM?選項(xiàng)→勾上?Microsoft?Shell?Controls?And?Automation
using?Shell32;
namespace?FD.WinformUI
{
????public?class?UICommon
????{
????????//?傳入快捷方式文件的路徑,返回目標(biāo)?exe?文件的路徑
????????public?string?GetExePathFromShortcut(string?shortcutFilePath)
????????{
????????????FileInfo?fileInfo?=?new?FileInfo(shortcutFilePath);
????????????string?targetPath?=?"";
????????????if?(fileInfo.Extension.ToLower()?==?".lnk")?//?判斷是否為快捷方式文件
????????????{
????????????????Shell?shell?=?new?Shell();
????????????????Folder?folder?=?shell.NameSpace(fileInfo.DirectoryName);
????????????????FolderItem?folderItem?=?folder.ParseName(fileInfo.Name);
????????????????if?(folderItem?!=?null)
????????????????{
????????????????????ShellLinkObject?link?=?(ShellLinkObject)folderItem.GetLink;
????????????????????targetPath?=?link.Target.Path;?//?獲取目標(biāo)?exe?文件的路徑
????????????????}
????????????}
????????????else?if?(fileInfo.Extension.ToLower()?==?".url")?//?判斷是否為網(wǎng)址快捷方式
????????????{
????????????????using?(StreamReader?reader?=?new?StreamReader(shortcutFilePath))
????????????????{
????????????????????string?line;
????????????????????while?((line?=?reader.ReadLine())?!=?null)
????????????????????{
????????????????????????if?(line.StartsWith("URL=",?StringComparison.OrdinalIgnoreCase))
????????????????????????{
????????????????????????????targetPath?=?line.Substring(4).Trim();
????????????????????????????break;
????????????????????????}
????????????????????}
????????????????}
????????????}
????????????return?targetPath;
????????}
????}
}
調(diào)用上面的函數(shù)UICommon.Instance.GetExePathFromShortcut(Path.GetFullPath("vlc.exe.lnk")),得到的路徑是 "C:\Program Files (x86)\VideoLAN\VLC\vlc.exe" ,而這個(gè)路徑根本不存在,這應(yīng)該是c#畫(huà)蛇添足了,要去掉" (x86)"。用System.Diagnostics.Process.Start(@"C:\Program Files (x86)\VideoLAN\VLC\vlc.exe", url);這樣就能調(diào)用了,算是解決了這個(gè)問(wèn)題。
后來(lái)我嘗試用System.Diagnostics.Process.Start(UICommon.Instance.GetExePathFromShortcut(Path.GetFullPath("vlc.exe.lnk")), url);結(jié)果又傻眼了,發(fā)現(xiàn)調(diào)用了這個(gè)函數(shù),vlc根本無(wú)法啟動(dòng)。后來(lái)打印日志,發(fā)現(xiàn)日志卡住了,這意思就是程序卡住了。后來(lái)干脆在項(xiàng)目的主函數(shù)里調(diào)用System.Diagnostics.Process.Start(UICommon.Instance.GetExePathFromShortcut(Path.GetFullPath("vlc.exe.lnk")), url);結(jié)果vlc能啟動(dòng),并且能正常打開(kāi)http的url。
在主函數(shù)里可以,在項(xiàng)目的其他代碼里不行,這非常奇怪。后來(lái)發(fā)現(xiàn)項(xiàng)目的其他代碼里新開(kāi)啟了線程,懷疑是線程的問(wèn)題。因此我在主函數(shù)里開(kāi)啟線程,然后在線程里調(diào)用System.Diagnostics.Process.Start(UICommon.Instance.GetExePathFromShortcut(Path.GetFullPath("vlc.exe.lnk")), url);測(cè)試結(jié)果是vlc無(wú)法啟動(dòng)。
這充分證明了我的猜想,UICommon.Instance.GetExePathFromShortcut(Path.GetFullPath("vlc.exe.lnk")這個(gè)方法只能在主線程里運(yùn)行,在其他線程里無(wú)法運(yùn)行。我在chatgpt里問(wèn)了下,chatgpt回復(fù)的如下:
1.該方法需要在主線程中執(zhí)行。因?yàn)?Shell32 命名空間對(duì)應(yīng)的 COM 組件在內(nèi)部使用了單線程模型(Single-Threaded Apartment, STA),必須在 UI 線程中執(zhí)行,否則會(huì)拋出異常。
2.如果你想在新線程中調(diào)用該方法,可以考慮將該方法封裝到一個(gè)帶有返回值的委托中,并使用 Control.Invoke() 或者 Control.BeginInvoke() 方法將其運(yùn)行在 UI 線程中。
最終的解決方案,不用根據(jù)快捷方式獲取程序路徑,在調(diào)用System.Diagnostics.Process.Start(Path.GetFullPath("vlc.exe.lnk"), url)之前,先判斷"C:\Program Files (x86)\VideoLAN\VLC\vlc.exe"和"C:\Program Files\VideoLAN\VLC\vlc.exe"是否存在。如果存在,就直接用已經(jīng)存在的vlc路徑;如果不存在,就用"vlc.exe.lnk"這個(gè)快捷方式。