解決策を見つけました:
OK、私が知る限り、MEF メタデータで画像やアイコンを使用することはできません。ただし、EXE ファイルの場合と同様に、DLL ファイルにアイコンを割り当てることができます。アイコンは、.NET の Icon タイプに組み込まれた静的メソッドを使用して読み取ることができます。
Icon MyDLLIcon = Icon.ExtractAssociatedIcon(DLLFilePath);
リソース ファイルから文字列を MEF メタデータとして返せるのに、埋め込まれたアイコンや画像を返せない理由はまだよくわかりません。
ここ数日、プラグイン メニューにアイコンを提供する機能するサンプル プログラムをまとめようとしてきたので、誰かの役に立てばと思い、コードを投稿することにしました。
これは、次の機能を備えた完全に機能するサンプル プロジェクトです。
5 つのプロジェクト ( MainProgram、ContractInterfaces、PlugInA、PlugInB、PlugInC ) を持つ単一のソリューションを意図しています。
ビルド後のイベントは、DLL を各プロジェクトから共通の「プラグイン」フォルダーに自動的にコピーします。
MainProgram (WinForm) プロジェクトは、利用可能な DLL プラグインのカタログを構築し、ListView に各プラグインのアイコンとメタデータ タイトルを設定します。
ListView アイテムをダブルクリックすると、プラグインがインスタンス化され (Lazy インスタンス化を利用)、開始されます。
各プラグインは、起動時にメイン フォームへの参照を受け取り、新しい TextBox を作成し、それをメイン フォームにポストして、プラグインが実行され、GUI にアクセスできることを証明します。
選択したプラグインのタイトル、説明、およびバージョンのメタデータ値がコンソール ウィンドウに出力されます。
各DLLに異なるアイコンを割り当てました(古いVisual Studio 6 Common Graphics Miscフォルダーから)

