Xamarinで C# interactive を動かそう…としたが無理でした

Visual Studio 2013 には F# interactive というインタープリタ版の F# コマンドラインツールがあります。これを使うと、数値の計算とかコードの検算とかが楽なので便利に使っているのですが、Xamarin Studio にも F# interactive があります。

Xamarin Studio で「ビュー」→「パッド」→「F# interactive」で開くと、文字化けをしていますが開きます。フォントが悪いのか、ここのペイン(パッド)の文字解析部分が悪いのかわからないのですが、一応使えます。あらかじめ、XamarinでF#を使う方法 | Moonmile Solutions Blog で示したようなアドインを入れておく必要があります。

image

この Gallary の中に「C# interactive」というのがあって、名前の通り C# のインタープリタなようです。試してみようと思って、インストールして動かしてみるのですが、以下なエラーを吐いて落ちてしまいます。

image

んー、元のソースはないかと思って調べると、praeclarum/CSharpInteractive にあります。SQLite.net の作者の方ですね。見ると、mac 上の xamarin studio では動いているようなので、ちょっとソースを覗いてみると、なところでパスが指定されていました。

public class CSharpInteractiveSession : ProcessInteractiveSession
{
public override string GetFileName ()
{
return “/Library/Frameworks/Mono.framework/Versions/Current/bin/csharp”;
}
}

このパスは何なのだろうと思ったら、mono には csharp という C# インタープリタがあるんですね。これをインストールしないダメっぽいのです。んが、Windows の場合は、このパスにインストールされる訳ではないので多分書き換えないと駄目です。

Download – Mono
http://www.go-mono.com/mono-downloads/download.html

から mono 一式をダウンロードすると、csharp.exe は C:/Program Files (x86)/Mono-3.2.3/lib/mono/4.5/csharp.exe なところにあります。この部分を修正して、更に参照設定を monotouch のものから Windows のものに切り替えます。

image

アドインのパッケージのつくり方が分からないので、アドインの DLL を直接変更します。

C:/Users/masuda/AppData/Local/XamarinStudio-4.0/LocalInstall/Addins/CSharpInteractive.CSharpInteractive.1.0/CSharpInteractive.dll

を差し替えてやればOKです。

■これで動くかな?

と思ったのですが、残念。Console アクセスでエラーになっているので、mac のターミナルと windows のコマンドラインの差をうまく変更しないと駄目そうですね。

image

ちなみに、csharp.exe をコマンドラインで動かすとうまく動きます。

image

書いた後に気づいたのですが、Download LINQPad でもいいし、CsharpRepl – Mono でも十分かも。

カテゴリー: C#, Xamarin | Xamarinで C# interactive を動かそう…としたが無理でした はコメントを受け付けていません

内蔵 WebBrowser を Fiddler でトラップする方法

艦これのバトルJSONを再解析(祥鳳改小破編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5517

の続きで、ブラウザの通信をトラップするのに InternetSetOption を使っていたのですが、URLMonInterop.SetProxyInProcess を使ってもできるよ、という話があったので試しに。InternetSetOption 関数自体は結構古くからある方法で定番のようです。たぶん、内部的にも同じことをやっているのかなと。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    FiddlerApplication.Startup(PROXY_PORT, false, true);
    // SetIESettings("localhost:" + PROXY_PORT);
    URLMonInterop.SetProxyInProcess("127.0.0.1:" + PROXY_PORT.ToString(), "");
    FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;
    this.wb.Navigate(URL_LOGIN);
}

こんな感じで1行で済みます。ちなみに InternetSetOption 関数を使った場合はこんな感じ。

internal struct INTERNET_PROXY_INFO
{
    public int dwAccessType;
    public IntPtr proxy;
    public IntPtr proxyBypass;
}
[DllImport("wininet.dll", SetLastError = true)]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);

private void SetIESettings(string proxyUri)
{
    const int INTERNET_OPTION_PROXY = 38;
    const int INTERNET_OPEN_TYPE_PROXY = 3;

    INTERNET_PROXY_INFO proxyInfo;
    proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
    proxyInfo.proxy = Marshal.StringToHGlobalAnsi(proxyUri);
    proxyInfo.proxyBypass = Marshal.StringToHGlobalAnsi("local");

    var proxyInfoSize = Marshal.SizeOf(proxyInfo);
    var proxyInfoPtr = Marshal.AllocCoTaskMem(proxyInfoSize);
    Marshal.StructureToPtr(proxyInfo, proxyInfoPtr, true);
    InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, proxyInfoPtr, proxyInfoSize);
}

サンプルはこんな感じ

https://github.com/moonmile/KcAgent/tree/master/KcAgentBrowser

F12キーを押すとデバッグ用のウィンドウを開きます。そのうち、JSON 解析と swf/mp3 のダウンロード機能とかつける予定。

カテゴリー: 開発, 艦これ | 内蔵 WebBrowser を Fiddler でトラップする方法 はコメントを受け付けていません

XamarinでF#を使う方法

Xamarin Studio は F# をサポートしています…という記述があります。で、具体的にどうするのか?という記述を見かけなかったので、メモとして。

Xamarin Studio の「ツール」→「アドインマネージャ」で Gallary を開きます。

image

  • Mobile Development の F# support for Xamarin.Android development
  • Language bindings の F# Language Binding

