制作 C++/MFC 应用程序以从其他应用程序中提取 AssemblyInfo?

发布于 2024-11-02 02:13:34 字数 212 浏览 1 评论 0原文

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

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

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

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

I am trying to make a C++/MFC application (so called "Update Application") that can extract AssemblyVersion information from other applications written in C#/.NET 3.5.
So I can update my C# program according to the version information I can get.

I am pretty sure this is possible, but I don't know which way would be the best way.

I would like to know some techniques or keywords that I can search on the web.

A direct explanation would be appreciated, too.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浊酒尽余欢 2024-11-09 02:13:34

下面大致介绍了我们如何在本机 C++ 应用程序中执行类似的操作。

使用 /clr 进行编译。您可以在项目范围内执行此操作,也可以仅在选定的 C++ 文件上执行此操作,但据我记得有选择地执行此操作会很复杂,因此我们只是在项目范围内执行此操作。在适当的情况下也可以使用#include

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

在我们的系统中,我们有一个名为 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 文件的方式。这本身就是一个相当大的领域,所以我现在不会再谈论它。 (无论如何我都不是专家。)首先,只需确保您要加载的所有程序集都位于您的主应用程序目录中,我想您或多或少都会没问题。然后,当您完成基本的加载工作后,您就可以担心更复杂的分辨率了。

Here's roughly how we do something similar in a native C++ app.

Compile with /clr. You can do this project-wide or just on selected C++ files, but as far as I remember there were complications doing it selectively and so we just did it project-wide. Also #include <vcclr.h> wherever appropriate.

You'll need to learn about app domains. The main thing here is that once you've loaded an assembly into a domain, you can't unload the assembly except by unloading the entire domain. Since you want to load an assembly, query its version, and then let it go, you'll probably want to create a temporary domain and load into this.

In our system we have a managed C++ class called ModelLoader to load object models, query their version info, and discard them - just like what you want to do. This class is the pivotal element in our managed/unmanaged marshaling.

The code in the ModelLoader has to execute in the temporary domain, because we want it to load the target assemblies there and then unload the domain However, the main app is already running in the main domain and so it needs to be able to marshal method calls across to the ModelLoader in the temp domain. So ModelLoader inherits System::MarshalByRefObject, which allows the .NET runtime to do all the marshaling magic.

So the basic steps are something like this:

  1. Load the assembly that contains the code for ModelLoader. In our system this is built into our main unmanaged .EXE and so we just use Reflection::Assembly::GetExecutingAssembly() to get a handle to it. If your equivalent of ModelLoader is in a separate assembly then you'll have to load it somehow. But since you probably won't need to unload this assembly you can load it into the main domain.

  2. Create a temporary domain.

  3. Create an instance of your ModelLoader class (obviously it will have a different name in your system) within the temporary domain.

  4. Marshal a handle to that new instance back to your main domain.

  5. Use the marshaled handle from within your main domain to execute code in the temp domain.

  6. Unload the temporary domain.

So, in code:

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);

To save you some head-scratching, the namespaces involved are:

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

Within your ModelLoader, you'll want to load the target assembly and query its version info. Compared to all the other stuff, this is straightforward:

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

(I made this function up just now, so it might not be quite right.)

Another thing to watch out for is assembly resolution. This is how the assembly loader resolves assembly names to DLL files. This is quite a large field in its own right, so I won't talk any more about it right now. (And in any case I'm no expert.) To get started, just make sure that all the assemblies you want to load are in your main app directory and I think you'll be more or less OK. Then when you have the basic loading working, you can worry about more sophisticated resolution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文