5

すべてのサードパーティプロジェクトの場所を一覧表示するプロジェクトファイルを指すインポートを含む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):インポートされたプロジェクト "C:\ Users ... \ AppData \ Local \ 3rdParty \ ThirdParty.targets " 見つかりませんでした。宣言内のパスが正しいこと、およびファイルがディスク上に存在することを確認してください。

VisualStudioが最初に一時的な場所でプロジェクトを開こうとしているようです。$(MSBuildProjectDirectory)をインポート場所に追加しようとしましたが、意図した場所を使用するように強制される可能性がありますが、それも機能しませんでした。

助言がありますか?

4

4 に答える 4

9

vstemplate でCreateInPlaceプロパティをに設定する必要があります。ドキュメントtrueによると

プロジェクトを作成して指定した場所でパラメータ置換を行うか、一時的な場所でパラメータ置換を行ってからプロジェクトを指定した場所に保存するかを指定します。

相対パスを機能させるには、一時的な場所ではなく、プロジェクトを作成している場所でパラメーターの置換を行う必要があります。

于 2012-01-05T12:45:32.130 に答える
1

主に一部のテンプレートですでにウィザードが必要だったため、プロジェクト テンプレートでウィザードを使用するソリューションを選択しました。

他のすべてのウィザードが拡張することになっている、または基本的な機能のために単独で使用できる基本クラスを作成しました。

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;
    }
}

このウォークスルーは、ウィザードをプロジェクト (または項目) テンプレートに関連付ける方法について非常によく説明しています。

OnRunStartedウィザード ウィンドウの表示、置換ディクショナリの入力など、追加機能を提供する必要がある子ウィザードに仮想メソッドを提供していることに気付くでしょう。

このアプローチおよび/または実装について私が気に入らない点:

  • 単純なプロジェクト テンプレートよりもはるかに複雑です。
  • ウィザード ウィンドウ (すべて WPF) を Visual Studio を所有者とする実際のモーダル ウィンドウにするために、現在のインスタンスのタイトルを使用して HWND と関連付けられてWindowいる .
  • プロジェクトが予想されるフォルダー階層に作成されている場合はすべて問題ありませんが、それ以外の場合、Visual Studio は奇妙な動作をします (つまり、役に立たないダイアログがポップアップします)。Importそのため、現在のプロジェクトの場所が相対パスで機能しない場合はエラー メッセージを表示し、挿入を避けることにしました。

誰かが他のアイデアを持っている場合、私はまだすべて耳を傾けています.

于 2011-08-12T10:16:08.660 に答える
0

デフォルトの動作では、テンプレートは一時フォルダーに解凍されます。次に、パラメータの置換がそこで実行されます。どういうわけか、相対パスがテストされ、一時的な場所にファイルが存在しません。

インポートの前に次の行を追加しようとしましたか?

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
于 2011-08-17T12:08:52.707 に答える
0

代わりに環境変数を使用するかもしれないと思います...それはあなたの状況でうまくいきますか? また、開発者間でプロジェクト テンプレートを共有する必要がある場合は、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++ では機能しますが、ac#/vb.net プロジェクトでは msbuild を使用する必要がある場合があります。

于 2011-08-18T15:38:49.337 に答える