の両方をインストールします。たぶん、Mobile のほうが Android に組み込む FSharep.Core で、Language のほうはコンパイラのほうだと思います。見ると、Lua とか D 言語とか並んでいるので、これでもプログラムが組めるのかも。

そうすると「新しいソリューション」でF#のAndroidアプリが組めるようになります。

image

テンプレートのコードも F# なので、Android も F# で組めますね。めでたしめでたし。

image

…と言いたいところなのですが、Xamarin の F# プロジェクトには Potral Class Library がありません。更に言うと、Xamarin が提供する FSharp.Core は Android 用のものはあるのですが、iOS 用はありません。Android 用は C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/MonoAndroid/v1.0/FSharp.Core.dll という DLL を参照していますが、iOS 版はないのです。

追記 2014/03/18
…と思ったのですが、実はあります。 monotouch のフォルダに FSharp.core がありました。なので、これをうまく使うと共有できますね。

ということは、F# で作ると、Android と Windows ストアアプリでは共有できるけど、iOS では共有できない。という結論になるのですが、ちょっと工夫すると F# のコードを Android/iOS/Windows で共有できます。

■Visual Studio で F# の PCL を作る

まずは Visual Studio で「ポータブルクラスライブラリ」を作ります。

image

F# で公開するクラスを使って C# で作った Android/iOS プロジェクトで参照すればよいのです。ビジネスロジックを F# で作りたい場合はこれでOKです。UI 部分も F# で作りたい場合は Xamarin Studio を使えばいいのですが、それだと iOS アプリがハブられてしまうという訳で。

ただし、ここで作った F# のコードですが、これもちょっとコツが要ります。

namespace XamarinFsLib

type OreOre() =
    let (+++) x y =
        x @ y |> Seq.distinct |> Seq.toList
    let (---) x y =
        Set.intersect (Set.ofList x) (Set.ofList y)
        |> Set.toList
    member this.X = "F#"
//    member this.join (x, y) = x +++ y
//    member this.intersect (x, y) = x --- y
    // for C#
    member this.join (x:int[]) (y:int[]) =
        let x' = List.ofArray x
        let y' = List.ofArray y
        x' +++ y' |> List.toArray
    member this.intersect (x:int[]) (y:int[]) =
        let x' = List.ofArray x
        let y' = List.ofArray y
        x' --- y' |> List.toArray

UI用のプロジェクトで FSharp.Core を参照させてしまうと、iOS で動かなくなってしまうので、これの参照しないようにします。また、Visual Studio の PCL では、

C:/Program Files (x86)/MSBuild/../Reference Assemblies/Microsoft/FSharp/.NETCore/3.3.1.0/FSharp.Core.dll を参照しているのですが、Android のほうは

C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/MonoAndroid/v1.0/FSharp.Core.dll を参照するので、不整合が起こります。これもあって、UI 側で FSharp.Core を参照しないようにします。

先の join メソッドで List.toArray しているのは、C# 側で int[] で受け取れるからです。List を使うと F# の List が使われてしまうのでわざと int[] を使っています。こんな風にすると、UI で FSharp.Core を参照しなくて済みます。多分、Generic 関係で渡しても OK だと思います。

あと、C# の場合 join メソッドを多重化できますが、F# ではそのままではできません。なので、引数を Tuple にすればいいのですが…まあ、そうすると F# 側で使うのが面倒なんですけどね。

image

そんなわけで、F# の PCL を Android/iOS アプリが作れるようになりました。

サンプルは 以下からダウンロードできます。
http://1drv.ms/1g1WE9M

ちなみに、このソリューションを Xamarin Studio を開くと以下のようなエラーがでます。mono版の FSharp.Core を期待しているところに、MS版の FSharp.Core を入れられた訳で、仕方がないといえば仕方がないですね。

image

カテゴリー: F#, Xamarin | XamarinでF#を使う方法 はコメントを受け付けていません

オレオレF#でフォークしました

オープン版が https://github.com/fsharp/fsharp にあると分かったので、https://github.com/moonmile/fsharp にフォークを作りました。

ひとまず、数学の記号だけを入れようと思って、[‘u2190’-‘u245f’] な風に範囲しています。文字コード表の「数学記号」なところが入ってます。

image

最近、ちょうど「最短距離の本」を読んでいるところで、その中に集合の記号がでてきます。

image

こんな感じで書けると、数式からF#へ直しやすいかなと。ただし、このままだと、F# Interactive でエラーになるし、Visual Studio の構文チェックが動きません。なので非常に書きづらい…というか、インテリセンスがないと私にはF#が書けない。

まあ、とりあえず、オレオレF# をビルドすると、

open System

let A = [1;2;3]
let B = [3;4;5]

// ∪記号
let (∪) x y =
    x @ y |> Seq.distinct |> Seq.toList
// ∩記号
let (∩) x y =
    Set.intersect (Set.ofList x) (Set.ofList y)
    |> Set.toList

printfn "和集合: %A" (A ∪ B)
printfn "積集合: %A" (A ∩ B)

なコードをビルドできます。実行結果はこちら。

image

カテゴリー: F# | 1件のコメント

オレオレF#コンパイラを作って集合論の記号(∩とか∪とか)の演算子が使えるようにする

を同時に実践しようと思って、F#のコンパイラを半日ほどいじってみました。

