【问题标题】:How to run a program from one of the projects in a solution as a build step?作为构建步骤,如何从解决方案中的一个项目运行程序?
【发布时间】:2017-03-21 06:19:52
【问题描述】:

问题如下:我的VS2015方案有几个项目,其中A和B。

A 是一个常规项目,其中包含一个程序/服务/代码,可以将某些源文件转换为已编译的资源(其想法是源可人工维护并受源控制,但生成的资源是机器优化的,但不受源代码控制)。

项目 B 包含一个这样的源文件,我希望 A 中的程序将其“编译”到资源文件中,并且只将其放入程序集 B 中(以及正常编译的项目B)。

+-------------------+                    +-----------------+
|Project A          |                    |Assembly A       |
|                   | +----------------> |                 |
|                   |                    |                 |
+-------------------+                    +-------+---------+
                                                 |
                                                 |
                +--------------------------------+------+
                |                                       |
+-------------------+                    +-----------------+
|Project B      |   |                    |Assembly B    |  |
|          +----+---+                    |        +-----v--+
|          |src.txt|| +----------------> |        |res.txt||
|          |       ||                    |        |       ||
|          +--------|                    |        +--------|
+-------------------+                    +-----------------+

如何在 Visual Studio 2015 中实现?

【问题讨论】:

  • 也许在其他程序的所需构建步骤中通过 .bat 文件调用您要运行的程序的 exe?我已经在 .bat 文件中完成了其他命令,所以听起来可能是这样的..
  • @Botonomous 该图的信用转至asciiflow.com。我正在研究 MSBuild 文档,但它虽然很冗长,但还没有给我任何想法。希望这里有人能解释得更清楚。
  • 如果您确保 projectA 在 projectB 之前构建,那么您没有理由不能在 B 的构建中使用 A 的输出吗?不过,您的问题非常广泛,您在寻找什么样的回答?我怀疑这只是“是的,在 VS 2015 中是可能的”:P 你试过什么?
  • @stijn 没有尝试太多,因为我什至不知道如何开始。我不知道构建前/构建后步骤的语法,更不知道如何在这样的步骤中从另一个项目运行程序。我想一个简单的例子会有所帮助,比如说,项目 A 知道如何 ROT13 文件,而项目 B 有一个构建步骤,其中一个文件在放入程序集中之前被编码。
  • 在一个解决方案中做到这一点有点困难。 A中有多少代码?您可以定义一个inline task in MSBuild 作为预构建目标运行,它将即时编译一些代码并使用您想要的任何输入项(src.txt 等)运行它。输出将是转换文件的列表,您可以通过 output element 将其添加到项目组“EmbeddedResource”中,以将它们作为资源包含在内。

标签: c# visual-studio visual-studio-2015 msbuild


【解决方案1】:

您可以使用 Visual Studio 自定义工具来实现这一点,而不是构建前/构建后的步骤。这并不是真正的 compile 步骤,而是 designer 转换,但仍应解决我认为您要问的问题。这将创建一个自定义代码生成器,类似于 Visual Studio 如何将资源字符串从 .resx 设计器转换为可编译的 C# 代码。

您没有指定您的目标是什么版本的 .NET,但这假设您的目标是 .NET 4.5。有一个good tutorial here 用于创建您自己的自定义工具,这是以下内容的基础。请注意,该文章是为 Visual Studio 2012 编写的,因此某些注册表项是不同的。

所有这一切的总结:

  1. 在项目 A 中实现 Microsoft.VisualStudio.TextTemplating.VSHost.BaseCodeGenerator。无论您在做什么,都可以将 src.txt 输入文件转换为 res.txt 输出文件。
  2. 将第 1 步中的生成器注册为 VS2015 自定义工具
  3. 在项目 B 中设置 src.txt 的属性以使用您的自定义工具。从现在开始,每次您保存或修改src.txt,Visual Studio 都会为您生成res.txt,您可以将其嵌入到您的Assembly B 或您喜欢的任何内容中。请记住,如果您稍后需要对 Project A 进行更改,则需要重复第 2 步并重新启动 VS。

实现代码生成器:

  1. 将 Microsoft.VisualStudio.TextTemplating.VSHost.14.0 的引用添加到项目 A。
  2. 打开项目 A 的 AssemblyInfo.cs 文件并将 [assembly: ComVisible(false)] 更改为 [assembly: ComVisible(true)]
  3. 创建一个新的代码生成器类,如下所示

    [ComVisible(true)]
    [Guid("C43E4E36-289C-40C8-9B87-7F79E2B57B0E")] // TODO: replace with your own random GUID
    public class MyResConverter : Microsoft.VisualStudio.TextTemplating.VSHost.BaseCodeGenerator
    {
        public override string GetDefaultExtension()
        {
            // TODO: file extension of the resulting resource file
            return ".res.txt";
        }
    
        protected override byte[] GenerateCode(string inputFileName, string inputFileContent)
        {
            // TODO: your "compile" step that converts `src.txt` to `res.txt`
            return Encoding.UTF8.GetBytes(inputFileContent.ToUpper());
        }
    }
    

