Dot netconf2017 - VS拡張
-
Upload
tatsuya-ishikawa -
Category
Software
-
view
239 -
download
2
Transcript of Dot netconf2017 - VS拡張
![Page 1: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/1.jpg)
Dawn Huczek
Quick shot 作成時に学んだVS拡張、Roslyn、Dotnet.exe関連の知識
![Page 2: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/2.jpg)
自己紹介
・石川達也
・(株)Codeer 代表取締役
・Microsoft MVP
・ささいなことですが(ブログ)
・OSS
FriendlySelenium拡張
LambdicSql
Visual Studio and Development Technologies
http://ishikawa-tatsuya.hatenablog.com/
https://www.nuget.org/profiles/ishikawa-tatsuya
趣味はギターとライブラリ作成
![Page 3: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/3.jpg)
Codeer Ltd.
こんなメンバーでやってます!
ソフトウェア開発でお悩みの方は、いつでもご相談ください
![Page 4: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/4.jpg)
Quick shot
関数単体で実行するVS拡張(無料)
![Page 5: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/5.jpg)
Quick shot デモ
https://marketplace.visualstudio.com/items?itemName=ishikawa-tatsuya.Quickshot
![Page 6: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/6.jpg)
λ sql
仲間募集中!
![Page 7: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/7.jpg)
LambdicSqlデモ
https://github.com/Codeer-Software/LambdicSql
![Page 8: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/8.jpg)
SQL Server LambdicSql.SqlServer
My Sql
SQLite
Oracle
DB2
PostgreSql
95%
実装状況
共通 LabmdicSql 99%
LambdicSql.MySql
LambdicSql.SQLite
LambdicSql.Oracle
LambdicSql.DB2
LambdicSql.Npgsql
![Page 9: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/9.jpg)
もっと仲間が欲しいのです!
戦いは数だよ兄貴!
![Page 10: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/10.jpg)
もし わしの味方になれば世界(実装)の半分を わけてやろう・・・
この世の全てのSQLをC#で表現してやる!
仲間募集中!
![Page 11: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/11.jpg)
VS拡張の話
ようやく・・・
![Page 12: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/12.jpg)
Quick shot を作るには?
・右クリックメニューを表示・ドッキングウィンドウを表示・VS2015にも対応・ソリューションビルド・選択位置の関数の情報を取得・追加コードのコンパイル・関数実行
![Page 13: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/13.jpg)
新規にVSIXプロジェクトを作成する
![Page 14: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/14.jpg)
Visual Studio 2017 で VSIXプロジェクトを作成する
![Page 15: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/15.jpg)
作成直後
ビルドして実行すると拡張をデバッグする用のVSが起動する
![Page 16: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/16.jpg)
右クリックメニュー
![Page 17: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/17.jpg)
右クリメニュー用のコマンド追加
![Page 18: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/18.jpg)
ビルド→起動
デフォルトではツールメニュー以下で表示される
押すとメッセージが出る
RClickCommand.csにサンプルコードが書かれていて、そこにメッセージを表示するコードがある
![Page 19: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/19.jpg)
Vsctファイル その前に名前を変更する(任意)
・そもそも、最初に作ったコマンド名がファイル名になっているのでファイル名を変更する。
RClickCommandPackage.vsct→ExTest.vsctRClickCommandPakage.cs → ExtTestPackage.cs
・見通しが悪いのでコメントをすべて消す。
→
・識別子の名前も変更guidRClickCommandPackage → guidTestExPackageguidRClickCommandPackageCmdSet → guidExTestCmdSetMyMenuGroup → CodeEditorGroup
![Page 20: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/20.jpg)
<Groups><Group guid="guidExTestCmdSet" id="CodeEditorGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/></Group>
</Groups>
Vsctファイル エディタ上で右クリックで表示されるようにする
<Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>
https://msdn.microsoft.com/ja-jp/library/microsoft.visualstudio.shell.vsmenus.aspx
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VSSDK\VisualStudioIntegration\Common\Inc\vsshlids.h
vsshlids.hに定義されている IDM_VS_ で始まる識別子をいくつか試してみる
ソースコードの右クリックメニュー以外で表示したい場合は・・・
<Extern href="stdidcmd.h"/><Extern href="vsshlids.h"/>
vsctファイルの先頭でインクルードされている
![Page 21: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/21.jpg)
Vsctファイル ついでにショートカットキーもつける
<KeyBindings><KeyBinding guid="guidExTestCmdSet" id="RClickCommandId“editor="guidVSStd97" key1="Z" mod1="Control Shift" />
</KeyBindings>
https://msdn.microsoft.com/ja-jp/library/cc138531.aspx
guidVSStd97が何を意味するのかは知らん
これを入れる
</CommandTable> ←これが閉じる前くらいに入れる
![Page 22: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/22.jpg)
Vsctファイル ついでにアイコンも変える
<Icon guid="guidImages" id="bmpPic1" />
<Bitmaps><Bitmap guid="guidImages" href="Resources\RClickCommand.png" usedList="bmpPic1, …"/>
</Bitmaps>
って書いてるので
RClickCommand.pngの最初の16×16に好きな絵を張り付ける
![Page 23: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/23.jpg)
こんな感じになります
![Page 24: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/24.jpg)
ドッキングウィンドウ
![Page 25: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/25.jpg)
ドッキングウィンドウ追加
追加はできるが・・・
![Page 26: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/26.jpg)
ビルド・・・
おい!
![Page 27: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/27.jpg)
Image?
ビルド・・・
![Page 28: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/28.jpg)
修正・・・
←削除
ExTest.vsctも変更する
新たに追加されたImage系の定義を削除してRClickCommandと同じものを使うようにする
どうやら、生成された
MyDockingWindowCommand.pngがゴミっている。Paintとかでも開けない。
Image差し替えてもいいよ
![Page 29: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/29.jpg)
(気を取り直して)ビルド→起動
表示→その他ウィンドウ→MyDockingWindow
デフォルトではフローティングで表示される
![Page 30: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/30.jpg)
アウトプットにドッキング表示されるようにする
[ProvideToolWindow(typeof(MyDockingWindow), Style = VsDockStyle.Tabbed, Window = ToolWindowGuids.Outputwindow)]public sealed class ExtTestPackage : Package
ExtTestPackageの属性に赤字のコードを足す
![Page 31: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/31.jpg)
ここで一旦、VS2015対応
![Page 32: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/32.jpg)
source.extension.vsixmanifest
ギャラリーにUpしたときに、この情報を使ってアイコンとか表示してくれる。リリースの時にVersionを上げておくとダウンロードした人が更新インストールできる(上げてないと、一回アンインストールが必要だし、そもそもバージョンアップされたかわからない
![Page 33: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/33.jpg)
source.extension.vsixmanifest 2015対応
14(2015)から対応していて16(201x)には対応していませんって意味らしい
[14.0, 16.0)
![Page 34: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/34.jpg)
source.extension.vsixmanifest 2015対応
![Page 35: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/35.jpg)
source.extension.vsixmanifest 2015対応
Visual Studio MPF 15.0 を消す
![Page 36: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/36.jpg)
これで終わりかと思いきや・・・
![Page 37: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/37.jpg)
参照関係を修正する VS2015対応
←赤枠の参照を消す
↧全部Nugetで消します依存関係がある。左のツリーの上から消すと上手く消える
![Page 38: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/38.jpg)
代わりに
Microsoft.VisualStudio.Shell.14.0を入れる
参照関係を修正する VS2015対応
![Page 39: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/39.jpg)
VS2015にインストールしてみる
2015対応大変やった・・・
![Page 40: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/40.jpg)
実装編
![Page 41: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/41.jpg)
Visual Stuidoの機能にアクセスする
DTEを使ってVS自体を操作します。色々できるようですが、この資料では
・Solution・ActiveDocument・Debugger
に触れてみます。その他のもDTE2の定義を見て勘で使ってみてください。
ググり力が重要・・・
var dte = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE2;
![Page 42: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/42.jpg)
プロジェクトをビルドする
dte.Solution. SolutionBuildが使えそうだなー
public interface SolutionBuild{void BuildProject(string SolutionConfiguration,
string ProjectUniqueName,bool WaitForBuildToFinish = false);
いやいや、SolutionConfigrationって何入れたらええねん・・・
![Page 43: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/43.jpg)
var doc = dte.ActiveDocument;if (doc == null) return false;
//選択されているビルドのモード(Debug|AnyCpu)var solutionBuild = DTE.Solution.SolutionBuild;var buildConfig = solutionBuild.ActiveConfiguration.Name;
//選択されているプロジェクト名称var proUniquName = doc.ProjectItem.ContainingProject.UniqueName;
//選択されているプラットフォームvar platform = solutionBuild.ActiveConfiguration.
SolutionContexts.Cast<SolutionContext>().FirstOrDefault().PlatformName;
if (platform == "Win32") platform = "x86";
//ビルドsolutionBuild.BuildProject(buildConfig + "|" + platform, proUniquName, false);
試行錯誤の末、何とかたどりつく・・・
![Page 44: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/44.jpg)
なんかダメ!
ビルドできるんだけど、複数プロジェクトがあるときにアウトプットに変なログが出る(手元にログ残してない。ごめん
どうすりゃいいんだよ!
![Page 45: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/45.jpg)
ググったら出てくる
dte.ExecuteCommand("Build.BuildSelection", "");
なんじゃそれ・・・
![Page 46: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/46.jpg)
//ビルド > ソリューションのビルドならばDTE.ExecuteCommand("Build.BuildSolution");
//ビルド > ソリューションのリビルドならばDTE.ExecuteCommand("Build.RebuildSolution");
//ビルド > xxxのビルドDTE.ExecuteCommand("Build.BuildSelection");
//ビルド > xxxのリビルドDTE.ExecuteCommand("Build.RebuildSelection");
http://microsoft.public.jp.dotnet.languages.vc.narkive.com/pukiYoAo
ちなみに、こうらしい
![Page 47: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/47.jpg)
public interface _Solution : IEnumerable{
Project Item(object index);IEnumerator GetEnumerator();void SaveAs(string FileName);Project AddFromTemplate(string FileName, string Destination, string ProjectName, bool Exclusive = false);Project AddFromFile(string FileName, bool Exclusive = false);void Open(string FileName);void Close(bool SaveFirst = false);void Remove(Project proj);string get_TemplatePath(string ProjectType);object get_Extender(string ExtenderName);void Create(string Destination, string Name);ProjectItem FindProjectItem(string FileName);string ProjectItemsTemplatePath(string ProjectKind);DTE DTE { get; }DTE Parent { get; }int Count { get; }string FileName { get; }Properties Properties { get; }bool IsDirty { get; set; }string FullName { get; }bool Saved { get; set; }Globals Globals { get; }AddIns AddIns { get; }object ExtenderNames { get; }string ExtenderCATID { get; }bool IsOpen { get; }SolutionBuild SolutionBuild { get; }Projects Projects { get; }
}
Solution
ビルドではイマイチやったけどプロジェクトの一覧取ったりソリューション全体を操作できて便利な子ではあります。
![Page 48: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/48.jpg)
右クリックした位置にある関数情報の取得
![Page 49: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/49.jpg)
クリックした位置を取得 dte.ActiveDocument
var csFile = Path.Combine(dte.ActiveDocument.Path, dte.ActiveDocument.Name);
//ファイルを読むvar csLines = File.ReadAllLines(csFile);
//選択位置取得var sel = dte.ActiveDocument.Selection as TextSelection;var pos = GetPos(csLines, sel.CurrentLine - 1, sel.CurrentColumn - 1);
static int GetPos(string[] lines, int currentLine, int currentCol){
int charCount = 0;for (int i = 0; i < lines.Length; i++){
if (i == currentLine){
return charCount + currentCol;}charCount += lines[i].Length;charCount += Environment.NewLine.Length;
}return -1;
}
dte.ActiveDocumentを使う
![Page 50: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/50.jpg)
Roslyn
Microsoft.CodeAnalysis
![Page 51: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/51.jpg)
//Roslynで解析var tree = CSharpSyntaxTree.ParseText(string.Join(Environment.NewLine, csLines));
//選択クラスvar classSyntaxs = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().
//含まれているWhere(x => x.Span.Contains(pos));
//ネームスペースvar namespaceSyntax = tree.GetRoot().DescendantNodes().OfType<NamespaceDeclarationSyntax>().
//先頭FirstOrDefault();
//選択メソッドvar methodSyntax = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().
//含まれているWhere(x => x.Span.Contains(pos)).//先頭FirstOrDefault();
選択位置の関数の型情報的なものを取得 Roslyn
![Page 52: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/52.jpg)
もっといい方法があるかも
//ネームスペースvar namespaceName = namespaceSyntax.Name.GetText().ToString().Trim();
//クラスvar className = string.Join("+", classSyntaxs.Select(x => x.Identifier.Text.Trim()));
//型完全名var typeFullName = namespaceName + "." + className;
//関数名var methodName = methodSyntax.Identifier.Text.Trim();
//戻り値(不完全な情報)var returnType = methodSyntax.ReturnType.ToFullString().Trim();
//引数(不完全な情報)var argumentTypes = new List<string>();var argumentNames = new List<string>();foreach (var e in methodSyntax.ParameterList.Parameters){
argumentTypes.Add(e.Type.ToFullString().Trim());argumentNames.Add(e.Identifier.Text.Trim());
}
選択位置の関数の型情報的なものを取得 Roslyn
![Page 53: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/53.jpg)
ちなみに、2015だと(ていうかVSの持っているRoslynと)同一AppDomainに複数のRoslynのdllがロードされるけど大丈夫みたい。
へー
![Page 54: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/54.jpg)
型情報を得るMono.Cecil
ここでは普通のリフレクションは使いづらい
![Page 55: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/55.jpg)
型情報を得る
アセンブリのパスを取得
もっといい方法があるかも
var proj = dte.ActiveDocument.ProjectItem.ContainingProject.FileName;var solutionBuild = dte.Solution.SolutionBuild;
//選択されているビルドのモード(Debug)var buildConfig = solutionBuild.ActiveConfiguration.Name;
//選択されているプラットフォームvar platform = solutionBuild.ActiveConfiguration.
SolutionContexts.Cast<SolutionContext>().FirstOrDefault().PlatformName;
//CSファイル解析は端折ります・・・ XML解析です。
//出力フォルダ取得var output = CSProjAnalyzer.GetOutputDirectory(proj, buildConfig, platform);
//拡張子var ext = CSProjAnalyzer.GetTargetFileExtension(proj);
//バイナリパスvar assembly = Path.Combine(output, CSProjAnalyzer.GetAssemblyName(proj) + "." + ext);
![Page 56: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/56.jpg)
型情報を得る Mono.Cecil
//アセンブリ情報取得var asm = AssemblyDefinition.ReadAssembly(assemblyPath);
//タイプvar type = asm.Modules.SelectMany(e => e.Types).
Where(e => e.FullName == typeFullName).FirstOrDefault();
//完全なマッチロジックにはならないが、実用上問題ないレベルではある・・・var methodInfo = type.Methods.Where(e => e.Name == methodName).
Where(e => IsMatchMethod(e, methodName, argumentTypes)).FirstOrDefault();
割り切った
![Page 57: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/57.jpg)
private static bool IsMatchMethod(MethodDefinition methodInfo, string methodName, List<string> argumentTypes){
if (methodInfo.Name != methodName) return false;if (methodInfo.Parameters.Count != argumentTypes.Count) return false;for (int i = 0; i < methodInfo.Parameters.Count; i++){
if (!IsMatchType(methodInfo.Parameters[i].ParameterType, argumentTypes[i])) return false;}return true;
}
static bool IsMatchType(TypeReference type, string typeName){
var types1 = GetAllTypes(type);var types2 = GetAllTypes(typeName);if (types1.Length != types2.Length) return false;for (int i = 0; i < types1.Length; i++){
if (!types1[i].Contains(types2[i])) return false;}return true;
}
static string[] GetAllTypes(string type){
return type.Replace(">", "").Split(new[] { "<", "," }, System.StringSplitOptions.RemoveEmptyEntries).Select(e => AdjustTypeName(e)).ToArray();}
static string[] GetAllTypes(TypeReference type){
var types = new List<string>();if (type.IsGenericInstance){
types.AddRange(GetAllTypes(type.GetElementType()));foreach (var e in ((dynamic)type).GenericArguments){
types.AddRange(GetAllTypes(e));}
}else{
//Innerクラスの表現が違うので合わせるtypes.Add(type.FullName.Replace("/", "+"));
}return types.ToArray();
}
static string AdjustTypeName(string type){
type = type.Trim();var arrayCount = GetArrayCount(type);type = type.Replace("[]", string.Empty);switch (type){
case "byte": type = typeof(byte).FullName; break;case "char": type = typeof(char).FullName; break;case "short": type = typeof(short).FullName; break;case "ushort": type = typeof(ushort).FullName; break;case "int": type = typeof(int).FullName; break;case "uint": type = typeof(uint).FullName; break;case "long": type = typeof(long).FullName; break;case "ulong": type = typeof(ulong).FullName; break;case "float": type = typeof(float).FullName; break;case "double": type = typeof(double).FullName; break;case "decimal": type = typeof(decimal).FullName; break;case "string": type = typeof(string).FullName; break;
}return type + string.Join("", Enumerable.Range(0, arrayCount).Select(e => "[]"));
}
static int GetArrayCount(string type){
int count = 0;while (true){
int index = type.IndexOf("[]");if (index == -1) break;count++;type = type.Substring(index + "[]".Length);
}return count;
}
IsMatchMethodは関数名と引数から、(だいたい)マッチしてるか判別するロジックです。
![Page 58: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/58.jpg)
実行 FullDotNet編
![Page 59: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/59.jpg)
VS
Host.exe起動(ファイルで情報を渡す)
コンパイル
リフレクションで実行
デバッグなら待ち
結果取得(ファイル)
構成
![Page 60: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/60.jpg)
Host.exeはリソースに仕込みました。
実行前に、存在しないかバイナリが異なればコピーする
C:¥ProgramData¥QuickShot
![Page 61: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/61.jpg)
リフレクションはアセンブリの解決が必要
C:\ProgramData\QuickShot
QuickShot.ExecutionHost.exe
対象プロジェクトのDebug or Releaseフォルダ
対象のdll群
ここにあるもの以外は解決できない
![Page 62: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/62.jpg)
class AssemblyResolver{
static string[] _dllDirectories;
internal static void Init(string[] dllDirectories){
_dllDirectories = dllDirectories;AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainAssemblyResolve;
}
static Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args){
var sep = args.Name.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);foreach (var e in _dllDirectories){
var path = Path.Combine(e, sep[0] + ".dll");if (File.Exists(path)){
return Assembly.LoadFrom(path);}path = Path.Combine(e, sep[0] + ".exe");if (File.Exists(path)){
return Assembly.LoadFrom(path);}
}return null;
}}
AppDomain.CurrentDomain.AssemblyResolve を使います
やったことないけどプロービング設定でも行けるかも
![Page 63: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/63.jpg)
コンパイルはRoslynを内部的に使ったCodeDom
最初から素直にRoslynにしておけば良かった・・・
https://opcdiary.net/?p=32908
CSharpCodeProvider codeProvider = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
Microsoft.CodeDom.Providers.DotNetCompilerPlatform
![Page 64: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/64.jpg)
Roslyn/Binフォルダが必要です。
Asp.Netのプロジェクト作るとできているのでそれをコピります
Bin/Release/Roslyn/Binとかに置く今回はこれもResourcesに入れてProgramData以下にコピった。
最初から素直にRoslynにしておけば良かった・・・
![Page 65: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/65.jpg)
デバッグはこんな感じで実現しました。
Host.exe
VS
if (info.IsAttach){
while (!System.Dianostics.Debugger.IsAttached){
Thread.Sleep(50);}
}
EnvDTE.Processes processes = DTE.Debugger.LocalProcesses;foreach (EnvDTE.Process proc in processes){
if (proc.ProcessID == hostProcessId){
proc.Attach();return;
}}
![Page 66: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/66.jpg)
実行 DotNetCore、DotNetStandard編
![Page 67: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/67.jpg)
リフレクションが上手くいかん!
なんでこんな仕様にしたんだよ・・・
deps.jsonってのがあってそこにないものはロードできない・・・
![Page 68: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/68.jpg)
リフレクションだけでなんとかできる気がしない・・・
・Deps.jsonを書き換えるのはしんどい
・そもそもdllが分散配置されてて解決するもの大変(binフォルダにコピられてない)
![Page 69: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/69.jpg)
方針
Host.exeは対象のプロジェクトごとにコードを作成、コンパイルする
でも、できるだけキャッシュするようにしたんですよ・・・
![Page 70: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/70.jpg)
csproj作成
ファイルは同一フォルダにいれたらOK
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup>
<OutputType>Exe</OutputType><TargetFramework>netcoreapp1.1</TargetFramework><ApplicationIcon /><StartupObject />
</PropertyGroup>
<ItemGroup><PackageReference Include="Newtonsoft.Json" Version="10.0.3" /><PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>
<ItemGroup><ProjectReference Include = "c:\work\StandardTest\StandardTest.csproj" />
</ItemGroup></Project>
DotNetCoreのcsprojはシンプル
↑対象のに合わせる
↧host.exeで使う参照
↧対象プロジェクトへのフルパス
![Page 71: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/71.jpg)
ビルド、実行はdotnetexeを使う
あれ?今日のチャックさんの話きいたらRunだけでよかったんじゃ・・・
コマンドラインの情報
https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet?tabs=netcore2x
dotnet restoredotnet builddotnet 対象.dll
今回使ったのは以下
![Page 72: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/72.jpg)
Restore 実行
WorkDirの設定がポイント
var exeOutput = new List<string>(); var p = Process.Start(new ProcessStartInfo{
FileName = "dotnet",Arguments = "restore",WorkingDirectory = workDir,UseShellExecute = false,CreateNoWindow = true,RedirectStandardOutput = true
});p.OutputDataReceived += (_, e) =>{
exeOutput.Add(e.Data);};p.BeginOutputReadLine();p.WaitForExit();
![Page 73: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/73.jpg)
Builld実行
出力も取っておく
var p = Process.Start(new ProcessStartInfo{
FileName = "dotnet",Arguments = "build" + (isDebug ? string.Empty : " -c Release"),WorkingDirectory = workDir,UseShellExecute = false,CreateNoWindow = true,RedirectStandardOutput = true
});p.OutputDataReceived += (_, e) =>{
exeOutput.Add(e.Data);};p.BeginOutputReadLine();p.WaitForExit();
![Page 74: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/74.jpg)
処理実行
他のもそうだけど、待ちは非同期で実行してメインスレッドを固めないようにしました。デバッグもできなくなるしね
var p = Process.Start(new ProcessStartInfo{
FileName = "dotnet",Arguments = isAttach ? "QuickShotExecuter.dll -a" : "QuickShotExecuter.dll",WorkingDirectory = targetDllDir,UseShellExecute = false,CreateNoWindow = true,
}); p.WaitForExit();
![Page 75: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/75.jpg)
QuickShotのTODO
・DotNetCore、DotNetStandardをもう少し速くしたい
・Xamarinとかも対応できないかなー
![Page 76: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/76.jpg)
最後になりましたが、QuickShotのInternal なオブジェクトを生成する部分の実装はneue.ccさんの ChainingAssertionのDynamicAccessorの実装大幅にパクりました。
あざっす!
謝辞
![Page 77: Dot netconf2017 - VS拡張](https://reader034.fdocument.pub/reader034/viewer/2022042611/5a64792c7f8b9a46568b4677/html5/thumbnails/77.jpg)
・Friendlyhttps://github.com/Codeer-Software/Friendly.Windows
・LambdicSqlhttps://github.com/Codeer-Software/LambdicSql
・QuickShothttps://marketplace.visualstudio.com/items?itemName=ishikawa-tatsuya.Quickshot
みんな使ってね!
ご清聴ありがとうございました!