8

概要:

特定の DLL を追加するときに、DTE を使用して [参照の追加] ダイアログの動作を複製する必要があります (CSProj ファイルの参照にヒント パス エントリが追加されます)。

**注: 関連するが重複していない別の投稿があります: https://stackoverflow.com/questions/6690655/visual-studio-2010-add-in-how-to-get-a-references-この問題の詳細については、ヒント パス プロパティもお読みください。私は今、これに対する答えを得るためにまともな報奨金を追加しました。

これまでの話:

DTE を使用してプログラムでプロジェクト参照を直接 DLL 参照に変換しています。

プロジェクト)を参照する(親プロジェクト)を使用Project2単純なソリューションがあると仮定すると、次のように変更します。Project1

project1Reference = FindProjectReference(project2.References, project1);
project1Reference.Remove();
Reference dllReference = project2.References.Add(project1DllPath);

ここで、project1DllPath は"c:\somewhere\Project1\Bin\Debug\Project1.dll"ファイルを参照します。

私がまだ解決できない問題は、新しい参照がへ ではなく"c:\somewhere\Project1\Bin\Debug\Project1.dll"、代わりに指している "c:\somewhere\Project2\Bin\Debug\Project1.dll"(そしてファイルがそこにコピーされる) ことです。

[参照の追加] メニューを使用して DLL を直接または手動で追加すると、このコピーは行われません。

既存のプロジェクトの DLL への DLL 参照を、コピーを取得して代わりに参照せずに追加するにはどうすればよいですか?

Add の後に追加しようとしdllReference.CopyLocal = false;ましたが、フラグを設定する以外は違いはありませんでした。作成後にパスを変更するオプションはないようです。

更新: Project2 から Project1 へのビルドの依存関係をプログラムで削除しようとしましたが、効果はありませんでした。

以下は、csproj ファイルの違いです。

プロジェクトとして:

  <ItemGroup>
    <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
      <Project>{86B3E118-2CD1-49E7-A180-C1346EC223B9}</Project>
      <Name>ClassLibrary1</Name>
    </ProjectReference>
  </ItemGroup>

DLL 参照として (パスが完全に失われました):

 <ItemGroup>
    <Reference Include="ClassLibrary1, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    ...
  </ItemGroup>

手動で参照される DLL として:

  <ItemGroup>
    <Reference Include="ClassLibrary1, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\ClassLibrary1\bin\Debug\ClassLibrary1.dll</HintPath>
    </Reference>
    ...
  </ItemGroup>

DLL参照のヒントパスを指定できることがポイントのようです。DLL 参照にヒント パスを設定するにはどうすればよいですか (参照プロパティへのハンドルしかないと仮定します)。

詳細情報 (2011 年 7 月 20 日):

以下のMuse VSExtensionsからの提案は、DLL のプロジェクト BIN から親プロジェクトの BIN フォルダーへのコピーが既に作成されているため、問題の DLL には影響しません。親プロジェクトは、出力フォルダーに子 DLL が既にあるため、参照パスを使用する必要はありません。

また、プロジェクトのファイルは、プロジェクトの .csproj ファイルではなく、プロジェクトの.csproj.user ファイルにReference Paths保存されます。

4

5 に答える 5

10

VS 2008 から移行した後、数日前に同様の動作を示し始めたアドインがあるため、これは VS 2010 の新しいバグ/機能であると確信しています...基本的に、への参照を追加する場合VS のアセンブリ検索パス内にあるものはすべて、パス ヒントなしで追加されます。

この問題を解決する他の VS アドイン (Power Tools、NuGet など) を見つけることができましたが、それらはすべて MsBuild を使用しているようです。MsBuild によってリソースの使用量が大幅に増加するかどうかはわかりません。おそらく References.Add() の開始が非常に遅いため、あまり大きな減速は見られませんでした。ただし、MsBuild プロジェクトのインスタンスを取得するには、"GetLoadedProjects" というメソッドが使用されることに注意してください。これは、メモリ内に既に存在するデータに対して機能することを意味する場合があります。

以下は、アドインを修正するために使用したコードです。これは、ネットで見つけたものの簡略化されたバージョンです...基本的に、アイデアは通常どおり参照を追加し、MsBuild を使用してパス ヒントを設定することです。ヒントの設定は簡単な操作ですが、ヒントを追加する MsBuild プロジェクト項目のインスタンスを見つけるのは非常に複雑です。MsBuild のみを使用して代替手段をハックしようとしましたが、他の問題に遭遇しました...これはうまくいくようです。

