C#で実行ファイルの会社名にMicrosoftを含むレジストリに登録されたCOMクラスを選択する方法
C#、Windows 10でレジストリに登録されたCOMクラスから実行ファイルの会社名にMicrosoftを含むものを選択するソースコードです。
概要
レジストリのアクセスにはMicrosoft.Win32名前空間のRegistryKeyクラス、実行ファイル(exe、dll)のバージョン情報取得にはSystem.Diagnostics名前空間のFileVersionInfoクラスを使用することができます。
ソースコード
// 参照:System 4.0.0, System.Core 4.0.0 // 環境:.NET Framework 4.7.2, C# 7.2 using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using Microsoft.Win32; namespace ConsoleApp1 { static class Program { static void Main() { // レジストリに登録されたCOMクラスのProgIDとCLSID列挙 var progIdAndCLSIDs = GetRegistedProgIDAndCLSID( RegistryView.Registry64); // CLSIDの情報取得 var clsidInfos = default(IEnumerable<CLSIDInfo>); using (var classesRootKey = RegistryKey.OpenBaseKey( RegistryHive.ClassesRoot, RegistryView.Registry64)) { clsidInfos = progIdAndCLSIDs.Values.Select( clsid => CLSIDInfo.Get(clsid, classesRootKey)); } // CLSID情報→FileVersionInfo var inProcServer32ClsidInfos = clsidInfos .Where(clsidInfo => clsidInfo.InProcServer32 != null); var clsidIdAndFileVerInfos = inProcServer32ClsidInfos .Select(clsidInfo => { try { return ( CLSIDInfo: clsidInfo, FileVerInfo: FileVersionInfo.GetVersionInfo( clsidInfo.InProcServer32)); } catch { return ( CLSIDInfo: clsidInfo, FileVerInfo: null); } }) .ToArray(); //評価実行 // FileVersionInfo.CompanyNameにMicrosoftが含まれる要素の抽出 var microsoftClsidIdAndFileVerInfos = clsidIdAndFileVerInfos .Where(info => { try { return info.FileVerInfo.CompanyName .Contains("Microsoft"); } catch { return false; } }) .ToArray(); #if true // 概要のCSV出力(強制上書き) using (var fo = File.OpenWrite("result.csv")) { var writer = new StreamWriter(fo, Encoding.Unicode); foreach (var info in microsoftClsidIdAndFileVerInfos) { writer.Write($"{info.CLSIDInfo.Description?.Replace('\t', ' ')}"); writer.Write("\t"); writer.Write($"{info.CLSIDInfo.ProgID?.Replace('\t', ' ')}"); writer.Write(","); writer.Write($"{info.FileVerInfo.FileDescription?.Replace('\t', ' ')}"); writer.WriteLine(); } } #else // 概要の文字列変換(デバッガーで確認用) var result = string.Join<string>( Environment.NewLine, microsoftClsidIdAndFileVerInfos.Select( (info, i) => $"{i:0000}:{info.CLSIDInfo.Description}-{info.CLSIDInfo.ProgID}-{info.FileVerInfo.FileDescription}")); #endif } [DebuggerDisplay("{Description}-{CLSID}")] public sealed class CLSIDInfo { #region コンストラクタ private CLSIDInfo() { } public static CLSIDInfo Get(string clsid, RegistryView view) { // 不正な文字列対策のため、意図的にGUIDへの変換を試みます。 return Get(Guid.ParseExact(clsid, "B"), view); } public static CLSIDInfo Get(Guid guid, RegistryView view) { using (var key = RegistryKey.OpenBaseKey( RegistryHive.ClassesRoot, view)) { var info = new CLSIDInfo(); info.Parse(guid, key); return info; } } public static CLSIDInfo Get(string clsid, RegistryKey classesRootKey) { // 不正な文字列対策のため、意図的にGUIDへの変換を試みます。 return Get(Guid.ParseExact(clsid, "B"), classesRootKey); } public static CLSIDInfo Get(Guid guid, RegistryKey classesRootKey) { var info = new CLSIDInfo(); info.Parse(guid, classesRootKey); return info; } #endregion public string CLSID { get; private set; } public string Description { get; private set; } public string InProcServer32 { get; private set; } public string InProcServer32ThreadingModel { get; private set; } public string ProgID { get; private set; } public string Version { get; private set; } public string VersionIndependentProgID { get; private set; } private void Parse(Guid guid, RegistryKey classsessRootKey) { CLSID = guid.ToString("B"); using (var clsidKey = classsessRootKey.OpenSubKey( "CLSID\\" + CLSID, false)) { if (clsidKey == null) return; Description = (string)clsidKey.GetValue(null); using (var key = clsidKey.OpenSubKey("InProcServer32", false)) { InProcServer32 = (string)key?.GetValue(null); InProcServer32ThreadingModel = (string)key?.GetValue("ThreadingModel"); } using (var key = clsidKey.OpenSubKey("ProgID", false)) { ProgID = (string)key?.GetValue(null); } using (var key = clsidKey.OpenSubKey("Version", false)) { Version = (string)key?.GetValue(null); } using (var key = clsidKey.OpenSubKey("VersionIndependentProgID", false)) { VersionIndependentProgID = (string)key?.GetValue(null); } } } } public static IDictionary<string, string> GetRegistedProgIDAndCLSID( RegistryView view) { var pairs = new Dictionary<string, string>(); using (var classesRootKey = RegistryKey.OpenBaseKey( RegistryHive.ClassesRoot, view)) { foreach (var name in classesRootKey.GetSubKeyNames()) { using (var key = classesRootKey.OpenSubKey( name + @"\CLSID", false)) { var value = key?.GetValue(null); if (!(value is null)) { pairs.Add(name, (string)value); } } } return pairs; } } } }
出力例(抜粋)
TaskScheduler class Schedule.Service.1,Task Scheduler COM API TaskScheduler class Schedule.Service.1,Task Scheduler COM API Moniker to a Windows Script Component script,Windows ® Script Component Runtime Microsoft Scriptlet Component ScriptBridge.ScriptBridge.1,Microsoft(R) HTML ビューアー CScriptedDiag ScriptedDiag.Engine.1,スクリプト化された診断の実行エンジン CScriptedDiag ScriptedDiag.Engine.1,スクリプト化された診断の実行エンジン Scripting.Dictionary Scripting.Dictionary,Microsoft ® Script Runtime Script Encoder Object Scripting.Encoder,Microsoft ® Script Runtime FileSystem Object Scripting.FileSystemObject,Microsoft ® Script Runtime Scripting.Signer Scripting.Signer,Microsoft ® Shell Extension for Windows Script Host Moniker to a Windows Script Component script,Windows ® Script Component Runtime Constructor that allows hosts better control creating scriptlets Scriptlet.Constructor,Windows ® Script Component Runtime Object under which scriptlets may be created Scriptlet.Context,Windows ® Script Component Runtime Factory bindable using IPersistMoniker Scriptlet.Factory,Windows ® Script Component Runtime Object for encoding scriptlets Scriptlet.HostEncode,Windows ® Script Component Runtime Object for constructing type libraries for scriptlets Scriptlet.TypeLib,Windows ® Script Component Runtime Factory bindable using IPersistMoniker Scriptlet.Factory,Windows ® Script Component Runtime Constructor for Scriptlet ASP Handler ScriptletHandler.ASP,Windows ® Script Component Runtime Constructor for Scriptlet Automation Handler ScriptletHandler.Automation,Windows ® Script Component Runtime Constructor for Scriptlet Behavior Handler ScriptletHandler.Behavior,Windows ® Script Component Runtime Constructor for Scriptlet Event Handler ScriptletHandler.Event,Windows ® Script Component Runtime ScriptoSys Class ScriptoSys.Scripto.1,Microsoft ScriptO App Content Filter Search.AppContentFilter.1,Microsoft WinRT ストレージ API App Content Filter Search.AppContentFilter.1,Microsoft WinRT ストレージ API Windows Search Data Source Search.CollatorDSO.1,Microsoft Tripoli Query Windows Search Data Source Search.CollatorDSO.1,Microsoft Tripoli Query Search command creator object Search.CommandCreator.1,Microsoft Tripoli Query Search command creator object Search.CommandCreator.1,Microsoft Tripoli Query Windows Search Service Client Side Cache Protocol Handler Search.CscHandler.1,MSSearch Vista プラットフォーム Windows Search Service Client Side Cache Protocol Handler Search.CscHandler.1,MSSearch Vista プラットフォーム
補足説明
COMクラスの登録場所
COMクラスの情報はHKCRキー\<ProgID>キーおよびHKCR\CLSID\<CLSID>キーに分散して登録されています。ProgIDはCOMクラスのユーザーが利用しやすい名前であり、<ProgID>キーはCLSIDサブキーの既定値に詳細情報の登録されるCLSIDを持ちます。<CLSID>キーはCOMクラスの実行ファイルの場所等の詳細な情報を持ちます。
64ビットOSではWOW64が有効になることに注意してください。
レジストリとWOW64
HKCR(HKEY_CLASSESS_ROOT)へのアクセス時、RegistryKey.OpenBaseKey関数でRegistryView.Registry64を指定しないとWOW64(32ビット環境、Wow6432Nodeキー配下キーへのリダイレクト)の影響を受けることに注意してください。
なお、32ビットOSでRegistryView.Registry64を指定した場合、自動的に32ビットビューが使用されます(RegistryView Enum (Microsoft.Win32) | Microsoft Docs)。
名前付きタプル
C# 7.2では以下の形式で名前付きタプルを作成することができます。詳細はタプル型 - C# ガイド | Microsoft Docsをご覧ください。
(Name1: value1, Name2: value2)
インデックス付きSelect
LINQのSelectメソッドは二番目の引数を与えることで0ベースのインデックスを使用することができます。
// "あ0","い1","う2" var ss = new[]{"あ","い","う"}.Select((s, i) => s+i);