C#コードを使用してシステムにアプリケーションをインストールする方法は?
回答:
レジストリキー「SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall」を繰り返すと、インストールされているアプリケーションの包括的なリストが表示されるようです。
以下の例とは別に、私がここで行ったことと同様のバージョンを見つけることができます。
これは大まかな例です。提供されている2番目のリンクのように、空白行を取り除くために何かをしたいと思うでしょう。
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"));
}
}
}
または、前述のようにWMIを使用することもできます。
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
Console.WriteLine(mo["Name"]);
}
しかし、これは実行にかなり時間がかかり、「ALLUSERS」の下にインストールされたプログラムのみがリストされる可能性があると聞きましたが、それは正しくない可能性があります。また、Windowsのコンポーネントとアップデートも無視されます。これは便利な場合があります。
あなたはこの記事を見ることができます。レジストリを利用して、インストールされているアプリケーションのリストを読み取ります。
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)
{ }
}
}
}
}
レジストリキーを介して列挙することが最善の方法であることに同意します。
ただし、指定されたキー@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
は、32ビットのWindowsインストールではすべてのアプリケーションを一覧表示し、Windows64ビットのインストールでは64ビットのアプリケーションを一覧表示することに注意してください。
Windows 64ビットインストールにインストールされている32ビットアプリケーションも表示するには、キーを列挙する必要もあります@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
。
regedit
、それはそう思えます。ただし、32ビットプログラム(64ビットWindows)では、両方のリストはからのWOW6432Node
ものと同じです regedit
。
スタートメニューに表示されるとおりにアプリのリストを抽出できるようにしたかったのです。レジストリを使用して、スタートメニューに表示されないエントリを取得していました。
また、exeパスを見つけてアイコンを抽出し、最終的に見栄えの良いランチャーを作成したいと思いました。残念ながら、レジストリ方式では、この情報が確実に利用可能ではないという私の観察から、これは一種のヒットとミスです。
私の代替案は、実行explorer.exe shell:appsFolder
してアクセスできるshell:AppsFolderに基づいており、ストアアプリを含む、現在インストールされており、スタートメニューから利用できるすべてのアプリが一覧表示されます。問題は、これがでアクセスできない仮想フォルダであるということSystem.IO.Directory
です。代わりに、ネイティブのshell32コマンドを使用する必要があります。幸い、MicrosoftはMicrosoft.WindowsAPICodePack-ShellをNugetで公開しました。これは、前述のコマンドのラッパーです。十分に言った、ここにコードがあります:
// 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;
}
そして、それがすべてです。を使用してアプリを起動することもできます
System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);
これは、通常のWin32アプリとUWPストアアプリで機能します。りんごはどうですか。
インストールされているすべてのアプリを一覧表示することに関心があるため、新しいアプリやアンインストールされたアプリも監視することをお勧めします。これは、ShellObjectWatcher
次を使用して実行できます。
ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();
編集:上記のAppUserMoedlIDは、Windowsがタスクバーのウィンドウをグループ化するために使用する一意のIDであることを知りたいと思うかもしれません。
AllEvents
、ItemCreated
またはItemRenamed
それ以外のイベントタイプがあります。これらのイベントのイベント引数にはPath
プロパティが含まれていますが、少なくとも私のテストでは、このプロパティは常にnullです。常にnullであるため、解析名を取得する方法をわざわざ理解しようとはしていません。代わりに、フォルダー内のアプリを反復処理してアイテムが発生するたびに同期するアプリのリストを保持するだけです。理想的ではありませんが、仕事を成し遂げます。
Win32_Product WMIクラスは、Windowsインストーラーによってインストールされる製品を表すことに注意してください。すべてのアプリケーションがWindowsインストーラーを使用するわけではありません
ただし、「SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall」は、32ビットのアプリケーションを表します。64ビットの場合は、「HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall」もトラバースする必要があります。すべてのソフトウェアに64ビットバージョンがあるわけではないため、インストールされるアプリケーションの総数は、「UninstallString」がある両方の場所のキーの和集合です。それらとの価値。
しかし、最良のオプションは同じままです。すべてのアプリケーションがレジストリにエントリを持っているので、レジストリキーをトラバースする方が良いアプローチです[Windowsインストーラーのエントリを含む]。ただし、レジストリメソッドは、誰かが対応するキーを削除するかのように安全ではありません。アプリケーションエントリ。逆に、HKEY_Classes_ROOT \ Installersの変更は、Microsoft Officeやその他の製品などのライセンスの問題に関連しているため、より注意が必要です。より堅牢なソリューションを実現するには、レジストリの代替手段をWMIといつでも組み合わせることができます。
受け入れられたソリューションは機能しますが、完全ではありません。はるかに。
すべてのキーを取得する場合は、さらに2つのことを考慮する必要があります。
x86およびx64アプリケーションは、同じレジストリにアクセスできません。基本的に、x86は通常x64レジストリにアクセスできません。また、一部のアプリケーションはx64レジストリにのみ登録します。
そして
一部のアプリケーションは、LocalMachineではなくCurrentUserレジストリに実際にインストールされます
このことを念頭に置いて、私は、ALLは、次のコードを使用してアプリケーションをインストールし得ることをどうにかなしWMIを使用して
コードは次のとおりです。
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)
{ }
}
}
}
}
}
「HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall」キーを繰り返し処理し、それらの「DisplayName」値を確認します。
WindowsインストーラAPIを使用してください!
これにより、すべてのプログラムの信頼できる列挙を行うことができます。レジストリは信頼できませんが、WMIは重要です。
リストのオブジェクト:
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; }
}
リストを作成するための呼び出し:
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")
});
}
}
}
}
他の人が指摘しているように、受け入れられた回答はx86とx64の両方のインストールを返しません。以下はそのための私の解決策です。を作成しStringBuilder
、それにレジストリ値を(フォーマットを使用して)追加し、その出力をテキストファイルに書き込みます。
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();
}
最善の策は、WMIを使用することです。具体的には、Win32_Productクラスです。
WMI(Windows Management Instrumentation)をご覧になることをお勧めします。System.Management参照をC#プロジェクトに追加すると、クラス `ManagementObjectSearcher 'にアクセスできるようになります。これは、おそらく便利です。
インストールされているアプリケーションにはさまざまなWMIクラスがありますが、Windowsインストーラーを使用してインストールされている場合は、Win32_Productクラスがおそらく最適です。
ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Nicksのアプローチを使用しました-VisualStudioのリモートツールがインストールされているかどうかを確認する必要がありました。少し遅いようですが、別のスレッドではこれで問題ありません。-ここに私の拡張コード:
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;
}
私の要件は、特定のソフトウェアがシステムにインストールされているかどうかを確認することです。このソリューションは期待どおりに機能します。それはあなたを助けるかもしれません。Visual Studio 2015でC#のWindowsアプリケーションを使用しました。
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;
}