VS项目可执行文件的最终位置

时间:2018-02-13 00:22:52

标签: c# visual-studio vs-extensibility

我正在编写一个Visual Studio扩展,我需要知道每个项目的最终用户项目可执行文件的最终位置。我们假设我专门针对C#桌面应用程序,因此他们应该使用MSBuild。这通常很简单,但是一些最终用户项目可能非常复杂。简单的答案是为每个项目查询DTE并获取他们的OutputPath。有时,它不是那么简单。这是一个不起作用的例子:

  • 某些解决方案包含三个项目:MainPlugin1Plugin2

  • Main项目使用标准输出路径。

  • Plugin1Plugin2项目在构建后通过各自项目文件中的plugins指令复制到Copy AfterBuild文件夹。< / p>

  • 用户运行Main项目并在运行时告诉它需要哪个插件。

  • Main项目使用该信息动态加载所选插件。

请注意,这意味着所选的DLL未在Main可执行文件中显示为引用。如果是的话,我可以找到一种方法来检索这些信息,但它们是动态计算的。我需要在执行前知道这些信息。

我遇到的主要问题是我没有可靠的方法来检索插件的“最终输出路径”(项目文件中AfterBuild指令的结果),这就是我真的需要知道。不幸的是,我不能只改变项目文件,因为这个扩展需要尽可能多地使用VS解决方案。

更新:我已经使用自定义记录器和FileWrites变量的组合对MSBuild API进行了实验,但我找不到提取此信息的方法。很遗憾,FileWrites不包含Copy操作的结果。除非有人提出更好的解决方案,否则我只需抓取解决方案树,查找与目标“匹配”的所有文件(大小,时间戳,内容等)。这无疑是一个黑客,但我没有看到更好的方式。

2 个答案:

答案 0 :(得分:0)

我认为你有以下选择:

  1. 您可能会将dll放在vsix文件see here中,这是一个zip文件。您可以使用入口点的反射(即主方法),然后您可以找到主要方法的可执行位置(即exe,dll等)。如果它显示在vsix路径中,那么你知道你的vsix位置,并且可以加载相对于它的其他dll。

  2. 您可以通过使用MEF或MAF see here等框架按需要下载d see here来解决您的问题。这样你就不需要知道这个位置了。您也可以选择将下载的dll独立存储或作为资源等存储在dll的一部分内(您的选择)

  3. 对于这两个选项,您最终将在新的dll中创建接口,这些接口将由插件和主项目引用。这将使您能够确定不同项目之间的确定性。接口无法实现,因为您甚至可以将函数回调放在那里。

答案 1 :(得分:0)

也可以解决这个问题。从来没有找到一个好的答案,所以我将勾勒出我的蛮力方法。第一种方法只是递归地返回给定路径中的所有可执行文件(DLL和EXE):

IEnumerable<FileInfo> FindBinaries(string path)
{
    var dirInfo = new DirectoryInfo(path);
    var exeFiles = dirInfo.EnumerateFiles("*.exe", SearchOption.AllDirectories);
    var dllFiles = dirInfo.EnumerateFiles("*.dll", SearchOption.AllDirectories);
    return exeFiles.Concat(dllFiles);
}

这是一种计算校验和的方法:

string GetChecksum(string filename)
{
    string checksum = null;
    using (var md5 = System.Security.Cryptography.MD5.Create())
    {
        using (var stream = File.OpenRead(filename))
        {
            checksum = BitConverter.ToString(md5.ComputeHash(stream));
        }
    }
    return checksum;
}

这是执行工作的方法:

IEnumerable<string> FindMatchingBinaries(string path, string filename)
{
    var checksum = GetChecksum(filename);
    return FindBinaries(path).Select(p => p.FullName).Where(name => GetChecksum(name) == checksum);
}

然后使用适当的参数调用它,如下所示:

var matchingFiles = FindMatchingBinaries(solutionRoot, projectBinaryName);

当然,您需要在其他地方确定解决方案的根目录和项目二进制文件是什么。它们有点超出问题的范围,针对这些特殊问题还有很多其他答案。