想要喚起本地已安裝應用程序,我想到的有三種可行的方法:
第一種就是打開本地的快捷方式(有的應用可能沒有快捷方式,但這種方法效率最高,可配合其他方法使用),快捷方式分為本地桌面快捷方式和開始菜單中的快捷方式兩種。
下面講找出快捷方式路徑的方法:
本地桌面快捷方式:用戶可能更改過默認的桌面路徑,此時以前添加的快捷方式還在默認的c盤下路徑,之后創建的快捷方式則會在新的桌面路徑之下。
因此我們首先獲取到當前桌面的目錄地址,代碼如下:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); //在path后面拼上 應用的名字.lnk 就是快捷方式的路徑啦
如果未更改過桌面目錄,默認的c盤路徑如下:
"C:\Users\Public\Desktop\" + appName + ".lnk"
開始菜單的快捷方式:(默認主要有兩種,在后面拼上應用的名字.lnk 就是快捷方式的路徑啦)
C:\ProgramData\Microsoft\Windows\Start Menu\Programs C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
然后把打開對應路徑下的文件就可以實現打開本地快捷方式啦。
打開的方法主要有三種:(詳情可查看此篇文章https://www.cnblogs.com/y-yp/p/8782641.html),我只是用了下面這種,原因是比較簡單:
System.Diagnostics.Process.Start(@"C:\Users\Public\Desktop\" + appName + ".lnk");
此方法打開失敗會返回異常,因此要用try{}catch{}語句把上面四種可能的快捷方式遍歷一遍,並使其忽略返回的異常信息。
當然這種方法顯然不是特別的完美,可在遍歷完之后,未找到應用的情況下再去注冊表中查找應用程序的可執行(.exe)文件的路徑,也就是第二種方法。
第二種就是查找注冊表,找出應用程序的安裝路徑,然后運行其中的.exe文件,如下:
由於win10和win7注冊表結構有些不同,我們首先需要判斷系統的版本,然后執行不同版本的代碼即可:
1 Version currentVersion = Environment.OSVersion.Version; 2 Version compareToVersion = new Version("6.2"); 3 if (currentVersion.CompareTo(compareToVersion) >= 0) 4 { 5 //win8及其以上版本的系統 6 }else{ 7 // win7及其以下版本的系統 8 }
win10主要在HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Store下,里面直接存放的就是.exe文件的路徑,代碼如下:

1 //win8及其以上版本的系統 2 using (RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Store")) 3 { 4 if (key != null) 5 { 6 bool isFind = false; 7 string[] sname = key.GetValueNames(); 8 for (int i = 0; i < sname.Length; i++) 9 { 10 if (sname[i].ToString().Substring(0, 2) == "C:" || sname[i].ToString().Substring(0, 2) == "D:" || sname[i].ToString().Substring(0, 2) == "E:" || sname[i].ToString().Substring(0, 2) == "F:" || sname[i].ToString().Substring(0, 2) == "G:" || sname[i].ToString().Substring(0, 2) == "H:") 11 12 //查到的注冊表可能有SIGN.MEDIA=2CE47846 VS2010\setup.exe,E:\win10\Opera\launcher.exe,需要判斷 13 { 14 int ss = sname[i].ToString().LastIndexOf("\\"); 15 string s = sname[i].ToString().Substring(ss, sname[i].Length - ss); 16 string sss = s.Substring(1, s.Length - 1); 17 if (sss == appName.Text.Trim() + ".exe") 18 { 19 MessageBox.Show(sname[i].ToString()); 20 try 21 { 22 System.Diagnostics.Process.Start(@sname[i].ToString()); 23 isFind = true; 24 break; 25 } 26 catch { 27 continue; 28 } 29 } 30 } 31 } 32 if(!isFind){ 33 MessageBox.Show("未找到應用,換個名字試試吧!"); 34 } 35 } 36 } 37 }
win7主要有三個目錄,里面存放的是有應用相關命名的文件夾,內部有個 InstallLocation 字符串,其值是文件的安裝路徑,需再拼上 .exe文件名 + “.exe”(特例:QQ需要先進入Bin目錄下):
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall 此為64位應用的路徑。
注意:此處需要將winform窗體改為64位應用,否則打開上述路徑會被微軟重定向到下面32位的目錄。操作如下:
右鍵項目-->屬性-->生成,勾選掉首選32位。
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall 此為32位應用的路徑
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
代碼如下,把三個路徑都加以實現即可:

1 using (RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", false)) 2 { 3 if (key != null) 4 { 5 //foreach (string keyName in key.GetSubKeyNames()) 6 string[] SubK = key.GetSubKeyNames(); 7 MessageBox.Show("length:" + SubK.Length); 8 for (int i = 0; i < SubK.Length; i++) 9 { 10 //MessageBox.Show(SubK[i]); 11 using (RegistryKey key2 = key.OpenSubKey(appName.Text.Trim(), false)) 12 { 13 if (key2 != null) 14 { 15 string installLocation = key2.GetValue("InstallLocation", "").ToString(); 16 if (!string.IsNullOrEmpty(installLocation)) 17 { 18 MessageBox.Show("路徑:" + installLocation); 19 try 20 { 21 System.Diagnostics.Process.Start(@installLocation + "\\" + win7_txt.Text.Trim()); 22 isFind2 = true; 23 break; 24 } 25 catch 26 { 27 MessageBox.Show("別循環!"); 28 } 29 } 30 } 31 } 32 } 33 if (!isFind2) 34 { 35 MessageBox.Show("未找到應用,換個名字試試吧!"); 36 } 37 } 38 }
第三種方法就是使用user32.dll提供的API:FindWindowA和ShowWindow,這種方法很簡單,但是這個方法只能打開已經在后台運行的應用(如果有更好的API請大佬下方留言)。
首先在CLASS在聲明API與常量:
1 [DllImport("user32.dll", EntryPoint = "FindWindowA")] 2 private extern static IntPtr FindWindowA(string lpClassName, string lpWindowName); 3 4 [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)] 5 public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); 6 public const int SW_SHOWMAXIMIZED = 3; 7 public const int SW_SHOWNORMAL = 4;
然后調用即可:
1 IntPtr hwnd = FindWindowA("WechatMainWndForPC", null); 2 if (hwnd != IntPtr.Zero) 3 { 4 MessageBox.Show("找到窗口"); 5 ShowWindow(hwnd, 3); 6 } 7 else 8 { 9 MessageBox.Show("沒有找到窗口"); 10 }
其中FindWindowA需要兩個參數(目標窗口類名,目標窗口標題),返回一個窗口的句柄(整數型),其中本地已打開窗口的標題(通用,一次獲取后面即可通過findWindowA調用,類名獲取未找到方法,還請大佬可以指導一下)可用py腳本獲取:
1 #! /usr/bin/env python 2 # -*- coding: utf-8 -*- 3 from win32gui import * 4 titles = set() 5 def foo(hwnd,mouse): 6 #去掉下面這句就所有都輸出了,但是我不需要那么多 7 if IsWindow(hwnd) and IsWindowEnabled(hwnd) and IsWindowVisible(hwnd): 8 titles.add(GetWindowText(hwnd)) 9 EnumWindows(foo, 0) 10 lt = [t for t in titles if t] 11 lt.sort() 12 for t in lt: 13 print(t)
然后ShowWindow中傳入FindWindowA得到的句柄和窗口的顯示命令兩個參數即可。
ShowWindow第二個參數:
SW_HIDE 隱藏窗口,活動狀態給令一個窗口
SW_MINIMIZE 最小化窗口,活動狀態給令一個窗口
SW_RESTORE 用原來的大小和位置顯示一個窗口,同時令其進入活動狀態
SW_SHOW 用當前的大小和位置顯示一個窗口,同時令其進入活動狀態
SW_SHOWMAXIMIZED 最大化窗口,並將其激活
SW_SHOWMINIMIZED 最小化窗口,並將其激活
SW_SHOWMINNOACTIVE 最小化一個窗口,同時不改變活動窗口
SW_SHOWNA 用當前的大小和位置顯示一個窗口,不改變活動窗口
SW_SHOWNOACTIVATE 用最近的大小和位置顯示一個窗口,同時不改變活動窗口
SW_SHOWNORMAL 與SW_RESTORE相同