F# のコンパイラのソースコードは↓でダウンロードができます。

F# PowerPack with F# Compiler Source Drops – Source Code
https://fsharppowerpack.codeplex.com/SourceControl/latest

中身が見れるということは、修正できるということで、修正できるということは何かあったら自分で修正しろって訳ですね。たぶん。

■なぜ、コンパイラを弄るのか?

F# の場合、演算子は記号の組み合わせで作ります。この記号の組み合わせで、多用な演算子が作れるわけですが「+++」とか「—」とか一定の記号の組みあわせしかできないんですよね。

F# で Fizz-Buzz 番外編 – 新しい演算子の作成と、パイプライン演算子 : @jsakamoto
http://devadjust.exblog.jp/11067474/

を見たあたりから「残念、F# って記号の組み合わせしかダメなのか」と思っていたわけですが、Scala ができるわけだから(できるというのはつい先日知りました。正確には先のオレオレF#コンパイラを作った後に知りました)、F# でできない訳はないだろうってことです。
ただし、Scala の場合は、「演算子」を統一的にメソッドに置き換えるのですが、F# の場合は関数に括弧を入れないので、演算子と関数(キーワード)とは別に管理しているようです。まあ、カリー化をすると、これはこれでいいような気がします。表面的には演算子を関数としても使えるようです。

少しコンパイラを齧った方は分かると思うのですが、コンパイラを作るときには lex と yacc を使って文字解析と構文解析をします。F# には fslex と fsyacc という F# 実装のものがあります。となると、演算子を記号縛りにしているのは lex か yacc あたりを見れば OK と見当がつきます。

集合にはなっていませんが、集合の記号だけ使うと、以下のように演算子を定義しますが…∪のところでエラーになります。

open System
let (∪) x y = x + y
let (∩) x y = x - y

let ans1 = 10 ∪ 20
let ans2 = 10 ∩ 20
printfn "ans1:%A" ans1
printfn "ans2:%A" ans2

なので、代わりに下のような「代替」の演算子を作るわけですが…これって、数式をプログラムに直すときに無駄なギャップになるんですよね。

open System
let (+++) x y = x + y
let (---) x y = x - y

let ans1 = 10 +++ 20
let ans2 = 10 --- 20
printfn "ans1:%A" ans1
printfn "ans2:%A" ans2

できることならば、紙に書いた数式からプログラムコードに平たく直したいのです。そうするほうが、バグが混入しにくくなりますよね。wxMaxima と同じ発想です。

となると、演算子を記号のみにしてしまっている lex の部分に「∩」や「∪」を入れればなんとなるんではないかと。

■F#コンパイラを自前ビルドする

F# PowerPack with F# Compiler Source Drops – Source Code
https://fsharppowerpack.codeplex.com/SourceControl/latest

からソースコードをダウンロードして、compiler\3.1\Nov2013\README.html にある通りに、proto comiler を作ります。開発用のコマンドラインを「管理者権限」で実行して、以下を実行。

  cd src
  gacutil /i ..lkg\FSharp-2.0.50726.900\bin\FSharp.Core.dll
  msbuild fsharp-proto-build.proj
  ngen install ..Protonet40binfsc-proto.exe

これをやらないと、Visual Studio で F# プロジェクトがロードできません。
コンパイラ自体は、Fsc プロジェクトです。文字解析、構文解析の部分は、FSharp.Compiler プロジェクトの
lex.fsl と pars.fsy になります。それぞれ、ビルドを実行すると、fslex と fsyacc が使われます。

ひとまず Fsc をビルドします。結構時間が掛かりますが(10分ぐらい?)ビルドができて、自前のF#コンパイラができます。

■演算子を増やしてみる

最終的には、自由な演算子を作りたいのですが、暫定的に「∩」や「∪」だけを追加します。どうもカリー化の関係で文字解析部分で演算子を記号にしないとうまくいかなそうなのですが、F#の場合、関数定義などは前方参照のみなので、構文解析側(pars.fsy)をうまく修正すれば、回避できそうかなと。再帰関数の rec も外せそうな気がします。

lex.fsl を開いて、174行目あたり

let op_char = '!'|'$'|'%'|'&'|'*'|'+'|'-'|'.'|'/'|'<'|'='|'>'|'?'|'@'|'^'|'|'|'~'|':'
	|'あ'|'い'|'う'|'え'|'お'
	|'∪'|'∩'

な感じで、使いたい演算子を追加します。この部分は [‘あ’-‘ん’]のように範囲指定できるかもしれません(試していない)。

237行目あたりで、以下のように演算子の解析を入れます。

rule token args skip = parse
 | ignored_op_char* ('あ'|'い'|'う'|'え'|'お'|'∪'|'∩') op_char* { checkExprOp lexbuf; PLUS_MINUS_OP(lexeme lexbuf) }
 | ident
     { Keywords.KeywordOrIdentifierToken args lexbuf (lexeme lexbuf) }

キーワードを解析している Keywords.KeywordOrIdentifierToken の前に入れてしまうのがミソです。token を PLUS_MINUS_OP にしていますが、これは何でもOKです。どうせ再定義してしまうので。

これでビルドをしてから、先の F# コードをオレオレF#コンパイラでコンパイルしてみてください。うまくビルドができて、実行できます。ぱちぱちぱち。

