Làm cách nào để cài đặt các ứng dụng trong hệ thống bằng mã c #?
Câu trả lời:
Lặp lại thông qua khóa đăng ký "SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" dường như cung cấp một danh sách đầy đủ các ứng dụng đã cài đặt.
Ngoài ví dụ bên dưới, bạn có thể tìm thấy một phiên bản tương tự như những gì tôi đã làm ở đây .
Đây là một ví dụ sơ bộ, bạn sẽ muốn làm gì đó để loại bỏ các hàng trống như trong liên kết thứ 2 được cung cấp.
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using(Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach(string subkey_name in key.GetSubKeyNames())
{
using(RegistryKey subkey = key.OpenSubKey(subkey_name))
{
Console.WriteLine(subkey.GetValue("DisplayName"));
}
}
}
Ngoài ra, bạn có thể sử dụng WMI như đã được đề cập:
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"]);
}
Nhưng điều này khá chậm hơn để thực thi và tôi đã nghe nói rằng nó có thể chỉ liệt kê các chương trình được cài đặt trong "ALLUSERS", mặc dù điều đó có thể không chính xác. Nó cũng bỏ qua các thành phần và cập nhật Windows, có thể hữu ích cho bạn.
Bạn có thể xem qua bài viết này . Nó sử dụng registry để đọc danh sách các ứng dụng đã cài đặt.
public void GetInstalledApps()
{
string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(uninstallKey))
{
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
lstInstalled.Items.Add(sk.GetValue("DisplayName"));
}
catch (Exception ex)
{ }
}
}
}
}
Tôi đồng ý rằng liệt kê thông qua khóa đăng ký là cách tốt nhất.
Tuy nhiên, lưu ý rằng khóa được cung cấp, @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
sẽ liệt kê tất cả các ứng dụng trong cài đặt Windows 32 bit và các ứng dụng 64 bit trong cài đặt Windows 64 bit.
Để xem các ứng dụng 32-bit được cài đặt trên bản cài đặt Windows 64-bit, bạn cũng cần phải liệt kê khóa @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
.
regedit
đó có vẻ như vậy. Tuy nhiên, trong chương trình 32 bit (trên Windows 64 bit), cả hai danh sách đều giống với danh sách WOW6432Node
từ regedit
.
Tôi muốn có thể trích xuất danh sách ứng dụng ngay khi chúng xuất hiện trong menu bắt đầu. Sử dụng sổ đăng ký, tôi nhận được các mục nhập không hiển thị trong menu bắt đầu.
Tôi cũng muốn tìm đường dẫn exe và trích xuất một biểu tượng để cuối cùng tạo ra một launcher đẹp mắt. Thật không may, với phương pháp đăng ký, đây là một sự cố và bỏ lỡ vì quan sát của tôi là thông tin này không có sẵn một cách đáng tin cậy.
Giải pháp thay thế của tôi dựa trên shell: AppsFolder mà bạn có thể truy cập bằng cách chạy explorer.exe shell:appsFolder
và liệt kê tất cả các ứng dụng, bao gồm các ứng dụng cửa hàng, hiện đã được cài đặt và có sẵn thông qua menu bắt đầu. Vấn đề là đây là một thư mục ảo không thể truy cập được System.IO.Directory
. Thay vào đó, bạn sẽ phải sử dụng các lệnh shell32 bản địa. May mắn thay, Microsoft đã xuất bản Microsoft.WindowsAPICodePack-Shell trên Nuget, một trình bao bọc cho các lệnh nói trên. Nói đủ rồi, đây là mã:
// GUID taken from https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid
var FOLDERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FOLDERID_AppsFolder);
foreach (var app in (IKnownFolder)appsFolder)
{
// The friendly app name
string name = app.Name;
// The ParsingName property is the AppUserModelID
string appUserModelID = app.ParsingName; // or app.Properties.System.AppUserModel.ID
// You can even get the Jumbo icon in one shot
ImageSource icon = app.Thumbnail.ExtraLargeBitmapSource;
}
Và đó là tất cả những gì cần làm. Bạn cũng có thể khởi động các ứng dụng bằng
System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);
Điều này hoạt động cho các ứng dụng Win32 thông thường và các ứng dụng cửa hàng UWP. Làm thế nào về họ táo.
Vì bạn quan tâm đến việc liệt kê tất cả các ứng dụng đã cài đặt, điều hợp lý là bạn có thể muốn theo dõi các ứng dụng mới hoặc ứng dụng đã gỡ cài đặt, bạn có thể thực hiện bằng cách sử dụng ShellObjectWatcher
:
ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();
Chỉnh sửa: Một người cũng có thể quan tâm đến việc biết rằng AppUserMoedlID được đề cập ở trên là ID duy nhất mà Windows sử dụng để nhóm các cửa sổ trong thanh tác vụ .
AllEvents
như ItemCreated
hoặc loại sự kiện ItemRenamed
mà tôi đã thử sử dụng để theo dõi các ứng dụng khi chúng được cài đặt hoặc gỡ bỏ. Các chuỗi sự kiện của các sự kiện này chứa một thuộc Path
tính nhưng thuộc tính này luôn là null, ít nhất là trong các thử nghiệm của tôi. Tôi không bận tâm khi cố gắng tìm cách lấy tên phân tích cú pháp từ nó vì nó luôn rỗng. Thay vào đó, tôi chỉ cần giữ một danh sách các ứng dụng mà tôi đồng bộ hóa bất cứ khi nào một mục được nâng lên bằng cách lặp lại các ứng dụng trong thư mục. Không lý tưởng nhưng hoàn thành công việc.
cần lưu ý rằng lớp WMI Win32_Product đại diện cho các sản phẩm khi chúng được cài đặt bởi Windows Installer . không phải mọi ứng dụng đều sử dụng trình cài đặt windows
tuy nhiên "SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" đại diện cho các ứng dụng cho 32 bit. Đối với 64 bit, bạn cũng cần xem qua "HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall" và vì không phải mọi phần mềm đều có phiên bản 64 bit nên tổng số ứng dụng được cài đặt là một tổ hợp khóa trên cả hai vị trí có "UninstallString" Giá trị với họ.
nhưng các tùy chọn tốt nhất vẫn giống nhau. khóa đăng ký chuyển đổi là một cách tiếp cận tốt hơn vì mọi ứng dụng đều có mục nhập trong sổ đăng ký [bao gồm cả những mục trong Windows Installer]. dù phương pháp đăng ký không an toàn vì nếu ai xóa khóa tương ứng thì bạn sẽ không biết Ngược lại, việc thay đổi HKEY_Classes_ROOT \ Installers phức tạp hơn vì nó được liên kết với các vấn đề cấp phép như Microsoft office hoặc các sản phẩm khác. để có giải pháp mạnh mẽ hơn, bạn luôn có thể kết hợp thay thế sổ đăng ký với WMI.
Trong khi giải pháp được chấp nhận hoạt động, nó không hoàn chỉnh. Cho đến nay.
Nếu muốn lấy hết chìa khóa, bạn cần lưu ý thêm 2 điều:
Các ứng dụng x86 & x64 không có quyền truy cập vào cùng một sổ đăng ký. Về cơ bản x86 thường không thể truy cập sổ đăng ký x64. Và một số ứng dụng chỉ đăng ký vào sổ đăng ký x64.
và
một số ứng dụng thực sự cài đặt vào sổ đăng ký CurrentUser thay vì LocalMachine
Với ý nghĩ đó, tôi đã quản lý để tải TẤT CẢ các ứng dụng được cài đặt bằng mã sau đây, KHÔNG sử dụng WMI
Đây là mã:
List<string> installs = new List<string>();
List<string> keys = new List<string>() {
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
};
// The RegistryView.Registry64 forces the application to open the registry as x64 even if the application is compiled as x86
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64), keys, installs);
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64), keys, installs);
installs = installs.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList();
installs.Sort(); // The list of ALL installed applications
private void FindInstalls(RegistryKey regKey, List<string> keys, List<string> installed)
{
foreach (string key in keys)
{
using (RegistryKey rk = regKey.OpenSubKey(key))
{
if (rk == null)
{
continue;
}
foreach (string skName in rk.GetSubKeyNames())
{
using (RegistryKey sk = rk.OpenSubKey(skName))
{
try
{
installed.Add(Convert.ToString(sk.GetValue("DisplayName")));
}
catch (Exception ex)
{ }
}
}
}
}
}
Lặp lại các khóa "HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall" và kiểm tra các giá trị "DisplayName" của chúng.
Sử dụng API của trình cài đặt Windows!
Nó cho phép liệt kê đáng tin cậy tất cả các chương trình. Registry không đáng tin cậy, nhưng WMI là nặng.
Đối tượng cho danh sách:
public class InstalledProgram
{
public string DisplayName { get; set; }
public string Version { get; set; }
public string InstalledDate { get; set; }
public string Publisher { get; set; }
public string UnninstallCommand { get; set; }
public string ModifyPath { get; set; }
}
Lời kêu gọi tạo danh sách:
List<InstalledProgram> installedprograms = new List<InstalledProgram>();
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
if (subkey.GetValue("DisplayName") != null)
{
installedprograms.Add(new InstalledProgram
{
DisplayName = (string)subkey.GetValue("DisplayName"),
Version = (string)subkey.GetValue("DisplayVersion"),
InstalledDate = (string)subkey.GetValue("InstallDate"),
Publisher = (string)subkey.GetValue("Publisher"),
UnninstallCommand = (string)subkey.GetValue("UninstallString"),
ModifyPath = (string)subkey.GetValue("ModifyPath")
});
}
}
}
}
Như những người khác đã chỉ ra, câu trả lời được chấp nhận không trả về cả cài đặt x86 và x64. Dưới đây là giải pháp của tôi cho điều đó. Nó tạo một StringBuilder
, nối các giá trị đăng ký vào nó (với định dạng) và ghi đầu ra của nó vào một tệp văn bản:
const string FORMAT = "{0,-100} {1,-20} {2,-30} {3,-8}\n";
private void LogInstalledSoftware()
{
var line = string.Format(FORMAT, "DisplayName", "Version", "Publisher", "InstallDate");
line += string.Format(FORMAT, "-----------", "-------", "---------", "-----------");
var sb = new StringBuilder(line, 100000);
ReadRegistryUninstall(ref sb, RegistryView.Registry32);
sb.Append($"\n[64 bit section]\n\n{line}");
ReadRegistryUninstall(ref sb, RegistryView.Registry64);
File.WriteAllText(@"c:\temp\log.txt", sb.ToString());
}
private static void ReadRegistryUninstall(ref StringBuilder sb, RegistryView view)
{
const string REGISTRY_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
using var subKey = baseKey.OpenSubKey(REGISTRY_KEY);
foreach (string subkey_name in subKey.GetSubKeyNames())
{
using RegistryKey key = subKey.OpenSubKey(subkey_name);
if (!string.IsNullOrEmpty(key.GetValue("DisplayName") as string))
{
var line = string.Format(FORMAT,
key.GetValue("DisplayName"),
key.GetValue("DisplayVersion"),
key.GetValue("Publisher"),
key.GetValue("InstallDate"));
sb.Append(line);
}
key.Close();
}
subKey.Close();
baseKey.Close();
}
Đặt cược tốt nhất của bạn là sử dụng WMI . Cụ thể là lớp Win32_Product .
Có thể tôi khuyên bạn nên xem qua WMI ( Công cụ quản lý Windows ). Nếu bạn thêm tham chiếu System.Management vào dự án C # của mình, bạn sẽ có quyền truy cập vào lớp ManagementObjectSearcher, lớp mà bạn có thể sẽ thấy hữu ích.
Có nhiều lớp WMI khác nhau cho các ứng dụng đã cài đặt , nhưng nếu nó được cài đặt bằng Windows Installer, thì lớp Win32_Product có lẽ phù hợp nhất với bạn.
ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Tôi đã sử dụng phương pháp tiếp cận Nicks - Tôi cần kiểm tra xem Công cụ Từ xa cho Visual Studio đã được cài đặt hay chưa, nó có vẻ hơi chậm, nhưng trong một chuỗi riêng biệt, điều này là tốt cho tôi. - đây là mã mở rộng của tôi:
private bool isRdInstalled() {
ManagementObjectSearcher p = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach (ManagementObject program in p.Get()) {
if (program != null && program.GetPropertyValue("Name") != null && program.GetPropertyValue("Name").ToString().Contains("Microsoft Visual Studio 2012 Remote Debugger")) {
return true;
}
if (program != null && program.GetPropertyValue("Name") != null) {
Trace.WriteLine(program.GetPropertyValue("Name"));
}
}
return false;
}
Yêu cầu của tôi là kiểm tra xem phần mềm cụ thể đã được cài đặt trong hệ thống của tôi chưa. Giải pháp này hoạt động như mong đợi. Nó có thể giúp bạn. Tôi đã sử dụng một ứng dụng windows trong c # với visual studio 2015.
private void Form1_Load(object sender, EventArgs e)
{
object line;
string softwareinstallpath = string.Empty;
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
using (var key = baseKey.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (var subKey = key.OpenSubKey(subkey_name))
{
line = subKey.GetValue("DisplayName");
if (line != null && (line.ToString().ToUpper().Contains("SPARK")))
{
softwareinstallpath = subKey.GetValue("InstallLocation").ToString();
listBox1.Items.Add(subKey.GetValue("InstallLocation"));
break;
}
}
}
}
}
if(softwareinstallpath.Equals(string.Empty))
{
MessageBox.Show("The Mirth connect software not installed in this system.")
}
string targetPath = softwareinstallpath + @"\custom-lib\";
string[] files = System.IO.Directory.GetFiles(@"D:\BaseFiles");
// Copy the files and overwrite destination files if they already exist.
foreach (var item in files)
{
string srcfilepath = item;
string fileName = System.IO.Path.GetFileName(item);
System.IO.File.Copy(srcfilepath, targetPath + fileName, true);
}
return;
}