1

我正在尝试制作一个 C++/MFC 应用程序(所谓的“更新应用程序”),它可以从用 C#/.NET 3.5 编写的其他应用程序中提取 AssemblyVersion 信息。
所以我可以根据我能得到的版本信息来更新我的C#程序。

我很确定这是可能的,但我不知道哪种方式是最好的方式。

我想知道一些我可以在网上搜索的技术或关键字。

直接的解释也将不胜感激。

4

1 回答 1

2

以下是我们在原生 C++ 应用程序中执行类似操作的大致方法。

用 编译/clr。您可以在项目范围内或仅在选定的 C++ 文件上执行此操作,但据我所知,有选择地执行此操作很复杂,因此我们只是在项目范围内执行此操作。也在#include <vcclr.h>适当的地方。

您需要了解应用程序域。这里的主要内容是,一旦将程序集加载到域中,就无法卸载程序集,除非卸载整个域。由于您要加载程序集,查询其版本,然后放手,您可能需要创建一个临时域并加载到其中。

在我们的系统中,我们有一个名为 ModelLoader 的托管 C++ 类来加载对象模型、查询它们的版本信息并丢弃它们——就像你想做的那样。此类是托管/非托管封送处理中的关键元素。

ModelLoader 中的代码必须在临时域中执行,因为我们希望它在那里加载目标程序集然后卸载域但是,主应用程序已经在主域中运行,因此它需要能够编组方法调用临时域中的 ModelLoader。所以 ModelLoader 继承System::MarshalByRefObject,它允许 .NET 运行时完成所有的编组魔法。

所以基本步骤是这样的:

  1. 加载包含 ModelLoader 代码的程序集。在我们的系统中,它内置在我们的主要非托管 .EXE 中,因此我们只需使用 Reflection::Assembly::GetExecutingAssembly() 来获取它的句柄。如果您的 ModelLoader 等效项位于单独的程序集中,那么您将不得不以某种方式加载它。但是由于您可能不需要卸载此程序集,您可以将其加载到主域中。

  2. 创建一个临时域。

  3. 在临时域中创建 ModelLoader 类的实例(显然它在您的系统中将具有不同的名称)。

  4. 将该新实例的句柄编组回您的主域。

  5. 使用主域中的编组句柄在临时域中执行代码。

  6. 卸载临时域。

所以,在代码中:

AppDomain ^domain = AppDomain::CreateDomain(L"temp domain");
Assembly ^assembly = Assembly::GetExecutingAssembly();
ObjectHandle ^handle = domain->CreateInstanceFrom(
                         assembly->Location,L"ModeLoader");
Object ^o = handle->Unwrap();
ModelLoader ^loader = dynamic_cast<ModelLoader^>(o);
loader->GetAssemblyVersion(...);
AppDomain::Unload(domain);

为了节省一些麻烦,所涉及的命名空间是:

System::AppDomain
System::Reflection::Assembly
System::Runtime::Remoting::ObjectHandle
System::Object

在您的 ModelLoader 中,您需要加载目标程序集并查询其版本信息。与所有其他东西相比,这很简单:

void ModelLoader::GetAssemblyVersion(const wchar_t *filename, AssemblyName ^name)
{
    Assembly ^assembly = Assembly::Load(gcnew String(filename));
    name = assembly->GetName();
}

(这个函数是我刚刚做的,所以可能不太对。)

另一件需要注意的是汇编决议。这就是程序集加载器将程序集名称解析为 DLL 文件的方式。这本身就是一个相当大的领域,所以我现在不会再谈论它了。(在任何情况下,我都不是专家。)要开始,只需确保您要加载的所有程序集都在您的主应用程序目录中,我认为您或多或少会没事的。然后当你有基本的加载工作时,你可以担心更复杂的分辨率。

于 2011-04-19T07:59:39.523 回答