open System
let (∪) x y = x + y
let (∩) x y = x - y

let ans1 = 10 ∪ 20
let ans2 = 10 ∩ 20
printfn "ans1:%A" ans1
printfn "ans2:%A" ans2

演算子は「あいうえお」のように複数でも定義できるし「あ+あ+あ」のように元の記号と組み合わせもできます。このあたりは、論理記号、集合論の記号を入れておきたいところです。

数学記号の表 – Wikipedia
http://ja.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E8%A8%98%E5%8F%B7%E3%81%AE%E8%A1%A8

■演算子とキーワードをデバッグする

演算子のチェックは checkExprOp で、キーワードのチェックは KeywordOrIdentifierToken で行っているので、ここにデバッグログを入れておきます。

演算子チェックは、lex.fsl 内

let checkExprOp (lexbuf:UnicodeLexing.Lexbuf) =
    printfn "exprOp %A" (lexeme lexbuf)
    if String.contains (lexeme lexbuf)  ':' then
        deprecatedWithError (FSComp.SR.lexCharNotAllowedInOperatorNames(":")) lexbuf.LexemeRange;
    if String.contains (lexeme lexbuf)  '$' then
        deprecatedWithError (FSComp.SR.lexCharNotAllowedInOperatorNames("$")) lexbuf.LexemeRange

キーワードチェックは lexhelp.fs 内

    let KeywordOrIdentifierToken args (lexbuf:UnicodeLexing.Lexbuf) s =
        printfn "keyword %A" s
        if not permitFsharpKeywords && List.mem s unreserveWords then
...

これを入れた状態でF#コードをコンパイルすると、演算子/キーワードの状態がわかります。
あとは、集合論の記号あたりを入れて、ざっと実装していくということで。

カテゴリー: F# | 1件のコメント

艦これのバトルJSONをNetwork Monitorで解析(端歩編)

