2011-05-10 58 views
5

我已經創建了一個項目模板,其中包含一個csproj,其中包含一個指向項目文件的導入,其中列出了所有第三方項目位置。我總是使用這個項目模板在相同的相對目錄中創建項目。如何在csproj模板中使用相對導入?

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Import Project="../../../3rdParty/ThirdParty.targets" /> 
    ... 
    <ItemGroup> 
    <Reference Include="Library, Version=$(LibraryVersion), Culture=neutral, PublicKeyToken=$(LibraryPublicKeyToken), processorArchitecture=MSIL"> 
     <SpecificVersion>False</SpecificVersion> 
     <HintPath>$(LibraryDir)LibraryDll.dll</HintPath> 
    </Reference> 
    </ItemGroup> 
    ... 
</Project> 

csproj文件在Visual Studio中正常工作,並從命令提示符運行msbuild時。當我嘗試創建一個使用項目模板,我得到以下錯誤的一個項目:

C:\Users...\AppData\Local\Temp\534cylld.o0p\Temp\MyModule.csproj(3,3): The imported project "C:\Users...\AppData\Local\3rdParty\ThirdParty.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

看來,Visual Studio是試圖先打開一個臨時位置的項目。 我已經嘗試將$(MSBuildProjectDirectory)添加到導入位置,希望它可能會強制它使用我打算的位置,但那也不起作用。

有什麼建議嗎?

+0

我有完全相同的問題,除了我的導入文件用於執行自定義生成任務。我需要這個路徑是相對的,因爲它是相對於我的源代碼管理文件夾層次結構。 – madd0 2011-08-12 08:14:17

+0

@Christo:你可以提供完整的pah到你從命令行運行構建的目錄嗎? – sll 2011-08-15 23:03:17

回答

7

您應該在vstemplate中將CreateInPlace屬性設置爲true。該documentation

Specifies whether to create the project and perform parameter replacement in the specified location, or perform parameter replacement in a temporary location and then save the project to the specified location.

如果你想相對路徑的工作,你所需要的參數更換的地方出現在那裏你在一個臨時位置創建項目,沒有。

1

我選擇使用Wizards with Project Templates的解決方案主要是因爲我的一些模板已經需要嚮導。

我創造了我所有的巫師都應該基類來擴展或可通過自身只是基本功能使用:

public class AddTargetsWizard : IWizard 
{ 
    private const string RELATIVE_PATH_TO_TARGETS = @"..\..\..\..\PATH\TO\Custom.Tasks.Targets"; 

    private const string TASK_NOT_FOUND_MESSAGE = @"A project of this type should be created under a specific path in order for the custom build task to be properly executed. 

The build task could not be found at the following location: 
    {0} 

Including the build task would result in unexpected behavior in Visual Studio. 

The project was created, but the build task WILL NOT BE INCLUDED. 
This project's builds WILL NOT benefit from the custom build task."; 

    private string _newProjectFileName; 

    private bool _addTaskToProject; 

    private Window _mainWindow; 

    public AddTargetsWizard() 
    { 
     this._addTaskToProject = true; 
    } 

    protected Window MainWindow 
    { 
     get 
     { 
      return this._mainWindow; 
     } 
    } 

    public virtual void BeforeOpeningFile(EnvDTE.ProjectItem projectItem) 
    { 
    } 

    public virtual void ProjectFinishedGenerating(EnvDTE.Project project) 
    { 
     this._newProjectFileName = project.FullName; 

     var projectDirectory = Path.GetDirectoryName(this._newProjectFileName); 

     var taskPath = Path.GetFullPath(Path.Combine(projectDirectory, RELATIVE_PATH_TO_TARGETS)); 

     if (!File.Exists(taskPath)) 
     { 
      MessageBox.Show(
       this.MainWindow, 
       string.Format(TASK_NOT_FOUND_MESSAGE, taskPath), 
       "Project Creation Error", 
       MessageBoxButton.OK, 
       MessageBoxImage.Error, 
       MessageBoxResult.OK, 
       MessageBoxOptions.None); 

       this._addTaskToProject = false; 
     } 
    } 

    public virtual void ProjectItemFinishedGenerating(EnvDTE.ProjectItem projectItem) 
    { 
    } 

    public virtual void RunFinished() 
    { 
     if (this._addTaskToProject) 
     { 
      var project = new Microsoft.Build.Evaluation.Project(this._newProjectFileName); 

      project.Xml.AddImport(RELATIVE_PATH_TO_TARGETS); 

      project.Save(); 
     } 
    } 

    public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) 
    { 
     var dte = (EnvDTE80.DTE2)automationObject; 

     var mainWindow = dte.MainWindow; 

     foreach (var proc in System.Diagnostics.Process.GetProcesses()) 
     { 
      if (proc.MainWindowTitle.Equals(mainWindow.Caption)) 
      { 
       var source = HwndSource.FromHwnd(proc.MainWindowHandle); 
       this._mainWindow = source.RootVisual as System.Windows.Window; 
       break; 
      } 
     } 

     this.OnRunStarted(automationObject, replacementsDictionary, runKind, customParams); 
    } 

    protected virtual void OnRunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) 
    { 
    } 

    public virtual bool ShouldAddProjectItem(string filePath) 
    { 
     return true; 
    } 
} 

This walkthrough提供了關於如何嚮導聯想到一個相當不錯的解釋一個項目(或項目)模板。

你會發現,我提供一個虛擬OnRunStarted方法,將需要提供額外的功能,如顯示嚮導窗口孩子嚮導,填充替代字典等

我沒有的東西喜歡這種方法和/或我的實現:

  • 它比普通的項目模板更復雜。
  • 爲了讓我的嚮導窗口(所有WPF)成爲使用Visual Studio作爲其所有者的真實模態窗口,我發現沒有比使用當前實例的標題來確定HWND和相關Window更好的方法。
  • 在預期的文件夾層次結構中創建項目時很好,但Visual Studio的行爲奇怪(即彈出無用的對話框)。這就是爲什麼我選擇顯示錯誤消息,並避免插入Import如果當前項目的位置與我的相對路徑不起作用。

如果有人有其他的想法,我仍然耳熟能詳。

0

默認行爲是將模板解壓到臨時文件夾中。然後,在那裏執行參數替換。不知何故,相對路徑被測試,並且在臨時位置,文件不存在。

您是否在導入之前嘗試添加以下行?

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 
+0

導入Microsoft.CSharp.targets將無法解決問題。 – madd0 2011-08-17 21:02:39

0

我想我可能會使用environment variable而不是...這會在你的情況下工作嗎?如果您必須在開發人員之間共享項目模板,則可以在PowerShell腳本中執行某些操作,它可以自動設置環境變量,也可以向開發人員詢問他的模板目錄在哪裏。

[Environment]::SetEnvironmentVariable("3rdPartyTargets", "%ProgramFiles%/3rdParty/ThirdParty.targets", "User") 

然後在宏觀的csproj:

<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Import Project="$(3rdPartyTargets)" /> 
    ... 

哦,等等。這適用於C++,但對於c#/ vb.net proj,您可能有to use msbuild

相關問題