Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run a program from one of the projects in a solution as a build step?

The problem is as follows: My VS2015 solution has several projects, among them A and B.

A is a regular project that contains a program/service/code that can translate certain source files into compiled resources (with the idea being that the source is human-maintanable and under source control but the resulting resource is machine-optimized but not under source control).

Project B contains one such source file and instead of being put verbatim in project B's resulting assembly, I want the program in A to "compile" it into a resource file and only put that in assembly B (along with other code in project B that compiles normally).

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

How to do it in Visual Studio 2015?

like image 707
Misza Avatar asked Oct 17 '22 22:10

Misza


1 Answers

You can implement this using a Visual Studio Custom Tool, rather than a pre-/post-build step. This isn't really a compile step as much as a designer transform, but should still solve the question I think you're asking. This creates a custom code generator similar to how Visual Studio converts resource strings from a .resx designer into compilable C# code.

You didn't specify what version of .NET you're targeting, but this assumes you're targeting .NET 4.5. There's a good tutorial here for creating your own Custom Tool, which is what the following is based on. Just note that that article was written for Visual Studio 2012, so some of the registry keys are different.

Summary of what all this does:

  1. Implement a Microsoft.VisualStudio.TextTemplating.VSHost.BaseCodeGenerator in Project A. This does whatever you're doing to convert from a src.txt input file to a res.txt output file.
  2. Register your generator from step 1 as a VS2015 Custom Tool
  3. Set the properties of your src.txt in Project B to use your custom tool. From now on, every time you save or modify src.txt, Visual Studio will generate your res.txt for you, which you can embed into your Assembly B or whatever you like. Just remember that if you need to make changes to Project A later, then you'll need to repeat step 2 and restart VS.

Implement the code generator:

  1. Add a reference to Microsoft.VisualStudio.TextTemplating.VSHost.14.0 to Project A.
  2. Open your AssemblyInfo.cs file for Project A and change [assembly: ComVisible(false)] to [assembly: ComVisible(true)]
  3. Create a new code generator class like below

    [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());
        }
    }
    

Register your code generator:

  1. Compile Project A, and copy the resulting assemblies to some other folder. If you leave them in the build output directory, the files will be write-locked later, since Visual Studio will load them into memory after you register the custom tool with VS and restart VS.
  2. Use regasm to register your Project A as a COM assembly, running from a command prompt as admin: C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe /codebase C:\Path\To\ProjectA.dll
  3. Create a new install.reg text file to configure VS to recognize your new Custom Tool from Project A, substituting TODOs as appropriate:

    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"
    
    • Note that this differs from the tutorial mentioned above in that you're targeting the 14.0_Config key since this is VS2015.
    • The {FAE... string is the GUID for C# code generators, and unrelated to any GUID you create for your custom code generator.
    • Note that this install.reg file must be an ANSI-encoded file, or else regedit.exe will reject with some "invalid registry file" error. If you create the install.reg file inside of VS as a Text File, it will be encoded as UTF8, so just create this in notepad.exe or whatever you like.
  4. Run install.reg to update the registry
  5. Restart Visual Studio

Use your Custom Tool:

  1. Right click your src.txt in Project B, then Properties
  2. Change the "Custom Tool" property to your tool's name that you specified in the install.reg, e.g. MyResConverter
  3. Save your src.txt file to generate the initial transformed resource file (can just open src.txt and click File > Save to force the code generator to run). You should now see a src.res.txt underneath your src.txt. You can change the Properties on the generated file to embed it as a resource into your assembly, or whatever you want.

From now on, whenever you modify src.txt, VS will regenerate the resource file for you, which you can embed into your Project B.

like image 199
Jeff P Avatar answered Oct 21 '22 02:10

Jeff P