艦これのバトルJSONを再解析(祥鳳改小破編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5517

で解析をした後で、hp を減算すれば ok というのは分かったので、さて他の艦これブラウザを見てみると…なんか、もうこれでいいやってな感じになってしまいました。もともと諜報員はデスクトップアクセサリ的に作りたかったわけで、戦略ゲーム的な内容を調査してというのはちょっと苦手で。ただし、デスクトップアクセサリといえば、

<b>MMDDM</b>MMDモデル用デスクトップマスコットツール?-?[?BowlRoll?]
http://bowlroll.net/up/dl30246

が動いているわけで、これでもいいか(偉そう)ってな感じになってます。そうなると、

  • 艦これブラウザで、GUI をまかなう
  • MMDDM で 榛名/ハルナ のマスコットが動く

という2点を満たせればいいわけで(ワタクシ的には)、となるとここの繋ぎの部分を作ればいいわけですね。業務的にもよくあるパターンです。

艦これブラウザは、

回転母港ページ
http://spinpreach.webcrow.jp/SpinHomePort.html
艦これ 司令部室
http://nozomi.arege.jp/KanHQ/
提督業も忙しい! | grabacr.net
http://grabacr.net/kancolleviewer

を使います。後、ブラウザ上(IE,Firefoxなど)で艦これを動かしている場合も含めます。先の艦これブラウザが fiddler を使っているので、fiddler から fiddler をフックすればいいのですが、ちょっとこれがうまくいかず。更に通常のブラウザの場合は fiddler だけではうまくいかないので(タブブラウザなのでピンポイントで proxy を変えることができるのか不明)、network monitor に立ち返って調べています。

Download Microsoft Network Monitor 3.4 from Official Microsoft Download Center
http://www.microsoft.com/en-us/download/details.aspx?id=4865

ネットワークのフックツールが wincap → network monitor → fiddler となっているので、ひとつ手前の技術なのですが、fiddler と違ってネットワーク全体をフックします(ネットワークドライバー系なのか、ちょっと不明)。なので、PC全体のネットワークを監視できますね。当然、proxy 形式の fiddler もフックできます。
逆に、fiddler にできて、network monitor にできないのが、

  • 通信データを改変する。
  • fiddler は HTTP プロトコルに特化していて、C#/VB.NETから扱いやすい。
  • network monitor をインストールする必要がある(多分)

なところです。下りデータの swf や mp3 を改変して「榛名をハルナにする」ことは network monitor ではできませんが、まあ、夜戦前の状態取得とか、Azure mobile service と連携して push 通信とかならできそうです(当然、fiddler でも可能ですが)。あと、network monitor の場合は、データをモニタ型式(たぶん内部的なコピー)で取ってくるので、PCに対するネットワーク負荷が(たぶん)低いと思われます。まあ、これも艦これに対してだけだし、艦これサーバー自体には fiddler でも network monitor でも負荷が低いのは同じなので(むしろブラウザのほうが負荷が高い)そのあたりは問題ありません。

■network monitor で艦これ通信だけ抽出する

Display Filter で以下を設定すれば OK です。SourceAddress は、艦これサーバーなので鎮守府が違うと別IPになります。URIで絞ったほうがいいも

.ProtocolName == "HTTP" and
.HTTP.Response and
.Ipv4.SourceAddress == XXX.XXX.XXX.167

■ヘルプを見る

実は network monitor には api があります。ヘルプもあります。API は wincap だけかと思い込んでいたので、これは結構使えますね。

C:Program FilesMicrosoft Network Monitor 3HelpNetMon.chm

なところに HTML ヘルプがあります。C++とC#の api も API フォルダに NmApi.h や NetmonAPI.cs というファイルであります。ヘルプには api を使ったサンプルが載っているので、これを手がかりにして作っています。

■api を使ってフックする

まだまだ途中ですが、晒しておきます。google で検索してもリアルタイムにフックする方法がなかなか出てこないので。
ハンドルのクローズとか例外処理とかは省いています。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // netmon api の初期化
    IntPtr phCaptureEngine = IntPtr.Zero;
    NetmonAPI.NmOpenCaptureEngine(out phCaptureEngine);
    // フィルタを作成
    MyLoadNPL();

    // ネットワークアダプタのチェック(複数差し込み、VMWare Netなど)
    uint ucnt = 0;
    NetmonAPI.NmGetAdapterCount(phCaptureEngine, out ucnt);
    NM_NIC_ADAPTER_INFO adapterInfo = new NM_NIC_ADAPTER_INFO();
    adapterInfo.Size = (ushort)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NM_NIC_ADAPTER_INFO));
    // 4番目のネットワークをフック
    uint ulIndex = 3;
    uint errno = NetmonAPI.NmGetAdapter(phCaptureEngine, ulIndex, ref adapterInfo);
    // モニタの準備
    uint ret = 0;
    IntPtr myTempCap = IntPtr.Zero;
    ret = NetmonAPI.NmConfigAdapter(phCaptureEngine, ulIndex,
        new CaptureCallbackDelegate(FrameIndicationCallback), 
        myTempCap, 
        NmCaptureCallbackExitMode.ReturnRemainFrames);
    // モニタの開始
    ret = NetmonAPI.NmStartCapture(phCaptureEngine, ulIndex, NmCaptureMode.Promiscuous);


}
/// <summary>
/// コールバック
/// </summary>
/// <param name="hCapEng"></param>
/// <param name="ulAdatIdx"></param>
/// <param name="pContext"></param>
/// <param name="hRawFrame"></param>
public void FrameIndicationCallback(IntPtr hCapEng, UInt32 ulAdatIdx, IntPtr pContext, IntPtr hRawFrame)
{

    IntPtr parsedFrame, insertedRawFrame;
    // フレームのパースチェック
    if( NetmonAPI.NmParseFrame(
        _frameParserHandle,
        hRawFrame,
        0,
        NmFrameParsingOption.None ,
        out parsedFrame,
        out insertedRawFrame)  != 0 )
    {
        // NetmonAPI.NmCloseHandle(hRawFrame);
        return;
    }

    // フィルタ
    bool passed = false;
    NetmonAPI.NmEvaluateFilter(parsedFrame, _httpFilterId, out passed);
    if (passed == false)
        return;

    uint ret;
    var name = new char[256];
    // ポインタを直接扱うので unsafe を使う
    unsafe
    {
        fixed (char* value = &name[0])
        {
            ret = NetmonAPI.NmGetFieldValueString(parsedFrame, _uriFeildId, 256, value);
        }
    }
    var bytes = new byte[4000];
    unsafe
    {
        fixed (byte* buf = &bytes[0])
        {
            uint offset, size;
            NetmonAPI.?NmGetFieldOffsetAndSize(parsedFrame, _uriFeildId, out offset, out size);
            Debug.WriteLine("offset:{0} size:{1} ", offset, size);
            // NetmonAPI.NmGetRawFrame(hRawFrame, 4000, buf, out size);
            // Debug.WriteLine("size2 {0}", size);
        }
    }
}

IntPtr _engineHandle, _frameParserHandle, _nplParserHandle, _configParserHandle;
uint _httpFilterId, _uriFeildId;

private void MyParserBuild(IntPtr pCallerContext, uint ulStatusCode, string lpDescription, NmCallbackMsgType ulType)
{
    /*
    // throw new NotImplementedException();
    if (pCallerContext == IntPtr.Zero)
        return;

    GCHandle gch = GCHandle.FromIntPtr(pCallerContext);
    NM_NIC_ADAPTER_INFO adapterInfo = (NM_NIC_ADAPTER_INFO)gch.Target;
        * */
}
/// <summary>
/// フィルタの作成
/// </summary>
void MyLoadNPL()
{
    IntPtr myFrameParser = IntPtr.Zero;
    ulong ret;
    IntPtr myNplParser = IntPtr.Zero;
    IntPtr myFrameParserConfig = IntPtr.Zero;


    // Use NULL to load the default NPL parser set.
    ret = NetmonAPI.NmLoadNplParser(null, NmNplParserLoadingOption.NmAppendRegisteredNplSets, MyParserBuild, IntPtr.Zero, out myNplParser);
    ret = NetmonAPI.NmCreateFrameParserConfiguration(myNplParser, MyParserBuild, IntPtr.Zero, out myFrameParserConfig);
    ret = NetmonAPI.NmConfigConversation(myFrameParserConfig, NmConversationConfigOption.None, true);
    ret = NetmonAPI.NmConfigReassembly(myFrameParserConfig, NmReassemblyConfigOption.None, true);

    uint myHTTPFilterID = 0;
    uint myHTTPFieldID = 0;
    // ret = NetmonAPI.NmAddFilter(myFrameParserConfig, "http.request.command == "GET"", out myHTTPFilterID);
    // ret = NetmonAPI.NmAddField( myFrameParserConfig, "http.request.uri", out myHTTPFieldID);
    // ret = NetmonAPI.NmAddFilter(myFrameParserConfig, "Protocol.HTTP", out _httpFilterId);
    // ret = NetmonAPI.NmAddFilter(myFrameParserConfig, "tcp.Port == 80", out _httpFilterId);
    ret = NetmonAPI.NmAddFilter(myFrameParserConfig, "http.request.command == "GET"", out _httpFilterId);
    ret = NetmonAPI.NmAddField(myFrameParserConfig, "http.request.uri", out _uriFeildId);
    ret = NetmonAPI.NmCreateFrameParser(myFrameParserConfig, out myFrameParser, NmFrameParserOptimizeOption.ParserOptimizeNone);
    _frameParserHandle = myFrameParser;
}

