C# COM 插件系统
C# COM Plugin System
我目前正处于需要一些建议的时刻。在我们公司,我们混合使用许多非托管语言,例如 PowerBuilder 或纯 C++。现在我们需要大量 .NET 代码。所以我的第一个目的是为什么不直接通过 COM 制作一个插件系统。
这就是我目前正在努力实现的目标。一切正常,插件系统可以加载插件。但是,一旦我将我的插件系统暴露给 COM 并尝试通过 VBS 加载插件,我总是会收到以下错误:
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information
根据我的研究,我发现在 Assembly.GetTypes()
期间无法加载类型时会出现此问题。这真的很奇怪,因为我将我的界面放入它自己的程序集中并由我的插件系统和插件引用它,所以界面总是一样的。
但是随着调试的深入,我发现实际上问题似乎不是我的界面。当他尝试加载继承接口的插件的 my class 类型时,实际上发生了加载问题。可能是界面问题,也可能是其他原因。
但现在要指出的是,只要我直接通过托管代码使用插件系统就没有问题。一旦我通过 COM 执行此操作,我就会收到此错误。所以我假设我遗漏了 COM 或弄乱了某些东西。
目前我真的需要一个解决方案,但不仅仅是解决方案,对解决方案的解释也非常好,因为我真的想了解我搞砸了什么。
这是解决方案的下载 link。也许你会发现一些东西。
[ComVisible(true)]
public bool Initialize(string dllPlugin)
{
try
{
string dllPluginPath = Assembly.GetExecutingAssembly().Location.Replace("IncoPluginSystem.dll", "") + "plugins\";
string completePluginPath = dllPluginPath + dllPlugin + ".dll";
if (!File.Exists(completePluginPath))
{
pluginError = "The plugin could not be found in the plugins directory.";
return false;
}
plugin = Assembly.LoadFile(completePluginPath);
if (plugin == null)
{
pluginError = "No plugin loaded. Pls initialize first";
return false;
}
foreach (Type t in plugin.GetTypes())
{
if (t.GetInterface("IPlugin") != null)
{
pluginInstance = Activator.CreateInstance(t) as IPlugin;
}
}
return true;
}
catch (Exception e)
{
pluginError = e.Message;
return false;
}
}
问题发生在您访问程序集类型的 foreach 循环中。
我添加了更详细的异常处理。这是我将它暴露给 COM
时的错误
Could not load file or assembly 'IncoPluginSystemInterface, Version-1.0.0.0, Culture=neutral, PuplicKeyToken=497bca4abf979e3e' or one of its dependencies. The system cannot finde the file specified.
Fusion Log:
WRN: Assembly binding logging is turned OFF.
Note: There is some performance penalty associated with assembly bind failure logging.
DLL 的引用只是创建.net 库的标准引用。没有添加任何内容。
插件系统结构如下
IncoPluginSystem.dll
IncoPluginSystemInterface.dll
plugins
->IncoPluginSystemInterface.dll
->TestPlugin.dll
所以丢失的dll实际上在需要的2个位置。可能是因为 IncoPluginSystem.dll 是作为 COM 对象加载的,所以路径可能不正确,但我不确定。我测试并改变了我能想象的一切。所以它肯定是我搞砸了 COM。
我找到了问题所在。其实真的是我的DLL放错地方了。只要我将 DLL 放入 GAC,它就会工作。所以现在我的问题是 - 我如何确定将 dll 放在它丢失的位置。在我的例外情况下,我只看到缺少什么 dll 而不是路径。有谁知道如何确定这个?
好的,我可以自己回答。解释什么是错的。我所做的可能 help\improve 其他人在未来工作。
我在注册表中打开了 FusionLog,并在 LoaderException 上检查了 FusionLog
catch (ReflectionTypeLoadException ex)
{
StringBuilder sb = new StringBuilder();
foreach (Exception exSub in ex.LoaderExceptions)
{
sb.AppendLine(exSub.Message);
FileNotFoundException exFileNotFound = exSub as FileNotFoundException;
if (exFileNotFound != null)
{
if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
{
sb.AppendLine("Fusion Log:");
sb.AppendLine(exFileNotFound.FusionLog);
}
}
sb.AppendLine();
}
pluginError = sb.ToString();
}
在注册表上启用 FisonLog 后 (HKLM\SOFTWARE\Microsoft\Fusion!EnableLog (DWORD 1) 我能够看到在调用 OLEObject 的执行程序的位置实际上需要缺少的 DLL 来创建一个通过 COM 的系统实例。
我不知道这一点,但是在某种程度上这是合乎逻辑的。幸运的是我没有搞砸代码,只是放错了地方。
我目前正处于需要一些建议的时刻。在我们公司,我们混合使用许多非托管语言,例如 PowerBuilder 或纯 C++。现在我们需要大量 .NET 代码。所以我的第一个目的是为什么不直接通过 COM 制作一个插件系统。
这就是我目前正在努力实现的目标。一切正常,插件系统可以加载插件。但是,一旦我将我的插件系统暴露给 COM 并尝试通过 VBS 加载插件,我总是会收到以下错误:
Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information
根据我的研究,我发现在 Assembly.GetTypes()
期间无法加载类型时会出现此问题。这真的很奇怪,因为我将我的界面放入它自己的程序集中并由我的插件系统和插件引用它,所以界面总是一样的。
但是随着调试的深入,我发现实际上问题似乎不是我的界面。当他尝试加载继承接口的插件的 my class 类型时,实际上发生了加载问题。可能是界面问题,也可能是其他原因。
但现在要指出的是,只要我直接通过托管代码使用插件系统就没有问题。一旦我通过 COM 执行此操作,我就会收到此错误。所以我假设我遗漏了 COM 或弄乱了某些东西。
目前我真的需要一个解决方案,但不仅仅是解决方案,对解决方案的解释也非常好,因为我真的想了解我搞砸了什么。
这是解决方案的下载 link。也许你会发现一些东西。
[ComVisible(true)]
public bool Initialize(string dllPlugin)
{
try
{
string dllPluginPath = Assembly.GetExecutingAssembly().Location.Replace("IncoPluginSystem.dll", "") + "plugins\";
string completePluginPath = dllPluginPath + dllPlugin + ".dll";
if (!File.Exists(completePluginPath))
{
pluginError = "The plugin could not be found in the plugins directory.";
return false;
}
plugin = Assembly.LoadFile(completePluginPath);
if (plugin == null)
{
pluginError = "No plugin loaded. Pls initialize first";
return false;
}
foreach (Type t in plugin.GetTypes())
{
if (t.GetInterface("IPlugin") != null)
{
pluginInstance = Activator.CreateInstance(t) as IPlugin;
}
}
return true;
}
catch (Exception e)
{
pluginError = e.Message;
return false;
}
}
问题发生在您访问程序集类型的 foreach 循环中。
我添加了更详细的异常处理。这是我将它暴露给 COM
时的错误Could not load file or assembly 'IncoPluginSystemInterface, Version-1.0.0.0, Culture=neutral, PuplicKeyToken=497bca4abf979e3e' or one of its dependencies. The system cannot finde the file specified. Fusion Log: WRN: Assembly binding logging is turned OFF. Note: There is some performance penalty associated with assembly bind failure logging.
DLL 的引用只是创建.net 库的标准引用。没有添加任何内容。
插件系统结构如下
IncoPluginSystem.dll
IncoPluginSystemInterface.dll
plugins
->IncoPluginSystemInterface.dll
->TestPlugin.dll
所以丢失的dll实际上在需要的2个位置。可能是因为 IncoPluginSystem.dll 是作为 COM 对象加载的,所以路径可能不正确,但我不确定。我测试并改变了我能想象的一切。所以它肯定是我搞砸了 COM。
我找到了问题所在。其实真的是我的DLL放错地方了。只要我将 DLL 放入 GAC,它就会工作。所以现在我的问题是 - 我如何确定将 dll 放在它丢失的位置。在我的例外情况下,我只看到缺少什么 dll 而不是路径。有谁知道如何确定这个?
好的,我可以自己回答。解释什么是错的。我所做的可能 help\improve 其他人在未来工作。
我在注册表中打开了 FusionLog,并在 LoaderException 上检查了 FusionLog
catch (ReflectionTypeLoadException ex)
{
StringBuilder sb = new StringBuilder();
foreach (Exception exSub in ex.LoaderExceptions)
{
sb.AppendLine(exSub.Message);
FileNotFoundException exFileNotFound = exSub as FileNotFoundException;
if (exFileNotFound != null)
{
if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
{
sb.AppendLine("Fusion Log:");
sb.AppendLine(exFileNotFound.FusionLog);
}
}
sb.AppendLine();
}
pluginError = sb.ToString();
}
在注册表上启用 FisonLog 后 (HKLM\SOFTWARE\Microsoft\Fusion!EnableLog (DWORD 1) 我能够看到在调用 OLEObject 的执行程序的位置实际上需要缺少的 DLL 来创建一个通过 COM 的系统实例。
我不知道这一点,但是在某种程度上这是合乎逻辑的。幸运的是我没有搞砸代码,只是放错了地方。