前回の記事で紹介したNuGetのパッケージは、Visual Studio 2015リリースに向けての追い込みの時期に公開されたものです。バージョンは1.0.0-rc2なので、Visual Studio 2015に合わせて正式リリースするつもりであるように見えました。ただ、バックログを見ても色々課題が残っており、本当にあと少しで間に合うのかという不安もあったのです。
Roslyn for Scriptingは、当然内部でRoslynを使用しているので、スクリプトのパース結果はRoslynの抽象構文木で表現されているはずです。rc2では一体それがどこからアクセス可能なのか良くわかりませんでしたが、1.1.1ではScriptクラスのGetCompilationメソッドからアクセス出来ます。
public static async Task ExecuteScriptAsync()
{
Trace.WriteLine("Start script...");
var script1 = CSharpScript.Create(
@"var target = new
{
Id = 123,
Name = ""ABC""
};
Console.WriteLine(""Id={0}, Name={1}"", target.Id, target.Name);
").
WithOptions(
ScriptOptions.Default.
WithImports(
"System",
"System.Diagnostics").
WithReferences(
typeof(object).Assembly);
var compilation = script1.GetCompilation();
var tree = compilation.SyntaxTrees.ElementAt(0);
var compilationUnitSyntax = (CompilationUnitSyntax)tree.GetRoot();
var members = compilationUnitSyntax.Members.Select(member => member.GetText().ToString());
Console.WriteLine(string.Join(Environment.NewLine, members));
Trace.Write("Finished script");
}
前回と今回の記事で、Roslyn for Scriptingの足掛かりは出来たかなと思います。Roslyn、特にASTの辺りはスクリプティングとは関係なく、これまた膨大なトピックが詰まっていると思います。Roslynで言うならば、上はこのスクリプティングやコンパイラインターフェイス、下はVisual Studio 2015の「アナライザー」が、Roslynへの入り口となると思います。
// (あくまで概念コードです。これは正式なCOMのコードではありません)
public interface IUnknown
{
T QueryInterface<T>() where T : IUnknown;
int AddRef();
int Release();
}
public interface ICalc : IUnknown
{
int Add(int a, int b);
}
// クラスは直接公開されない
internal sealed class CalcImpl : IUnknown, ICalc
{
private int count_ = 1;
public int AddRef()
{
return Interlocked.Increment(ref count_);
}
public int Release()
{
var current = Interlocked.Decrement(ref count_);
if (count == 0)
{
// インスタンスの破棄処理
// Disposeに近いが、メモリストレージも削除される。
// 破棄処理を隠蔽することで、処理系依存を排除。
}
}
public T QueryInterface<T>() where T : IUnknown
{
// CやC++にはリフレクションは無いので、本当はインターフェイスID(GUID)で判定する。
// キャスト処理を隠蔽することで、処理系依存を排除。
if (typeof(T) == typeof(ICalc))
{
Interlocked.Increment(ref count_);
return (T)(object)this;
}
if (typeof(T) == typeof(IUnknown))
{
Interlocked.Increment(ref count_);
return (T)(object)this;
}
throw new NotImplementedException();
}
public int Add(int a, int b)
{
return a + b;
}
}
public interface IClassFactory
{
T CreateInstance<T>(Guid clsid) where T : IUnknown;
}
// クラスファクトリクラスも公開されない
internal sealed class CalcClassFactory : IClassFactory
{
public T CreateInstance<T>(Guid clsid) where T : IUnknown
{
if (clsid == CLSID_Calc)
{
// newの実装を隠蔽することで、処理系依存を排除。
return new CalcImpl();
}
throw new NotImplementedException();
}
}
// CalcImplを外部から特定するためのGuid
public static readonly Guid CLSID_Calc = new Guid("BD4D1DDD-9C28-4432-A8DD-9CFA77E6433F");
// DLL外からはこのエントリポイントだけが見える
public static IClassFactory DllGetClassObject()
{
return new CalcClassFactory();
}
ということで、一からIUnknownをCで実装するというハードは方法は時間もないのでパスし、ATL(Active Template Library)での実装方法をライブデモしました。ライブデモは私がやったのですが、ATLでバリバリ書いていたのはVisual Studio 2005の時だったので、2005を使ってデモ(こんなこともあろうかと、2005はインスコしてあるのだよ)。ATLは途中から、C#のような属性ベースの指定で楽に書けるようになったはずなのですが、結局私的には移行しなかったので分からず…
using ATLSampleLib;
class Program
{
static void Main(string[] args)
{
var testClass = new TestClass();
testClass.TestProp = "ABCX";
Console.WriteLine(testClass.TestProp);
}
}
using ATLSampleLib;
class Program
{
static void Main(string[] args)
{
var testClass = new TestClass();
testClass.TestProp = "ABCX";
Console.WriteLine(testClass.TestProp);
Marshal.FinalReleaseComObject(testClass);
}
}
今回、主題として「All about COM」と銘打ったのですが、実は「隠された副題」がありました。それは、「COM requiem」です。COMの全盛期は2000年頃(つまりもう15年も前)と思っているのですが、まだまだいたるところで使われており、すぐにomitすることは当面出来そうにありません。しかし、プログラミング環境は完全に.NETが主体となり、C++でコードを書く際も、ライブラリのインフラとしてCOMを選択すると言う事は殆ど無くなりました。
① コードの実行が開始されると、”Physical Memory”のグラフが跳ね上がり、16GB近辺まで上昇します。ここで、Windowsシステム全体が操作不能に近いぐらいにスローダウンします。グラフはスパイク状になっていますが、実際には上昇し切った時点でProcess Explorerもログ不能に陥ったようで、操作が回復するまでログが取れなかったためです。
② 操作が回復したとき、Physical Memoryの値が急激に低下していますが、Parallel.ForEachの処理は終わっても、まだプロセスは終了していません。
③ コードの実行が完了してプロセスが終了すると、System Commitのグラフも低下し、プロセス起動前の状態に戻っています。
そんなわけで、11月第一週は、MVP Global Summitに参加すべく、米国ワシントン州・シアトル・レドモンドへと行ってきました。国外に出るのは初めてなので、色々準備が必要だったのですが、特にパスポートの受領とスーツケースの新調が大きかったです。スーツケースは以前に長期出張の時に持っていっていたものがあったのですがすっかり忘れていて、どのみちもう重いのも辛いので、軽いやつを買いました。大きさは中ぐらい?何かお土産が出来た時に入るぐらいの大きさってことで考えました。
勢いで買ってしまった感があったんですが、非常に満足感が高かった。勿論、その日のうちにWindows 10 Mobile Insider Previewに更新。ちなみにSIMロックですが、6か月経つとAT&Tのサイトでアンロックできるようになるらしいです(すぐにアンロック出来るのかと勘違いしてトライしたけど、流石にダメだった)。ほかの方法として、某SIMロック解除サイトを使うと、$15ぐらいでアンロック出来ることも判明。参考までに。
まとめ
MVP Global Summitに参加するのが主題だったんですが、初の海外旅行・シアトル良いところ・サミットセッションももちろん、偶然入手したWindows Phoneや現地SIM調達など、ものすごく盛り沢山の旅行で本当に良かったです。次回MVPを受賞しているかどうかはわかりませんが、また行ってみたいなぁと思っています。
さて、今年私は「Microsoft MVP for .NET(今はカテゴリーが再編されたので、Visual Studio and Development Technology)」を受賞しました。MVPを受賞すると特典の一つとして、一年に一度行われる「MVP Global Summit」への参加資格が得られます。生まれてこの方、一度も日本を出たことがなかったので、この節目に行ってみようかと思いました。この記事ではその話に絡めてWindows Phoneの話をしようかと思いましたが、その前に「Microsoft MVP Award」(長いのでMSMVPと略します)についての紹介もしようかと思います。
「Microsoft Most Valuable Professional (MVP) は、自身のマイクロソフト技術に関する知識や経験を最大限に活かしながら、他のユーザーを積極的にサポートしている、非常に優れたコミュニティのリーダーです。彼らは、技術専門知識に加えて自主性と情熱を兼ね備え、マイクロソフト製品の実用的な活用方法をコミュニティやマイクロソフトと共有しています。」
MVP Global Summitへの参加権
毎年11月ぐらいに催されているようです。期間中、米国本社(ワシントン・シアトル付近)のホテルに無料で宿泊できますが、飛行機代やそれ以外のコストは自腹でねん出する必要があります。また、ここで見聞きする技術情報はNDAベースなので、最新情報を聞いて帰ってきても、喋ることは出来ません。