初期化は、
1. NmOpenCaptureEngine で api 初期化
2. NmGetAdapterCount と NmGetAdapter で、フック対象のネットワークアダプタを取得
3. NmConfigAdapter でコールバック関数の登録
4. NmStartCapture でモニタ開始

フィルタ作成は、
1. NmLoadNplParser と NmCreateFrameParserConfiguration で初期化
2. NmAddFilter でフィルタ作成
3. NmAddField でフィールド作成(値を取得するところ)
4. NmCreateFrameParser でパーサの作成
_httpFilterId や _uriFeildId は、グローバルに保存しておいて使いまわしをします。たぶん、コールバックの時に作ってもよいのですが、あらかじめ作ったほうがハンドルとしてベターかと。

コールバック関数には、全ての通信が入って来るのでフィルタで選別します(ここに注意)。
1. 最初に NmParseFrame でパースします。
2. NmEvaluateFilter で、先に作成したフィルタを適用
3. NmGetFieldValueString や NmGetFieldOffsetAndSize などを使って各種フィールドの値を取得

network monitor を調べていくと NPL にぶち当たるのですが、所謂構造体定義です。

Network Monitor Open Source Parsers – Home
http://nmparsers.codeplex.com/

HTTPプロトコルとかICMPプロトコルとか、各種プロトコルを疑似的な構造対で定義します(中身はコードです)。これは、既に network monitor にデフォルトで含まれているので NmLoadNplParser の NmNplParserLoadingOption.NmAppendRegisteredNplSets で読み込ませれば OK です。独自プロトコルを作るときには NPL を作ればいいのでしょう。ここでは HTTP プロトコルしか使わないのでこれで十分です。

netmon api の C# は薄いラッパーなので、NmGetFieldValueString を使った受け渡しはポインタになります。この手のデータを扱うためには unsafe と fixed が必要なのですが…このあたりは C++/CLI で作り直したほうがよさそう。あるいは、string に変換する関数を作るとか。
または HTTP プロトコルしか使わないので、fidder 互換にしてしまうのがよさそうですね。まあ、network monitor 自体が 2010/06 で更新が終わっているので、今更感がありますが。ネットワーク解析的には便利かな。ちなみに、System requirements には Winodws 8 までしか書いてありませんが、Windows 8.1 x64 で動作してます。

カテゴリー: 艦これ | 艦これのバトルJSONをNetwork Monitorで解析(端歩編) はコメントを受け付けていません

艦これのバトルJSONを再解析(祥鳳改小破編)

Fiddlerを使って艦これのバトルJSONを解析(敷波復活編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5071

結局のところ Feddler 使った諜報ブラウザを作って再び解析。やっぱり夜戦の前とか続行の前とかに「うっかり続行してしまって撃沈」してしまうのもアレなので。いやいや、ゲームとしてはありなんですけどね。

  1. /kcsapi/api_req_sortie/battle
  2. /kcsapi/api_req_sortie/battleresult
  3. /kcsapi/api_get_member/deck
  4. /kcsapi/api_get_member/ship2
  5. /kcsapi/api_get_member/ship3

の順番で流れてくるので順番に調べます。以下、メモ的に。

戦闘を開始すると battle が降ってくるので、

“api_dock_id”:1,
“api_ship_ke”:[-1,510,510,510,505,502,502],
“api_ship_lv”:[-1,1,1,1,1,1,1],
“api_nowhps”:[-1,70,77,45,55,29,74,65,65,65,33,22,22],
“api_maxhps”:[-1,75,77,45,55,32,74,65,65,65,33,22,22],

で敵戦艦の種類とHPを取得。バトル自体の順番は、

“api_hougeki1”:{
“api_at_list”:[-1,2,1,12,6,7,4,5,3],
“api_at_type”:[-1,0,0,0,0,0,0,0,0],
“api_df_list”:[-1,[10],[9],[6],[12],[3],[8],[7],[7]],
“api_si_list”:[-1,7,8,502,7,-1,6,3,-1],
“api_cl_list”:[-1,[2],[1],[0],[1],[1],[1],[2],[1]],
“api_damage”:[-1,[129],[102],[0],[73],[12],[33.1],[28],[65]]
},
“api_hougeki2”:{
“api_at_list”:[-1,1],
“api_at_type”:[-1,0],
“api_df_list”:[-1,[8]],
“api_si_list”:[-1,8],
“api_cl_list”:[-1,[1]],
“api_damage”:[-1,[98]]
},
“api_hougeki3”:null,
“api_raigeki”:null
}

