4

Visual Studio 2008でマクロ(またはアドイン)を使用して、コードウィンドウの特定のポイント(カーソル)でac#identifierの完全修飾名を解決しようとしています。VSマクロ内の識別子の完全修飾名を取得するにはどうすればよいですか?

たとえばカーソルが "Rectangle"にある場合、 "System.Drawing.Rectangle"が返されます。

私はFileCodeModel.CodeElements.CodeElementFromPointを試しましたが、含まれているメソッドまたはクラス(およびその他)のみを取得しています。

マクロまたはアドインを使用してこれを行うことができない場合(たとえVSがインテリセンスを介して情報を知っていても)、C#ファイルでReflectionを使用して情報を取得することは可能でしょうか?

答えて

7

できます。 1つの解決策(ややハッキリだが)がある:F1 Help Contextを使う。 F1ヘルプを機能させるために、Visual Studioは現在の選択または挿入ポイントの完全修飾型名を "F1ヘルプコンテキスト"と呼ばれる名前/値ペアのバッグにプッシュします。 F1ヘルプコンテキストの内容を照会するためのVisual Studio SDKには公開APIがあります。

この問題を解決するには、F1ヘルプコンテキストのデバッグレジストリキーを有効にする必要があります。これにより、いつでもヘルプコンテキスト内の内容を、邪魔されていない動的ヘルプウィンドウから確認することができます。これを行うには:

  1. Visual Studioを起動し、[ヘルプ]メニューから[ダイナミックヘルプ]を選択します。
  2. は、今すぐ変更
  3. をピックアップして再起動Visual Studioの
  4. (レジストリツリーを作成するために、ステップ#1が必要)以下のレジストリキーを設定し、あなたが見ることができるように、ダイナミックヘルプウィンドウにデバッグ出力があるでしょうF1ヘルプの内容は何ですか?この回答の残りの部分では、アドインで使用できるようにプログラムでそのコンテキストを取得する方法について説明します。あなたは、Visual Studioが明示的に「これは識別子のタイプである」あなたを教えてくれない、F1のデバッグ出力を見てから見るよう

    [HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\Dynamic Help] 
    "Display Debug Output in Retail"="YES" 
    

    :ここ

は、レジストリキーです。代わりに、F1がヘルプを表示するために使用する1つ以上の「ヘルプキーワード」の先頭に完全修飾型名を貼り付けます。たとえば、ヘルプコンテキストにはSystem.String、VS.TextEditor、VS.Ambientがあり、最初のコードのみが現在のコードに関連しています。

これを簡単にする方法は次のとおりです。Visual Studioでは、キーワードを大文字と小文字を区別したり、大文字と小文字を区別しないようにマークすることができます。大文字と小文字を区別するキーワードを挿入するVisual Studioの唯一の部分であるAFAIKは、コードコンテキストに対応して大文字と小文字を区別する言語(C#、C++)のコードエディタです。したがって、すべてのキーワードを大文字と小文字を区別するキーワードにフィルタリングすると、コードを見ていることになります。

残念ながら、C#エディタは、挿入ポイントが言語キーワードの上にある場合、言語キーワード(識別子だけでなく)をヘルプコンテキストにプッシュします。したがって、言語のキーワードを除外する必要があります。これを行うには2つの方法があります。型システムでそれらを探すことはできますが、有効な型名ではありません(特に、VSがそれらをマングリングする方法ではありません。例えば、文字列キーワードの "string_CSharpKeyword"など)。または、ドットの欠如を検出し、それが型名ではないと仮定することができます。または、_CSharpKeyword接尾辞を検出し、VSチームがそれを変更しないことを期待できます。 :-)

もう1つの潜在的な問題はジェネリックです。ジェネリック型のためにあなたはVSから買ってあげるタイプ名は次のようになります。あなたは、バックティックを検出についてスマートにする必要があります

System.Collections.Generic.List`1.FindAll. 

System.Collections.Generic.List`1 

とメソッド次のようになりそれに対処する。

また、ASP.NET MVC .ASPXファイルのように、C#コードとその他の大文字と小文字を区別するコード(例:javascript)がページにある場合には、面白い動作が発生する可能性があります。その場合は、属性も参照する必要があります。ヘルプコンテキストには、キーワードに加えて、現在のコンテキストを記述する名前/値のペアである「属性」もあります。たとえば、devlang = csharpは1つの属性です。以下のコードは、属性を引き出すためにも使用できます。あなたは、あなたがjavascriptやその他の奇妙なコードで動作するようにならないように、探し出す正しい属性を見つけ出すために実験をする必要があります。

とにかく、すべての警告を理解している(または少なくとも露出している)ので、ヘルプコンテキストからの大文字と小文字を区別するキーワード(存在する場合)を引き出すコードがあります名前と値のペア(キーワードは、名前が「キーワード」である単純な名前/値のペアです)。

このコードでは、Microsoft.VisualStudio.Shell.Interop、Microsoft.VisualStudio.Shell、およびMicrosoftを入手するために、ビルドするためにVisual Studio SDK(通常のVSインストールだけでなく)が必要であることに注意してください。 VisualStudio.OLE.Interop名前空間(アドインプロジェクトで参照として追加する必要があります)。

OK、楽しいと幸運を持ってください!

using System; 
using Extensibility; 
using EnvDTE; 
using EnvDTE80; 
using Microsoft.VisualStudio.CommandBars; 
using System.Resources; 
using System.Reflection; 
using System.Globalization; 
using Microsoft.VisualStudio.Shell.Interop; 
using Microsoft.VisualStudio.Shell; 
using Microsoft.VisualStudio.OLE.Interop; 
using System.Collections.Generic; 

public class HelpAttribute 
{ 
    public string Name; 
    public string Value; 
    public VSUSERCONTEXTPRIORITY Priority; 
    public VSUSERCONTEXTATTRIBUTEUSAGE Usage; 
} 

public class HelpContext2 : List<HelpAttribute> 
{ 
    public static HelpContext2 GetHelpContext(DTE2 dte) 
    { 
     // Get a reference to the current active window (presumably a code editor). 
     Window activeWindow = dte.ActiveWindow; 

     // make a few gnarly COM-interop calls in order to get Help Context 
     Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)activeWindow.DTE; 
     Microsoft.VisualStudio.Shell.ServiceProvider serviceProvider = new Microsoft.VisualStudio.Shell.ServiceProvider(sp); 
     IVsMonitorUserContext contextMonitor = (IVsMonitorUserContext)serviceProvider.GetService(typeof(IVsMonitorUserContext)); 
     IVsUserContext userContext; 
     int hresult = contextMonitor.get_ApplicationContext(out userContext); 
     HelpContext2 attrs = new HelpContext2(userContext); 

     return attrs; 
    } 
    public HelpContext2(IVsUserContext userContext) 
    { 
     int count; 
     userContext.CountAttributes(null, 1, out count); 
     for (int i = 0; i < count; i++) 
     { 
      string name, value; 
      int priority; 
      userContext.GetAttributePri(i, null, 1, out priority, out name, out value); 
      VSUSERCONTEXTATTRIBUTEUSAGE[] usageArray = new VSUSERCONTEXTATTRIBUTEUSAGE[1]; 
      userContext.GetAttrUsage(i, 1, usageArray); 
      VSUSERCONTEXTATTRIBUTEUSAGE usage = usageArray[0]; 
      HelpAttribute attr = new HelpAttribute(); 
      attr.Name = name; 
      attr.Value = value; 
      attr.Priority = (VSUSERCONTEXTPRIORITY)priority; 
      attr.Usage = usage; // name == "keyword" ? VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Lookup : VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Filter; 
      this.Add(attr); 
     } 
    } 
    public string CaseSensitiveKeyword 
    { 
     get 
     { 
      HelpAttribute caseSensitive = Keywords.Find(attr => 
       attr.Usage == VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_LookupF1_CaseSensitive 
       || attr.Usage == VSUSERCONTEXTATTRIBUTEUSAGE.VSUC_Usage_Lookup_CaseSensitive 
       ); 
      return caseSensitive == null ? null : caseSensitive.Value; 
     } 
    } 
    public List<HelpAttribute> Keywords 
    { 
     get 
     { 
      return this.FindAll(attr=> attr.Name == "keyword"); 
     } 
    } 
} 
+0

ありがとう、これは完璧に動作します! – ste

+0

優秀!喜んで助けてください。幸運にも、私はこのコードをいくつかの以前の調査から欺いていました...初めてこれを行う方法を考え出すのはやや難しかったです。 :-) –

+0

あなたは正式に私の個人的な英雄です。 私はCodeElementの荒れ野の周りをさまよっていて、ヘルプ文字列の派生方法を決定しようとしていました。 あなたは正しい軌道に戻ってきました。 もう一度おねがいします! – Batgar

関連する問題