ここでもう 1 つ興味深いことがあります。コードには一種の最適化が含まれています。参照のパスが追加したいパスと等しい場合、新しい参照にヒントを追加しません。問題のケースではこれで十分であり、VS が指定されたものではなく、出力フォルダーから dll を使用することを決定したことを正しく検出します。しかし、既に出力フォルダーにある dll への参照を追加しようとしたとき (私は多くの関連プロジェクトに単一の出力フォルダーを使用しています)、アドインはヒント パスを設定せず、プロジェクトは他の dll の使用に切り替わったようです。パス(私の場合はPublicAssembliesフォルダーからのパス)...したがって、その「if(!newRef.Path.Equals(...)」行を完全に削除し、常にヒントを追加すると便利な場合があります。私はこの事件はまだ調査中なので、追加の - うーん、

string newFileName = "the path to your.dll";
VSLangProj.VSProject containingProject = yourProject;

VSLangProj.Reference newRef;

newRef = containingProject.References.Add(newFileName);
if (!newRef.Path.Equals(newFileName, StringComparison.OrdinalIgnoreCase))
{
    Microsoft.Build.Evaluation.Project msBuildProj = Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.GetLoadedProjects(containingProject.Project.FullName).First();
    Microsoft.Build.Evaluation.ProjectItem msBuildRef = null;

    AssemblyName newFileAssemblyName = AssemblyName.GetAssemblyName(newFileName);
    foreach(var item in msBuildProj.GetItems("Reference"))
    {
        AssemblyName refAssemblyName = null;
        try 
        {
            refAssemblyName = new AssemblyName(item.EvaluatedInclude);
        }
        catch {}

        if (refAssemblyName != null)
        {
            var refToken = refAssemblyName.GetPublicKeyToken();
            var newToken = newFileAssemblyName.GetPublicKeyToken();

            if
            (
                refAssemblyName.Name.Equals(newFileAssemblyName.Name, StringComparison.OrdinalIgnoreCase)
                && ((refAssemblyName.Version != null && refAssemblyName.Version.Equals(newFileAssemblyName.Version))
                    || (refAssemblyName.Version == null && newFileAssemblyName.Version == null))
                && (refAssemblyName.CultureInfo != null && (refAssemblyName.CultureInfo.Equals(newFileAssemblyName.CultureInfo))
                    || (refAssemblyName.CultureInfo == null && newFileAssemblyName.CultureInfo == null))
                && ((refToken != null && newToken != null && Enumerable.SequenceEqual(refToken, newToken))
                    || (refToken == null && newToken == null))
            )
            {
                msBuildRef = item;
                break;
            }
        }
    }

    if (msBuildRef != null)
    {
        Uri newFileUri = new Uri(newFileName);
        Uri projectUri = new Uri(Path.GetDirectoryName(containingProject.Project.FullName).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar);

        Uri relativeUri = projectUri.MakeRelativeUri(newFileUri);
        msBuildRef.SetMetadataValue("HintPath", relativeUri.ToString());
    }
}
于 2011-07-27T16:32:15.907 に答える
2

これは DTE のみを使用して解決する必要がありますか? MSBuild オートメーションを使用してこれを行うことができます... csproj ファイルの内容を解析できるクラスがあります。

Microsoft.Build.Evaluation Namespaceを見てください。 csproj ファイルをロードする方法と、それを変更する方法に関する有用な情報がいくつかあります。Project クラスも参照してください。

于 2011-07-26T17:34:29.803 に答える
0

最近、Visual Studio 2010でdll参照を追加する際に問題が発生しましたが、HintPathを追加できないため、TFSビルドで問題が発生しました。数週間前にインストールしたProductivityPowerToolsアドオンによって、参照の追加ダイアログが変更されていることに気付きました。[ツール]メニューからアドオンの[検索可能な参照の追加ダイアログ]をオフにし、Visual Studio 2010を再起動した後、再び満足しました。参照を追加できましたが、今回はHintPathもありました。

于 2012-08-07T13:22:04.327 に答える
0

良い挑戦を拒否するのは難しいです...私はそこにいませんが、これを前進させるためのいくつかの適切なヒントがあると思います.
まず、問題を再現するための小さなテスト アドインを作成します。失敗しました。

    foreach (Project project in (object[])_applicationObject.ActiveSolutionProjects)
    {
        ((VSProject)project.Object).References.Add(@"c:\temp\test\FromFolder\bin\debug\KmlLib.dll");
    }

これは、ディスク上のどこかにあるランダムな dll です。dllは署名されておらず、最終的に私のcsprojに(あなたが達成したいことだけ):

   <Reference Include="KmlLib">
      <HintPath>..\..\FromFolder\bin\debug\KmlLib.dll</HintPath>
    </Reference>

次に、dll が署名されていることに気付きました。それも違いはありませんでした。次に行ったテストは、標準の MS dll をコピーすることでした。\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\ から VsWebSite.Interop.dll を選択し、それを FromFolder\bin\debug\ にコピーしました参照として追加すると、シナリオが突然再現されました> インクルードは取得しましたが、取得しませんでしたヒントパス。
次に、最終テスト: VsWebSite.Interop.dll の名前を xxVsWebSite.Interop.dll に変更し、その dll を含めました。突然、ヒントパスが再び追加されました!

これらすべてとあなたの説明を組み合わせると、参照 VS を追加するときに、参照されている dll が現在の検索場所 (GAC、プロジェクト フォルダー、パス(?)、..) で見つかるかどうかが最初に確認されると思います。追加した。見つからない場合は、ヒントパスが必要であり、追加されます。

この理論が成り立つかどうかを確認するために、次の 2 つのテストを実行できます。

  • 参照されている dll をまったく別のフォルダーにコピーし、そこから参照します --> 同じ署名を持つ dll がまだ「パス」にあるため、ヒントパスは含まれません
  • 参照されているdllをまったく別のフォルダーにコピーして名前を変更し、新しい名前を参照します->ヒントパスを追加する必要があります

あなたの結果に興味があります:)

于 2011-07-22T22:24:28.530 に答える
0

この問題を解決するには、DTE からプロジェクト プロパティへの参照パスを追加する必要があります。

Visual Studio で参照パスを設定するには:

  1. ソリューション エクスプローラーで、プロジェクトを選択します。
  2. [プロジェクト] メニューの [プロパティ] をクリックします。
  3. [参照パス] をクリックします。
  4. [フォルダー] テキスト ボックスに、アセンブリを含むフォルダーのパスを指定します。フォルダーを参照するには、省略記号 (…) をクリックします。
  5. [フォルダーの追加] をクリックします。

自動化オブジェクトから同じことを行う必要があります

それが役立つかどうか教えてください

于 2011-07-19T20:54:36.593 に答える