なところで、hougekiX を順番に調べればOK。たぶん、api_at_list のところが味方&敵の攻撃&防御の順番と思う。このあたりはあとで動画キャプチャを利用して突合せ。

戦闘が終わると battleresult が降ってくるので、これで結果をチェック。艦娘の経験値などは

“api_win_rank”:”S”,
“api_get_exp”:60,
“api_mvp”:1,
“api_member_lv”:54,
“api_member_exp”:146241,
“api_get_base_exp”:120,
“api_get_ship_exp”:[-1,432,144,144,144,144,144],
“api_get_exp_lvup”:[[390850,397000],[53943,56100],[41250,43500],[36353,37800],[44292,46500],[5851,6600]],

で取得。

“api_lost_flag”:[-1,0,0,0,0,0,0],

のところは、味方かロスト…だと思う。敵の撃沈がここではわからない?ので、先の api_damage あたりでチェック?

ここで、祥鳳改が「小破」になっているので、

image

続き deck で艦隊に属している艦娘を調べて、

{
“api_member_id”:41898,
“api_id”:1,
“api_name”:”u524du885bu8266u968a”,
“api_name_id”:”110117909,
“api_mission”:[0,0,0,0],
“api_flagship”:”0″,
“api_ship”:[83,252,278,81,288,675]
},

ここの api_ship は「保持してい艦娘」。保持している祥鳳改は「278」なので、ship2 か ship3 で艦娘IDに直すと、「282」が「祥鳳改」とわかる。

{
“api_id”:278,
“api_sortno”:382,
“api_ship_id”:282,
“api_lv”:29,
“api_exp”:[41394,2106,27],
“api_nowhp”:33,
“api_maxhp”:45,
“api_leng”:1,
“api_slot”:[699,700,475,218,-1],
“api_onslot”:[18,12,12,6,0],
“api_kyouka”:[11,0,6,6,0],
“api_backs”:4,
“api_fuel”:40,
“api_bull”:40,
“api_slotnum”:4,
“api_ndock_time”:4260000,
“api_ndock_item”:[15,28],
“api_srate”:1,
“api_cond”:49,
“api_karyoku”:[11,29],
“api_raisou”:[0,0],
“api_taiku”:[30,39],
“api_soukou”:[31,59],
“api_kaihi”:[37,59],
“api_taisen”:[9,0],
“api_sakuteki”:[47,79],
“api_lucky”:[12,59],
“api_locked”:1
},

小破などは、

“api_nowhp”:33,
“api_maxhp”:45,

を見るのだと思う。ここは後で。ちなみに、弾丸と燃料が

“api_fuel”:40,
“api_bull”:40,

入渠がこれ。

“api_ndock_time”:4260000,
“api_ndock_item”:[15,28],

なので、進撃の選択の場合は ship2 が降ってくるので、これから hp を見ればいいんだけど、夜戦の場合は違うようで、battle の後に「夜戦」の選択になるので、battle の api_damage を見て艦娘の hp を減らさないといけない。

多分、艦娘と敵艦の hp と

“api_ship_ke”:[-1,510,510,510,505,502,502],
“api_ship_lv”:[-1,1,1,1,1,1,1],
“api_nowhps”:[-1,70,77,45,55,29,74,65,65,65,33,22,22],
“api_maxhps”:[-1,75,77,45,55,32,74,65,65,65,33,22,22],

バトルの対応(1から12番まで)があるので、これで hp を引けばいい。

“api_hougeki1”:{
“api_at_list”:[-1,2,1,12,6,7,4,5,3],
“api_at_type”:[-1,0,0,0,0,0,0,0,0],
“api_df_list”:[-1,[10],[9],[6],[12],[3],[8],[7],[7]],
“api_si_list”:[-1,7,8,502,7,-1,6,3,-1],
“api_cl_list”:[-1,[2],[1],[0],[1],[1],[1],[2],[1]],
“api_damage”:[-1,[129],[102],[0],[73],[12],[33.1],[28],[65]]
},

演習の場合もいっしょ。小破、大破などは、maxhp が分かっているので hp と比較して割合だと思う。艦娘の名前は先に現れる ship2 などであらかじめチェックしておけばOK。

カテゴリー: 艦これ | 2件のコメント

MVP Community Camp 2014でXamarinの話をします

MVP Community Camp 2014
https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032577010&culture=ja-JP

来る3月22日(土)に東京会場で「Xamarinで作るiPhoneとWindows ストア アプリの共通コンポーネント」というタイトルで話します。iPhoneとWindowsストアアプリ、ってことになっていますが、実際はXamarinでiOS/Android/WinRTで共通のコードを使おう(PLC)ってことです。手元で作っている下なアプリ(というかゲーム)をベースにしてプロジェクト構成とかXamariの使い方とかを話す予定です。ええ、予定ってのは、まだプレゼン資料を作ってないからなんですね。

image

Xamarin自体は、http://xamarin.com/ からダウンロードしてBUSSINESS版が試用期間1か月で試すことができます。最近は、Microsoft MVP の方向け無償 Xamarin Business ライセンスについて – Xamarin 日本語情報 な感じで MVP の方に配っていたりします(これは去年も配っていました)。