注册您的代码生成器:

  1. 编译项目 A,并将生成的程序集复制到其他文件夹。如果您将它们留在构建输出目录中,这些文件稍后将被写锁定,因为 Visual Studio 会在您向 VS 注册自定义工具并重新启动 VS 后将它们加载到内存中。
  2. 使用 regasm 将您的项目 A 注册为 COM 程序集,以管理员身份从命令提示符运行:C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe /codebase C:\Path\To\ProjectA.dll
  3. 创建一个新的 install.reg 文本文件以配置 VS 以识别来自项目 A 的新自定义工具,并根据需要替换 TODO:

    Windows Registry Editor Version 5.00
    
    ; TODO: Replace with your GUID
    [HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\14.0_Config\CLSID\{C43E4E36-289C-40C8-9B87-7F79E2B57B0E}]
    "InprocServer32"="C:\\Windows\\System32\\mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="ProjectA.MyResConverter"
    ; TODO: Replace with your assembly
    "Assembly"="ProjectA, Version=1.0.0.0, Culture=neutral"
    ; TODO: Replace with your dll file
    "CodeBase"="file:///C:\\Path\\To\\ProjectA.dll"
    
    ; TODO: Replace with your tool name
    [HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0_Config\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\MyResConverter]
    ; TODO: Replace with your GUID
    "CLSID"="{C43E4E36-289C-40C8-9B87-7F79E2B57B0E}"
    "GeneratesDesignTimeSource"=dword:00000001
    ; TODO: Replace with your description
    @="My Custom Tool"
    
    • 请注意,这与上面提到的 the tutorial 不同,因为这是 VS2015,所以您的目标是 14.0_Config 键。
    • {FAE... 字符串是 C# 代码生成器的 GUID,与您为自定义代码生成器创建的任何 GUID 无关。
    • 请注意,此 install.reg 文件必须是 ANSI 编码的文件,否则 regedit.exe 将拒绝并出现一些“无效的注册表文件”错误。如果您在 VS 中将 install.reg 文件创建为文本文件,它将被编码为 UTF8,因此只需在 notepad.exe 或任何您喜欢的文件中创建即可。
  4. 运行 install.reg 以更新注册表
  5. 重启 Visual Studio

使用您的自定义工具:

  1. 右键单击项目 B 中的 src.txt,然后单击属性
  2. 将“自定义工具”属性更改为您在 install.reg 中指定的工具名称,例如MyResConverter
  3. 保存您的src.txt 文件以生成初始转换后的资源文件(只需打开src.txt 并单击文件> 保存以强制运行代码生成器)。您现在应该在您的src.txt 下方看到一个src.res.txt。您可以更改生成文件的属性,将其作为资源嵌入到您的程序集中,或任何您想要的。

从现在开始,每当你修改src.txt时,VS都会为你重新生成资源文件,你可以将其嵌入到你的项目B中。

【讨论】:

  • 感谢您详尽的回答和一个很好的例子。我只接受另一个答案,因为这是一个 1-off(只有一个文件可以预见地以这种方式转换)。但是,如果我需要为一堆文件(如实际的编译器或其他东西)提供解决方案,我会将其加入书签以供将来参考。我希望它更容易,无需注册程序集等。
【解决方案2】:

基本原理很简单,可以这样实现:确保 A 在 B 之前构建,然后在 B 中使用 A.exe 作为预构建步骤。

要获得正确的构建顺序:在 VS 中打开带有两个项目的 .sln,右键单击 projectB,选择“Build Depedencies->Project Depedencies...”并使 projectB 依赖于 projectA。在构建顺序选项卡中验证 A 将在 B 之前构建。

现在在文本编辑器中打开 projectB,一直滚动到最后并在 </Project> 结束标记之前添加类似这样的内容:

<Target Name="GenerateSomeFile" BeforeTargets="Build">
  <PropertyGroup>
    <SourceFile>$(MsBuildThisFileDirectory)\in.cs</SourceFile>
    <TargetFile>$(MsBuildThisFileDirectory)\out.cs</TargetFile>
  </PropertyGroup>
  <Exec Command="/path/to/projectAOutputDir/A.exe $(SourceFile) $(TargetFile)"
</Target>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-20
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 2012-12-31
    • 1970-01-01
    相关资源
    最近更新 更多