如何从解决方案中的一个项目作为构建步骤运行程序?

时间:2016-11-07 19:30:52

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

问题如下:我的VS2015解决方案有几个项目,其中包括A和B.

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

项目B包含一个这样的源文件,而不是逐字逐句地放在项目B的结果程序集中,我希望A中的程序将其“编译”到资源文件中,并且只将它放在程序集B中(以及其他代码)正常编译的项目B。

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

如何在Visual Studio 2015中执行此操作?

2 个答案:

答案 0 :(得分:2)

您可以使用Visual Studio自定义工具实现此功能,而不是使用前/后构建步骤。这不是编译步骤和设计器转换一样,但仍应解决我认为您要问的问题。这将创建一个自定义代码生成器,类似于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,您可以将其嵌入到程序集B或任何您喜欢的内容中。请记住,如果您以后需要更改项目A,那么您需要重复步骤2并重新启动VS。
  4. 实施代码生成器:

    1. 将对Microsoft.VisualStudio.TextTemplating.VSHost.14.0的引用添加到项目A.
    2. 打开Project 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());
          }
      }
      
    4. 注册代码生成器:

      1. 编译项​​目A,并将生成的程序集复制到其他文件夹。如果将它们保留在构建输出目录中,则稍后将对文件进行写锁定,因为在向VS注册自定义工具并重新启动VS后,Visual Studio会将它们加载到内存中。
      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不同,因为您定位的是14.0_Config密钥,因为这是VS2015。
        • {FAE...字符串是C#代码生成器的GUID,与您为自定义代码生成器创建的任何GUID无关。
        • 请注意,此install.reg文件必须是ANSI编码的文件,否则regedit.exe将拒绝某些"无效的注册表文件"错误。如果你在VS中创建install.reg文件作为文本文件,它将被编码为UTF8,所以只需在notepad.exe或任何你喜欢的地方创建它。
      4. 运行install.reg以更新注册表
      5. 重新启动Visual Studio
      6. 使用自定义工具:

        1. 右键单击项目B中的src.txt,然后单击属性
        2. 更改"自定义工具"您在install.reg中指定的工具名称的属性,例如MyResConverter
        3. 保存您的src.txt文件以生成初始转换的资源文件(只需打开src.txt并单击文件>保存以强制代码生成器运行)。您现在应该在src.res.txt下方看到src.txt了。您可以更改生成文件上的“属性”,将其作为资源嵌入到程序集中,或者随意嵌入。
        4. 从现在开始,每当您修改src.txt时,VS都会为您重新生成资源文件,您可以将其嵌入到项目B中。

答案 1 :(得分:1)

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

要使构建顺序正确:在VS中打开包含两个项目的.sln,右键单击projectB,选择“构建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>