プレゼンで発表するのは、Visual Studio との組み合わせで結構な値段($999/年)するほうなのですが、Xamarin Studio だけで開発するならば INDIE版が $299/年 で手に入ります。「結構な値段」というのは、当時会社員だったときMSDNが年間15万円ぐらいを自腹で買っていました。Windows XPとVisual Studio 6.0、Office が手に入ってそれはそれでよかったのですが、Xamarin だと Xamarin だけなんですよね。ただ、前身の MonoDevelop や Xamarin Studio とXcode との連携を考えてみると、それだけの労力はある削減されるような気がするのですが。

ええ、おそらく Xamarin はきっちり「費用対効果」を考えないといけない代物です。そこに対して「先行投資」をしてきちんとペイできるか、を考えないと駄目で「興味」だけでやるには高価な遊び道具ですね。もちろん「高価な趣味」として嗜むのもよいのですが。

そんなことを踏まえてか踏まえてないか、3/22 は品川へどうぞ。ちなみに MvvmCross な話は14:00 からの田中さん担当で。私のところは、普通にPCLの話か、Xamarin で具体的にゲームをつくっていく話です。

カテゴリー: Xamarin, 勉強会 | MVP Community Camp 2014でXamarinの話をします はコメントを受け付けていません

うっかりAndroid SDK ToolsをアップデートしてXamarin StudioのAXMLデザイナが動かなくなった時の対処

現時点 Xamarin Studio 4.2.3 のものなので、いずれ直るかもしれませんが。念のため。

追記 2014/03/19
現在 Xamarin.Android 4.12.x の場合は、逆に Andorid SDK tools ver 22.6.x 以上を要求してきます。そうしないとデザイナが開けません。アップデートした後は SDK Manager で「Android SDK tools」をアップデートのこと

最新のAndroid 4.4.2 API 19 を入れようと思って、同時に「Android SDK tools」を「22.6」にアップデートしてしまうと…

image

こんな風に Xamarin Studio の AXML デザイナが死にます。Disconnected from layout renderer. Please close open the file agein.  というメッセージが出て、閉じて開いてもダメ。
Xamarin Studio の場合はデザイナだけが死ぬですが、Visual Studio の場合は、Visual Studio ごと落ちるという憂き目に。

image

そもそもなんでデザイナだけが落ちるのか分からなかったので苦労したのですが…まあ、最新の Android SDK Tools を入れてダメだったんだから、前のバージョンに戻せばよい。戻せばよいのですが、どうやって戻せばいいのか分かりません。

SDK Tools | Android Developers からダウンロードのページ Android SDK | Android Developers へ行って、下にある DOWNLOAD FOR OTHER PLATFORMS をクリックすると、「最新のバージョン」はダウンロードできます。過去バージョンはどうするかという、アドレスを見て書き換えて、dl.google.com/android/android-sdk_r22.3-windows.zip をダウンロード。

これを解凍すると tools というフォルダがあるので、C:UsersmasudaAppDataLocalAndroidandroid-sdk の中に tools フォルダと置き換えます。すると無事 22.3 のバージョンが戻って AXML デザイナが動きます。めでたしめでたし。

ちなみに、Xamarin Studio 4.2.4 (Alpha版)にアップデートすると、下記のようになります。最悪ですね。

image

Xamarin-Studio Android Form Designer: Android Version not installed – Xamarin を見ると、api 19 にはデザイナが対応してないよってことなんですが、この返答自体が去年の11月なので、tools のアップデートはしなほうがよいかも。バグ報告したほうがいいのかな?

カテゴリー: Xamarin | うっかりAndroid SDK ToolsをアップデートしてXamarin StudioのAXMLデザイナが動かなくなった時の対処 はコメントを受け付けていません

Visual Studio 2013のソリューションをXamarin Studioを編集すると再び開けなくなる、の対処方法

Term Foundation Service を Xamarin から利用する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5461

で Mac 側とソース共有していたら突如として Xamarin Studioでソリューションが開けなくなったので、それの対処方法です。Xamarin Studio 4.2.3 です。

  1. Visual Studio 2013でXamarin.Andoroidのプロジェクトを作って保存
  2. Xamarin Studio で、作成したソリューションを開いて、なんか編集(スタートアプトとか)をして *.sln を保存
  3. 再び、Xamarin Studio を開くとエラーが発生。

image

なんかよくわからないけど、*.sln をメモ帳で開くと、

# Visual Studio 2012
VisualStudioVersion = {0}
MinimumVisualStudioVersion = {0}

な感じになっているので、

# Visual Studio 2013
VisualStudioVersion = 12.0.30110.0
MinimumVisualStudioVersion = 10.0.40219.1

に直します。ベータ版では直っているかもしれませんが、一応。

Windows 上のVisual Studio 2013(Xamarin.iOS)で編集をして、Mac上のXamarin Studioでデザイナ(storyboard)を編集してあれこれやっていたら、発覚した現象でした。これ関係で、Xamarin Studioでデバッグ実行ができなくなっていたのですが、VisualStudioVersion を直したら、うまく動いたので。Xamarin にはバグ報告済みです。

カテゴリー: Xamarin | Visual Studio 2013のソリューションをXamarin Studioを編集すると再び開けなくなる、の対処方法 はコメントを受け付けていません