【问题标题】:Embedding an external executable inside a C# program在 C# 程序中嵌入外部可执行文件
【发布时间】:2022-01-19 20:24:39
【问题描述】:

如何在我的 C# Windows 窗体应用程序中嵌入外部可执行文件?

编辑:我需要嵌入它,因为它是一个外部免费控制台应用程序(用 C++ 制作),我从中读取输出值以在我的程序中使用。嵌入它会更好,更专业。

第二个原因是需要在 .NET 应用程序中嵌入 Flash 投影仪文件。

【问题讨论】:

  • 问题是:你想用那个“外部可执行文件”做什么?如果只是嵌入并取出它,当“嵌入资源”时
  • 如果它只是running it and getting its output,那么并排部署它。不需要嵌入它。同样的 Flash 文件,您的 可以 只需将它与您的程序一起部署,如果这就是您真正需要的。我怀疑您还有更多需求,您没有费心列出。 :)

标签: c# windows embed executable


【解决方案1】:

最简单的方法,从Will said开始:

  1. 使用 Resources.resx 添加 .exe
  2. 编码:

    string path = Path.Combine(Path.GetTempPath(), "tempfile.exe");  
    File.WriteAllBytes(path, MyNamespace.Properties.Resources.MyExecutable);
    Process.Start(path);
    

【讨论】:

  • 当然,明智的做法是检查文件是否存在和/或之后酌情删除文件。
  • 这很有用,什么是Properties.Resources.[MyExecutable]之后的MyExecutable,这是为嵌入资源定义的对象吗?
  • 将文件添加到资源中时不要忘记将FileType 设置为Binary,否则会出现错误cannot convert string to byte[]。为此,请在添加资源文件后单击它,然后从属性中看到FileType 并将其设置为Binary
【解决方案2】:

这里有一些示例代码可以大致完成此任务,减去任何类型的错误检查。另外,请确保要嵌入的程序的许可证允许这种使用。

// extracts [resource] into the the file specified by [path]
void ExtractResource( string resource, string path )
{
    Stream stream = GetType().Assembly.GetManifestResourceStream( resource );
    byte[] bytes = new byte[(int)stream.Length];
    stream.Read( bytes, 0, bytes.Length );
    File.WriteAllBytes( path, bytes );
}

string exePath = "c:\temp\embedded.exe";
ExtractResource( "myProj.embedded.exe", exePath );
// run the exe...
File.Delete( exePath );

唯一棘手的部分是为ExtractResource 的第一个参数获取正确的值。它应该具有“namespace.name”的形式,其中命名空间是您项目的默认命名空间(在项目 | 属性 | 应用程序 | 默认命名空间下找到它)。第二部分是文件的名称,您需要将其包含在项目中(确保将构建选项设置为“嵌入式资源”)。如果将文件放在目录下,例如资源,然后该名称成为资源名称的一部分(例如“myProj.Resources.Embedded.exe”)。如果遇到问题,请尝试在 Reflector 中打开已编译的二进制文件并查看 Resources 文件夹。此处列出的名称是您将传递给GetManifestResourceStream 的名称。

【讨论】:

  • 咳咳。 GMRS 是执行此操作的旧方法。您可以将 .exe 作为可作为属性访问的字节数组嵌入程序集中。获取它并将其保存到磁盘的两个步骤,而不是您建议的带有魔法字符串的怪物。 Here's a page on how to create strongly typed resources in VS.
  • 对不起,这显然不是最新的答案,但我不确定它是否真的应该被称为“怪物”。
  • 将文件添加到资源中时不要忘记将FileType 设置为Binary,否则会出现错误cannot convert string to byte[]。为此,请在添加资源文件后单击它,然后从属性中看到FileType 并将其设置为Binary
【解决方案3】:

只需将其添加到您的项目中并将构建选项设置为“嵌入式资源”

【讨论】:

    【解决方案4】:

    这可能是最简单的:

    byte[] exeBytes = Properties.Resources.myApp;
    string exeToRun = Path.Combine(Path.GetTempPath(), "myApp.exe");
    
    using (FileStream exeFile = new FileStream(exeToRun, FileMode.CreateNew))
        exeFile.Write(exeBytes, 0, exeBytes.Length);
    
    Process.Start(exeToRun);
    

    【讨论】:

    • Properties.Resources 之后的 myApp 是什么?这是嵌入资源的自定义类吗?
    • @datelligence myApp 是您的自定义资源名称。您添加/嵌入到资源文件中的那个。在我的例子中,它是一个带有 .exe 扩展名的可执行文件。
    【解决方案5】:

    可执行文件是托管程序集吗?如果是这样,您可以使用 ILMerge 将该程序集与您的程序集合并。

    【讨论】:

    • 他将如何运行它?
    【解决方案6】:

    这是我的版本: 将文件作为现有项添加到项目中,将文件的属性更改为“嵌入式资源”

    将文件动态提取到给定位置:(此示例不测试位置的写入权限等)

        /// <summary>
        /// Extract Embedded resource files to a given path
        /// </summary>
        /// <param name="embeddedFileName">Name of the embedded resource file</param>
        /// <param name="destinationPath">Path and file to export resource to</param>
        public static void extractResource(String embeddedFileName, String destinationPath)
        {
            Assembly currentAssembly = Assembly.GetExecutingAssembly();
            string[] arrResources = currentAssembly.GetManifestResourceNames();
            foreach (string resourceName in arrResources)
                if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
                {
                    Stream resourceToSave = currentAssembly.GetManifestResourceStream(resourceName);
                    var output = File.OpenWrite(destinationPath);
                    resourceToSave.CopyTo(output);
                    resourceToSave.Close();
                }
        }
    

    【讨论】:

      【解决方案7】:
      1. 将文件添加到 VS 项目
      2. 标记为“嵌入式资源” -> 文件属性
      3. 使用名称解析:[Assembly Name].[Name of embedded resource] like "MyFunkyNTServcice.SelfDelete.bat"

      您的代码存在资源错误(文件句柄未释放!),请更正:

      public static void extractResource(String embeddedFileName, String destinationPath)
          {
              var currentAssembly = Assembly.GetExecutingAssembly();
              var arrResources = currentAssembly.GetManifestResourceNames();
              foreach (var resourceName in arrResources)
              {
                  if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
                  {
                      using (var resourceToSave = currentAssembly.GetManifestResourceStream(resourceName))
                      {
                          using (var output = File.OpenWrite(destinationPath))
                              resourceToSave.CopyTo(output);
                          resourceToSave.Close();
                      }
                  }
              }
          }
      

      【讨论】:

        【解决方案8】:

        如果需要,将某些内容提取为字符串:

        public static string ExtractResourceAsString(String embeddedFileName)
            {
                var currentAssembly = Assembly.GetExecutingAssembly();
                var arrResources = currentAssembly.GetManifestResourceNames();
                foreach (var resourceName in arrResources)
                {
                    if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
                    {
                        using (var resourceToSave = currentAssembly.GetManifestResourceStream(resourceName))
                        {
                            using (var output = new MemoryStream())
                            {
                                resourceToSave.CopyTo(output);
                                return Encoding.ASCII.GetString(output.ToArray());
                            }
                        }
                    }
                }
        
                return string.Empty;
            }
        

        【讨论】:

          猜你喜欢
          • 2010-12-21
          • 2012-08-14
          • 2013-08-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-27
          • 2011-08-18
          相关资源
          最近更新 更多