C# .dll 程序集可以包含入口点吗?

Posted

技术标签:

【中文标题】C# .dll 程序集可以包含入口点吗?【英文标题】:Can a C# .dll assembly contain an entry point? 【发布时间】:2012-03-23 13:40:00 【问题描述】:

我的目标是创建一个可执行文件来启动影子复制应用程序。诀窍是,我希望这个启动程序没有外部依赖项,并且不必包含有关它必须启动的程序的任何知识。

我还希望它成为目录中唯一的可执行文件。换句话说,我希望它“运行”一个 .dll 程序集而不是一个 .exe 程序集。 (我可以要求加载到新 AppDomain 中的 .dll 文件的名称每次都相同,例如 Main.dll 或类似的名称。)

看起来AppDomain.ExecuteAssembly 会做我想做的事。它说它将在“.NET Framework 标头中指定的入口点”开始执行。

当我尝试使用该函数时,我收到错误“在程序集 'DllApp' 中找不到入口点”。

我有的启动程序,只是想运行程序集:

static void Main()

    AppDomain domain = AppDomain.CreateDomain( "DllApp" );
    domain.ExecuteAssembly( "DllApp.dll" );

.dll 文件中的应用程序代码,具有默认入口点:

static class Program

    [STAThread]
    static void Main()
    
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault( false );
        Application.Run( new Form1() );
    

This page on Main() functions 说“库和服务不需要 Main 方法作为入口点”。它也没有说他们不能有默认入口点。

我已经尝试了 public/private static void main、int 返回类型、string[] args 作为参数、有命名空间、没有命名空间、静态/非静态类等的所有各种排列。

我能够将我的代码更改为从 MarshalByRefObject 继承,然后使用 CreateInstance 创建一个对象,但这似乎会使启动器与它应该启动的程序更紧密地耦合。如果我可以使用 ExecuteAssembly,正在启动的应用程序只需要一个静态 void Main,这真的很简单,也很难搞砸。

.dll 程序集是否有可能有一个默认入口点,并且 ExecuteAssembly 可以找到它,还是我只需要辞职走另一条路?

【问题讨论】:

拥有 .NET 程序集 (dll) 的入口点是没有意义的,因为它本身不会作为进程启动。 【参考方案1】:

您可以将 .NET 应用程序编译为 exe(它是一个程序集)并将其重命名为 .DLL,它将充当普通的 .NET .dll 程序集。然后它将拥有您的入口点。

【讨论】:

这工作完美,无需更改任何其他内容。想知道为什么我没想到...谢谢基思。【参考方案2】:

简短的回答是否定的。 .DLL 文件是一个动态链接库,它是由另一个库调用的代码。我猜 Keith 所说的在技术上是可行的.. 只要您以正确的方式启动应用程序,您甚至可以将其重命名为您想要的任何内容,甚至是 .txt 或 .pdf。我的主要问题是这个;你想做什么??除非您尝试编写恶意软件,否则为什么要这样做? 并不是说我宽恕出于恶意目的编写恶意软件,但我知道人们喜欢在自己的实验室中进行实验,所以我不谴责它。如果你正在编写恶意软件,比如 c++,c 或汇编程序可能是更好的选择,我猜 C# 可以完成这项工作,但是嗯……

【讨论】:

我的回答是编译器生成 dll 或 exe,但两者都是程序集,它只是 exe 是定义了入口点的程序集,这就是他所要求的。 不,这里没有恶意软件。我正在尝试创建一个小型启动程序来影子复制我的主应用程序。然后我可以轻松地更新我的主应用程序,而无需跳过其他单独的可执行文件进行更新等。我只是希望启动器在可能的情况下完全解耦,然后我可以将它与我的所有应用程序一起使用。 “除非你试图编写恶意软件” LOL!! “普通”win32 dll 具有入口点,可在进程附加到库时初始化库,或在所有进程已卸载时完成。这是正常的做法,因此对恶意软件的指控是不正常的。【参考方案3】:

我发现这些建议并不容易遵循。经过一些实验,这就是我成功的方式:

我用一个简单的 main 创建了一个控制台应用程序,并包含了我原始 DLL 中的其余代码。下面是一个包含 DLL 的简化程序:

namespace FIT.DLLTest

  public class DLLTest
  
    [STAThread]
    static void Main(string[] args)
    
      int a = 1;
    

    public DLLTest()
    
      int b = 17;
    

    public int Add(int int1, int int2)
    
      return int1 + int2;
    
  

编译后我将生成的 .exe 重命名为 .DLL。

在使用 DLL 的母程序中,我首先添加了 DLLTest.dll 作为引用,然后添加了执行 DLL 的代码。

namespace TestDLLTest

  class TestDLLTest
  
    static void Main(string[] args)
    
      AppDomain domain = AppDomain.CreateDomain( "DLLTest" );
      domain.ExecuteAssembly( "DllTest.dll" );

      DLLTest dt = new DLLTest();
      int res2 = dt.Add(6, 8);
      int a = 1;
    
  

Violà 我可以在 DLLTest.Main 方法中执行并添加一个断点,然后看到我可以调用 DLLTest 的 Main。谢谢大家的讨论!

【讨论】:

以上是关于C# .dll 程序集可以包含入口点吗?的主要内容,如果未能解决你的问题,请参考以下文章

C#动态加载dll 时程序集的卸载问题

C#利用反射动态调用DLL并返回结果,和获取程序集的信息

C# 动态加载程序集dll (实现接口)

C#:在 GAC 中查找 PresentationCore.dll(和其他程序集)的路径

将 c# 程序集动态加载和卸载到 appdomain

嵌入 .dll - 在 C# 中解析程序集