以编程方式加载嵌入式资源文件

6
我最近实现了以下代码,以便通过编程方式构建项目/可执行文件。在这个exe构建中,我想将一堆“实际文件”存储为流放入资源中。
下面是我如何将文件添加到资源文件(单数),然后将该资源文件嵌入到编译器参数中:
        List<string> UserFiles = new List<string>();
        UserFiles.AddRange(Helpers.GetFilesInFolder(this.txt_Publish_Folder.Text));

        string folder = this.txt_Package_Location.Text;
        folder = folder + "\\Package_" + DateTime.Now.ToLongTimeString().Replace(":", "_").Replace(".", "_");
        Directory.CreateDirectory(folder);

        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateExecutable = true;
        parameters.IncludeDebugInformation = true;
        parameters.GenerateInMemory = false;
        parameters.WarningLevel = 3;
        parameters.CompilerOptions = "/optimize";
        parameters.OutputAssembly = folder + "\\Install_" + this.txt_AppName.Text + ".exe";
        parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
        parameters.ReferencedAssemblies.Add("System.dll");
        parameters.ReferencedAssemblies.Add("System.Core.dll");
        parameters.ReferencedAssemblies.Add("System.Data.dll");
        parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
        parameters.ReferencedAssemblies.Add("System.Xml.dll");
        parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");

        CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
        if (codeProvider.Supports(GeneratorSupport.Resources))
        {
            string temp = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
            //create temp file first, because we want to append to it so as to have a single resource file with multiple stream entries...
            File.WriteAllText(temp, null);
            for (int i = 0; i < UserFiles.Count; i++ )
            {
                byte[] FileBytes = File.ReadAllBytes(UserFiles[i]);

                using (FileStream stream = new FileStream(temp, FileMode.Append))
                {
                    using (ResourceWriter writer = new ResourceWriter(stream))
                    {
                        writer.AddResource(Path.GetFileName(UserFiles[i]), FileBytes);
                    }
                }
            }
            parameters.EmbeddedResources.Add(temp);
        }

        CompilerResults res = codeProvider.CompileAssemblyFromFile(parameters, @"C:\HIDDENPATH\Program.cs");

这个很好用,没有任何错误,我实际上可以通过下面的代码在我构建的控制台应用程序(上面引用的Prorgam.cs)中获取嵌入的资源文件。然而,我遇到的问题是“加载”这个资源文件到应用程序集中/以某种方式获取它的值… 这是我目前用来做这件事的代码:

    static void Main(string[] args)
    {
        Console.WriteLine("Checking for resources... please wait...");

        Assembly thisExe;
        thisExe = Assembly.GetExecutingAssembly();
        List<string> resources = thisExe.GetManifestResourceNames().ToList();

        if(resources.Count >= 1)
        {
            try
            {
                string baseName = resources[0];
                ResourceManager mgr = new ResourceManager(baseName, thisExe);
                Console.WriteLine("retrieved manager...");
                Console.ReadLine();
                ResourceSet set = mgr.GetResourceSet(Thread.CurrentThread.CurrentCulture, true, true);
                int count = set.Cast<object>().Count();
                Console.WriteLine("Found [" + count.ToString() + "] embedded resources. Would you like to enumerate them?");
                ConsoleKeyInfo input = Console.ReadKey();
                if (input.Key == ConsoleKey.Y)
                {
                    // Build the string of resources.
                    foreach (string resource in resources)
                        Console.WriteLine(resource);
                }

            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                Console.ReadLine();
            }
        }

        Console.ReadLine();
    }

每次我运行已编译的exe,都会得到以下结果:
正在检查资源... 请稍候...
检索管理器...
找不到适用于指定文化或中性文化的任何资源。 确保“tmpCC59.tmp.resources”在编译时正确嵌入或链接到程序集“Install_testing”中,或者所有所需的卫星程序集都可以加载且完全签名。
有人能告诉我为什么会出现这种情况吗? 我尝试了所有我能想到的不同文化设置,但仍然没有任何结果。 这个问题是否与我如何“嵌入”或者如何“加载”有关?
1个回答

2

好的,这就是我最终得出的结果,它实际上解决了我所有的问题。

  1. Instead of trying to add "Resource Entries" into a single "Resource File", i'm now adding every file as its own resource, directly from the source file (don't know why i thought making a temp copy of the original and using a stream was necessary but it's not) like this:

            for (int i = 0; i < WebAppFiles.Count; i++)
            {
                parameters.EmbeddedResources.Add(WebAppFiles[i]);
            }
    
  2. Then, when comes time to extract the actual files, instead of trying to load a "set" from a single "resource file", i simply extract the data from each embedded resource, like this:

                    for (int i = 0; i < resources.Count; i++)
                    {
                        Console.WriteLine("Extracting file: " + resources[i] + "...");
                        Stream stream = thisExe.GetManifestResourceStream(resources[i]);
                        byte[] bytes = new byte[(int)stream.Length];
                        stream.Read(bytes, 0, bytes.Length);
                        File.WriteAllBytes(dir + resources[i], bytes);
                    }
    
这种新的方法基本上是告诉编译器,“这些文件对于exe是必要的并且被嵌入”,所以当你调用“build”命令时,它实际上会为您完成所有工作,并将文件读取为字节数组并嵌入到可执行文件中。
另一方面,你只需要告诉程序你想要将嵌入的资源保存为文件,并使用它们自己的文件名即可。
希望这能帮助其他试图做到这一点的人...因为对于这种问题的每一个其他帖子都有一些过于复杂的答案,要么不完整(例如:如何嵌入,但不能检索),要么根本不起作用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接