ListView を作成するために DLL プラグインからアイコンが抽出され、TextBox が作成され、DLL が起動すると ( ListView の各プラグイン項目をダブルクリックした後)、DLL によって GUI にポストされました。
次のコードを「MainProgram」と呼ばれる新しい C# WinForm プロジェクトに追加します (私は VS 2010 を使用しました)。
何らかの理由でコード サンプル パーサーは Using ステートメントを好まないため、箇条書きとして以下に示します。
- システムを使用する;
- System.Collections.Generic の使用;
- System.ComponentModel.Composition を使用します。
- System.ComponentModel.Composition.Hosting の使用;
- System.Drawing を使用します。
- System.IO の使用;
- System.Windows.Forms を使用します。
- ContractInterfaces を使用します。
- (名前空間) MainProgram
public partial class Form1 : Form
{
// Prerequisites to run:
// 1) Project, Add Reference, Projects, ContractInterface
// 2) Project, Add Reference, .NET, System.ComponentModel.Composition
[ImportMany(typeof(IPlugIn))]
private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> LoadedPlugIns;
List<PlugInInfo> AvailablePlugIns = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Get a list of the available Plug-Ins
AvailablePlugIns = GetPlugInList();
// Prepare an ImageList to hold the DLL icons
ImageList ImgList = new ImageList();
ImgList.ColorDepth = ColorDepth.Depth32Bit;
ImgList.ImageSize = new Size(32, 32);
// Populate ImageList with Plug-In Icons
foreach (var item in AvailablePlugIns)
{
ImgList.Images.Add(item.PlugInIcon.ToBitmap());
}
// Assign the ImageList to the ListView
listView1.LargeImageList = ImgList;
int imageIndex = 0;
// Create the ListView items
foreach (var item in AvailablePlugIns)
{
listView1.Items.Add(item.PlugInTitle, imageIndex);
imageIndex++;
}
listView1.MouseDoubleClick += new MouseEventHandler(listView1_MouseDoubleClick);
}
void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
// Get the Plug-In index number
int plugInNum = listView1.SelectedItems[0].Index;
PlugInInfo selectedPlugIn = AvailablePlugIns[plugInNum];
// Call the StartPlugIn method in the selected Plug-In.
// Lazy Instantiation will fully load the Assembly here
selectedPlugIn.PlugIn.StartPlugIn(this);
Console.WriteLine("Plug-In Title: {0}", selectedPlugIn.PlugInTitle);
Console.WriteLine("Plug-In Description: {0}", selectedPlugIn.PlugInDescription);
Console.WriteLine("Plug-In Version: {0}", selectedPlugIn.PlugInVersion);
Console.WriteLine();
}
private List<PlugInInfo> GetPlugInList()
{
// Create a List to hold the info for each plug-in
List<PlugInInfo> plugInList = new List<PlugInInfo>();
// Set Plug-In folder path to same directory level as Solution
string plugInFolderPath = System.IO.Path.Combine(Application.StartupPath, @"..\..\..\Plug-Ins");
// Test if the Plug-In folder exists
if (!Directory.Exists(plugInFolderPath))
{
// Plug-In Folder is missing, so try to create it
try
{ Directory.CreateDirectory(plugInFolderPath); }
catch
{ MessageBox.Show("Failed to create Plug-In folder", "Folder Creation Error:", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); }
}
try
{
// Create a catalog of plug-ins
var catalog = new DirectoryCatalog(plugInFolderPath, "*.dll");
AggregateCatalog plugInCatalog = new AggregateCatalog();
plugInCatalog.Catalogs.Add(catalog);
CompositionContainer container = new CompositionContainer(plugInCatalog);
// This line will fetch the metadata from each plug-in and populate LoadedPlugIns
container.ComposeParts(this);
// Save each Plug-Ins metadata
foreach (var plugin in LoadedPlugIns)
{
PlugInInfo info = new PlugInInfo();
info.PlugInTitle = plugin.Metadata.PlugInTitle;
info.PlugInDescription = plugin.Metadata.PlugInDescription;
info.PlugInVersion = plugin.Metadata.PlugInVersion;
info.PlugIn = plugin.Value;
plugInList.Add(info);
}
int index = 0;
// Extract icons from each Plug-In DLL and store in Plug-In list
foreach (var filePath in catalog.LoadedFiles)
{
plugInList[index].PlugInIcon = Icon.ExtractAssociatedIcon(filePath);
index++;
}
}
catch (FileNotFoundException fex)
{
Console.WriteLine("File not found exception : " + fex.Message);
}
catch (CompositionException cex)
{
Console.WriteLine("Composition exception : " + cex.Message);
}
catch (DirectoryNotFoundException dex)
{
Console.WriteLine("Directory not found exception : " + dex.Message);
}
return plugInList;
}
}
public class PlugInInfo
{
public string PlugInTitle { get; set; }
public string PlugInDescription { get; set; }
public string PlugInVersion { get; set; }
public Icon PlugInIcon { get; set; }
public IPlugIn PlugIn { get; set; }
}
ここで、「listView1」という ListView コントロールをメイン フォームに追加し、フォームの右側に保持します。プラグインから動的に作成されたテキスト ボックスが左側に表示されます。
次に、「ContractInterfaces」というクラス プロジェクトを追加し、次のコードを含めます。
- System.Windows.Forms を使用します。
- (名前空間) ContractInterfaces
// Prerequisites to run:
// 1) Project, Add Reference, .NET, "System.Windows.Forms"
public interface IPlugIn
{
void StartPlugIn(Form mainForm);
}
public interface IPlugInMetadata
{
string PlugInTitle { get; }
string PlugInDescription { get; }
string PlugInVersion { get; }
}
次に、「PlugInA」というクラス プロジェクトを追加し、次のコードを含めます。
- システムを使用する;
- System.ComponentModel.Composition を使用します。
- System.Windows.Forms を使用します。
- ContractInterfaces を使用します。
- (名前空間) PlugInA
// Prerequisites to run:
// 1) Project, Add Reference, Projects, "ContractInterface"
// 2) Project, Add Reference, .NET, "System.Windows.Forms"
// 3) Project, Add Reference, .NET, "System.ComponentModel.Composition"
// 4) Project, Properties, Build Events, Post-Build event command line:
// xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y
// 5) Project, Properties, Build Events, Run the post-build event:, Always
// 6) Project, Properties, Application, Icon and manifest, [Select an icon]
[Export(typeof(IPlugIn))]
[PluginMetadata]
public class Program : IPlugIn
{
private Form MainForm;
public void StartPlugIn(Form mainForm)
{
MainForm = mainForm;
// Place a TextBox on the Main Form
TextBox textBox = new TextBox();
textBox.Text = "PlugInA";
MainForm.Controls.Add(textBox);
textBox.Width = 65;
textBox.Height = 20;
textBox.Top = 0;
textBox.Left = 0;
}
}
// Create a custom strong-typed Metadata Attribute for MEF
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginMetadataAttribute : ExportAttribute
{
public string PlugInTitle { get; set; }
public string PlugInDescription { get; set; }
public object PlugInVersion { get; set; }
public PluginMetadataAttribute()
: base(typeof(IPlugInMetadata))
{
PlugInTitle = "Plug-In A";
PlugInDescription = "This is Plug-In A";
PlugInVersion = "1.0.0.0";
}
}
次に、「PlugInB」というクラス プロジェクトを追加し、次のコードを含めます。
- システムを使用する;
- System.ComponentModel.Composition を使用します。
- System.Windows.Forms を使用します。
- ContractInterfaces を使用します。
- (名前空間) PlugInB
// Prerequisites to run:
// 1) Project, Add Reference, Projects, "ContractInterface"
// 2) Project, Add Reference, .NET, "System.Windows.Forms"
// 3) Project, Add Reference, .NET, "System.ComponentModel.Composition"
// 4) Project, Properties, Build Events, Post-Build event command line:
// xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y
// 5) Project, Properties, Build Events, Run the post-build event:, Always
// 6) Project, Properties, Application, Icon and manifest, [Select an icon]
[Export(typeof(IPlugIn))]
[PluginMetadata]
public class Program : IPlugIn
{
private Form MainForm;
public void StartPlugIn(Form mainForm)
{
MainForm = mainForm;
// Place a TextBox on the Main Form
TextBox textBox = new TextBox();
textBox.Text = "PlugInB";
MainForm.Controls.Add(textBox);
textBox.Width = 65;
textBox.Height = 20;
textBox.Top = 30;
textBox.Left = 0;
}
}
// Create a custom strong-typed Metadata Attribute for MEF
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginMetadataAttribute : ExportAttribute
{
public string PlugInTitle { get; set; }
public string PlugInDescription { get; set; }
public object PlugInVersion { get; set; }
public PluginMetadataAttribute()
: base(typeof(IPlugInMetadata))
{
PlugInTitle = "Plug-In B";
PlugInDescription = "This is Plug-In B";
PlugInVersion = "1.0.0.1";
}
}
次に、「PlugInC」というクラス プロジェクトを追加し、次のコードを含めます。
- システムを使用する;
- System.ComponentModel.Composition を使用します。
- System.Windows.Forms を使用します。
- ContractInterfaces を使用します。
- (名前空間) PlugInC
// Prerequisites to run:
// 1) Project, Add Reference, Projects, "ContractInterface"
// 2) Project, Add Reference, .NET, "System.Windows.Forms"
// 3) Project, Add Reference, .NET, "System.ComponentModel.Composition"
// 4) Project, Properties, Build Events, Post-Build event command line:
// xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y
// 5) Project, Properties, Build Events, Run the post-build event:, Always
// 6) Project, Properties, Application, Icon and manifest, [Select an icon]
[Export(typeof(IPlugIn))]
[PluginMetadata]
public class Program : IPlugIn
{
private Form MainForm;
public void StartPlugIn(Form mainForm)
{
MainForm = mainForm;
// Place a TextBox on the Main Form
TextBox textBox = new TextBox();
textBox.Text = "PlugInC";
MainForm.Controls.Add(textBox);
textBox.Width = 65;
textBox.Height = 20;
textBox.Top = 60;
textBox.Left = 0;
}
}
// Create a custom strong-typed Metadata Attribute for MEF
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginMetadataAttribute : ExportAttribute
{
public string PlugInTitle { get; set; }
public string PlugInDescription { get; set; }
public object PlugInVersion { get; set; }
public PluginMetadataAttribute()
: base(typeof(IPlugInMetadata))
{
PlugInTitle = "Plug-In C";
PlugInDescription = "This is Plug-In C";
PlugInVersion = "1.0.0.2";
}
}
ソリューションは次のようになります。

ソリューションを右クリックし、[プロジェクトの依存関係...] を選択します。依存関係を次のように設定します。
- MainProgram - 依存 - ContractInterface
- PlugInA - 依存 - ContractInterface
- PlugInB - 依存 - ContractInterface
- PlugInC - 依存 - ContractInterface
- ContractInterface - 依存 - [なし]
ソリューションを右クリックし、[Project Build Order...] を選択します。ビルド順序は次のとおりです。
- 契約インターフェース
- プラグインA
- プラグインB
- プラグイン
- メインプログラム
プログラムをビルドして実行します。3 つの DLL ファイルが、ソリューション ファイル (*.sln) と同じディレクトリ レベルにある新しい "Plug-Ins" フォルダーにコピーされます。そうでない場合は、プロジェクトのビルド順序、依存関係を確認し、上記のプラグイン コードのメモに従ってビルド後のイベントを入力したことを確認します。ファイルが存在する場合は、ListView にプラグイン エントリをフォームに入力する必要があります。各 ListView エントリをダブルクリックして、プラグインを開始します。
楽しんでください、これが誰かに役立つことを願っています....