Fiddlerを使って艦これのバトルJSONを解析(敷波復活編)

ちょっと気になるツイートを見かけたのでそれ絡みで。

https://twitter.com/Sikushima/status/374120078976880640
「艦これ」から、ソーシャル系のサーバ構成を考える – SQLer 生島勘富 の日記
http://d.hatena.ne.jp/Sikushima/20130901/1378021345

艦これサーバーのトラブル云々には同意しかねるのですが、素直にMySQLのSQLで組んだほうが、下手にデータ構造を考えてAPIを作ったりするよりは断然早い、ところの同感です。更新系は兎も角、参照関係は断然RDBMSは早く作られているので、下手のO/RマッピングやるよりもSQL直で書いたほうが手早くかつ実行スピードがすばやくできます。ええ、SQL文を書ければ、の前提なのですが。

で、艦これの同時セッション絡みの部分、いくらか艦これをやっていて、いくらかFlashの通信部分を覗いてみると、さほどセッション/DBコネクション自体には負荷がかかっていないことが分かります。つーか、アクションRPGと違って、艦これの場合、サーバーとの通信が極端に少なくて、ガラ携のWEBゲームぐらい通信は少ない。なので、同時接続数(アクティブ数が30%だとしても3万人ぐらい)だとしても、DBコネクション等で輻輳しているところは更に1/100以下ぐらい、もっと少ないかもしれません。艦これの場合、Flashから各サーバーに送るのは、普通にRESTで送って、JSONで返ってきます。詳しく見ると cookie を使っていません。GET するときの URL に token が入っているのですが、多分ユーザIDへの紐づけかと。なので、非常にDBに負荷の少ない設計(意図的…ということにしておきましょう)になっています。ぷよぷよクエストとか、バウモンとか、レガリアを iPhone でやっていると、やたらに「ログイン中です…」が出るのですが、艦これの場合は全く出てきません。そういう意味では、パズドラも出てこないですね。優秀です。

このあたり、通常のソーシャルゲームにある、

  • ユーザーごとのチャット機能
  • 他ユーザーのデータを参照して、何かやる(仲間にするとか)する機能
  • リアルタイムに他ユーザーと何かやる機能

というのがごっそり抜けています。これは、各鎮守府サーバー(ログイン先のサーバー)間で通信が発生しない(発生できない)のと、まあ、そのあたりを設計しなかっった(意図的に…としておきます)ためです。なので、極端な話で言えば、ロードバランサーすら必要なくて(あるのかな?)、ひとつのサーバーで10万人程度受け持つ、という予算の中で組んで、開いてみたら思わずアクセスがあって、順々にサーバーを増やす、という作りになっているかと。と想像するわけですが、そのあたりは ツチノコブログ | DMM.comラボのインフラエンジニアブログ を参照して頂くということで。

なので、参照系のデータとしては艦船データやマップデータで、更新系は各ユーザーのHPやログインデータぐらいなもので、データベースへの輻輳の率を考えると、それほどシビアな形で使わないくてもうまくいのかな、と想像します。MySQL Clustor を使う位だから、それなりに負荷は掛かっているのでしょうが、同時コネクション数は、100程度あれば十分かも。

■戦闘の開始(battole)と結果(battleresult)

戦闘開始

svdata={
  "api_result":1,
  "api_result_msg":"成功",
  "api_data":{
    "api_dock_id":1,
    "api_ship_ke":[-1,509,509,502,502,502,-1],
    "api_ship_lv":[-1,1,1,1,1,1,-1],
    "api_nowhps":[-1,66,36,36,37,25,43,58,58,22,22,22,-1],
    "api_maxhps":[-1,75,40,36,37,25,63,58,58,22,22,22,-1],
    "api_midnight_flag":0,
    "api_eSlot":[[505,513,525,-1,-1],[505,513,525,-1,-1],[502,-1,-1,-1,-1],[502,-1,-1,-1,-1],[502,-1,-1,-1,-1],[-1,-1,-1,-1,-1]],
    "api_eKyouka":[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],
    "api_fParam":[[82,0,50,81],[3,0,26,25],[32,19,19,28],[39,24,31,30],[24,43,31,17],[74,0,38,69]],
    "api_eParam":[[32,32,16,28],[32,32,16,28],[7,16,7,6],[7,16,7,6],[7,16,7,6],[0,0,0,0]],
    "api_search":[1,1],
    "api_formation":[3,2,1],
    "api_stage_flag":[1,1,1],
    "api_kouku":{
      "api_plane_from":[[2],[-1]],
      "api_stage1":{
        "api_f_count":58,
        "api_f_lostcount":0,
        "api_e_count":0,
        "api_e_lostcount":0,
        "api_disp_seiku":1
      },
      "api_stage2":{
        "api_f_count":46,
        "api_f_lostcount":0,
        "api_e_count":0,
        "api_e_lostcount":0
      },
      "api_stage3":{
        "api_frai_flag":[-1,0,0,0,0,0,0],
        "api_erai_flag":[-1,0,0,1,0,0,0],
        "api_fbak_flag":[-1,0,0,0,0,0,0],
        "api_ebak_flag":[-1,0,0,0,0,1,0],
        "api_fcl_flag":[-1,0,0,0,0,0,0],
        "api_ecl_flag":[-1,0,0,0,0,0,0],
        "api_fdam":[-1,0,0,0,0,0,0],
        "api_edam":[-1,0,0,25,0,0,0]
      }
    },
    "api_support_flag":0,
    "api_support_info":null,
    "api_opening_flag":0,
    "api_opening_atack":null,
    "api_hourai_flag":[1,1,0,0],
    "api_hougeki1":{
      "api_at_list":[-1,1,7,6,8,4,3,5,-1,-1,-1,-1,-1],
      "api_df_list":[-1,11,6,10,2,8,8,7,-1,-1,-1,-1,-1],
      "api_si_list":[-1,8,505,7,505,6,6,4,-1,-1,-1,-1,-1],
      "api_cl_list":[-1,1,2,1,1,1,1,1,-1,-1,-1,-1,-1],
      "api_damage":[-1,85,2,61,16,15,5,5,0,0,0,0,0]
    },
    "api_hougeki2":{
      "api_at_list":[-1,1,8,3,4,5,6,-1,-1,-1,-1,-1,-1],
      "api_df_list":[-1,7,2,8,8,8,8,-1,-1,-1,-1,-1,-1],
      "api_si_list":[-1,12,505,6,6,4,11,-1,-1,-1,-1,-1,-1],
      "api_cl_list":[-1,1,0,1,1,1,2,-1,-1,-1,-1,-1,-1],
      "api_damage":[-1,66,0,4,8,2,69,0,0,0,0,0,0]
    },
    "api_hougeki3":null,
    "api_raigeki":null
  }
}

戦闘開始のAPIを呼び出すと、いきなり戦闘結果が返ってきます。api_hougeki1 と api_hougeki2 のあたりがそれですね。サーバーにはユーザーの艦娘のデータが保持されているので、鎮守府サーバーで戦闘の計算を出して返してきます。なので、戦闘をしてズル…はできないと思います。api_hougeki1 などの結果で、クライアントの Flash でアニメーションをしています。ということは、このあたりのデータを解析すれば、戦闘シーンは復元可能ってことです。

戦闘結果

svdata={
  "api_result":1,
  "api_result_msg":"成功",
  "api_data":{
    "api_ship_id":[-1,509,509,502,502,502,-1],
    "api_win_rank":"S",
    "api_get_exp":60,
    "api_mvp":1,
    "api_member_lv":24,
    "api_member_exp":29431,
    "api_get_base_exp":120,
    "api_get_ship_exp":[-1,432,144,144,144,144,144],
    "api_get_exp_lvup":[[69933,70300,74100],[2471,2800],[2574,2800],[8773,9100],[9330,10500],[12372,13600]],
    "api_dests":5,
    "api_destsf":1,
    "api_lost_flag":[-1,0,0,0,0,0,0],
    "api_quest_name":"カムラン半島",
    "api_quest_level":3,
    "api_enemy_info":{
      "api_level":"",
      "api_rank":"",
      "api_deck_name":"敵前衛部隊"
    },
    "api_first_clear":0,
    "api_get_flag":[0,1,0],
    "api_get_ship":{
      "api_ship_id":32,
      "api_ship_type":"駆逐艦",
      "api_ship_name":"初雪",
      "api_ship_getmes":"初雪……です……よろしく。"
    },
    "api_get_eventflag":0
  }
}

戦闘のアニメーションが終わったら、戦闘結果≒経験値を取得します。この計算も既に鎮守府サーバーで行った結果を返してきて、結果のアニメーションを出します。新しい艦娘が出て来たときには、この JSON に書いてあります。ランクとか経験値が書いてあるので、先の戦闘前の戦闘結果(ってややこしい)と、経験値の結果をあわせると、自分の艦娘の戦歴が作成できます。

多分、サーバーのほうでは、この手の履歴は保持ってないと思うんですよね。なので、いつ、どんな風に戦闘を勝ち抜いてきたのか、という戦歴は、この方法でしか取れないと思います。

■敷波復活

そんな訳で、この通信キャプチャを遣っている間に「敷波さん」をGetッ!!! 英霊により復活であります。

image

まだ、Get したばっかりなので、レベル1ですが、ええ、「ブラ鎮」≒「鎮守府をぶらぶら歩くこと」(銀ぶらと同じですねッ!!! 決して、ブラック鎮守府ではありませぬー)して遠征に出れる位までには御育て致しましょう。

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

 

カテゴリー: 艦これ | Fiddlerを使って艦これのバトルJSONを解析(敷波復活編) はコメントを受け付けていません

Fiddlerを使って艦これの戦闘シーンをトラップ(敷波撃沈編)

FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦) – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5050

の続きで、昨日の晩3時間ぐらいやってました。メモ的にやったことを書くと、

  • IE10 の開発ツールを使って、サーバーアクセスをロギング
  • Fiddler を使ってロギング
  • FiddlerCore を使って自作ツールでロギング
  • Network Monitor を使ってロギング

って感じです。Fiddler自体は、「実践Fiddler」英語版をPDFで買ってチェック。

目的は、戦闘シーンを時系列でキャプチャできないかな?と思ったところです。艦娘の獲得シーンの画面キャプチャもそうなのですが、それぞれの戦闘シーンを記録しておくと、なんとなく感情移入がしやすいというか、ボードゲームの海戦シミュレーションをやったことがある方(って何時の話か?)は分かると思いますが、記録から映像が浮かぶってやつです。いくつかハッキングもどきもできそうな感じ(艦娘の画像取得とか)ですが、それはまた別の話(注意、悪用しないように)。

戦闘シーンをIEの開発ツールで「ネットワーク キャプチャ」をするとこんな風に取れます。battle で始まって、*.swf が艦娘の画像で、*.mp3 が艦娘の音声、最後に battleresult で戦闘結果がでます。battle と battleresult は JSON なので、艦船情報と戦闘の結果(HPとか大破とか)が取れそうです。リアルタイムに戦闘シーンが取れると思ったのですが…

image

で、これを fiddlerCore でキャプチャすれば言い訳ですから、IEのFiddlerで試してみます。

image

これを見るとわかるのですが、battle と battleresult の間がほとんど通信していませよね。あれ?変だなと思って IE のほうを見れば、ステータスが 304 な訳です。なるほど、HTTPステータス・コード – CyberLibrarian を見ればわかる通り、自前のキャシュを当てにせよ、ってわけですね。で、ここまで知っていたので、じゃあ、Fiddler って 304 を無視するんですかね?と思って調べていったのが私の間違いです。

実際、Fiddler には 304 を無視するカスタムルールがついているのですが、良く分からんけど、google への 304 はキャプチャできているけど、艦これの 304 はキャプチャできない。謎だー、ってことで、あれこれと fiddlerCore の CONFIG を探したりあれこれと調べました。

image

調べたおかげで、fiddler を使いこなせるかな、ぐらいにはなったのですが、まあ目的は「艦これの戦闘シーンのキャプチャ」なので、さて、どうするかというところ。

代案として、「IE でキャッシュを効かない」ようにして、毎回取るようにすれば、常に 200 になるから大丈夫とか、送信するときのヘッダを no-cache にしてしまえば…という誘惑もあるのですが、それはそれでサーバーに負担を掛けるし、第一毎度サーバーに取りに行ったのではスムースな戦闘シーンがダメになりそうですよね。

image

ちなみに、IE のオプションでキャッシュを使わないようにして試したのですが、Flash の場合は別ものみたいです。この「自動的に確認する」が曲者で、どのくらいの時間でサーバーに問い合わせをするのかが微妙なのです…というのに気付いたのは、実は後からで、ここで私が思い込んでいたのは、

  • 304 なのだから、毎度サーバーに If-Modified-Since で問い合わせをしているのだろう。

と想像したのが間違い。あれこれ2時間ほど network monitor を使って出た結論は、

  • IE の場合、If-Modified-Since を付けていても「自動的に確認する」にしておくと、時間内であれば IE 内でしれっと 304 を返す。

ってことです。詳細な動きは Fiddler PowerToy – 第 2 部: HTTP パフォーマンス あたりに書いてあります。クライアントアプリで Web API を使う時に高速化できるテクニック(逆に、最新データを取得するときに使うテクニック)としては常套手段みたいです。

そんな訳で、リアルタイムに戦闘シーンは取れなそうですね。IEを適当にフックすれば、サーバー問い合わせをしない 304 も取れそうな気がするのですが、ちょっとそれは大袈裟だし。どうせならば、ストア版のIEに艦これを出して、スナップ表示でリアルタイム実況なるものを考えていたのですが、ちょっと無理っぽい。バトル結果と艦娘一覧ぐらいが無難ですかね。

そんな訳で、出撃を何度も繰り返して経験値を貯めつつ、戦闘ログを取っていたわけで…駆逐艦敷波の憂き目に orz うっかり、大破の後、継続して出撃しておりました。

Amazon.co.jp: 聯合艦隊軍艦銘銘伝―全860余隻の栄光と悲劇: 片桐 大自: 本 によれば、名前は「万葉集」巻十一の「うぢ川のせぜのしきなみしくしくに」から。最後は海南東方において、米潜水艦「グローラー」の雷撃により撃沈、だそうです。敷波 (吹雪型駆逐艦) – Wikipedia もあわせて、無駄な知識をため込むのOKかと。

image

英霊として復活すべく、現在、鎮守府海域を探索中…。

カテゴリー: 開発 | Fiddlerを使って艦これの戦闘シーンをトラップ(敷波撃沈編) はコメントを受け付けていません

FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦)

まあ、端的に言えば「艦これ」 http://www.dmm.com/netgame/feature/kancolle.html なのですが、先日「艦これのAPIがLTに」ってのを見つけて、そのあと自前で IE を使って調べてみました。で、単純な JSON と Flash の圧縮 SWF ファイルになっているので、解析は楽そう。実際公開当時(6月頃)から色々解析はやられているみたいで、マクロとか諸々あるのですが、まぁ、それはさておき。

艦これ 司令部室
http://nozomi.arege.jp/KanHQ/

20130827_01

というので、FiddlerCore というのを知りました。Fiddler 自体、Network monitor の後継なのかな?程度の知識しかなくて、昔は winsock をトラップするには特殊なDLLを入れないといけなくて(それでも DLL を入れて組めばなんとかなったわけですが)、かなり躊躇していたのですが、どうやら Fiddler にはコア部分だけをアプリで使えるように FiddlerCore ってのがあるんですね。なるほど。

# F# で JSON のパーサーが作ってあるのはまた後日に。

Fiddler – The Free Web Debugging Proxy by Telerik
http://fiddler2.com/
FiddlerCore – Fiddler Proxy Engine for your .NET Applications
http://fiddler2.com/fiddlercore

ネットワークモニタとして使う場合は、Fiddler をアプリとしてインストールします。詳細は、↓なんかを参考いすると色々でてきます。

実はFiddlerがすごすぎたので、機能まとめ紹介 – digital matter
http://blog.loadlimits.info/2009/09/%E5%AE%9F%E3%81%AFfiddler%E3%81%8C%E3%81%99%E3%81%94%E3%81%99%E3%81%8E%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E6%A9%9F%E8%83%BD%E3%81%BE%E3%81%A8%E3%82%81%E7%B4%B9%E4%BB%8B/

それはそれでWEB開発のテストには便利なのですが、もうちょっと突っ込んでアプリに組み込んでみたいと思っていたわけです。普通にプロキシを使えばそれでいいのですが、他アプリのネットワークも覗いてみたいですね、という感じで。

Fiddlercore Demo – Fiddler
http://fiddler.wikidot.com/fiddlercore-demo

に組み込んだときのテストコードがあります。これだとちと、ややこしいのでコメントやらイベントの位置を直したのが以下です。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        Fiddler.FiddlerApplication.OnNotification += FiddlerApplication_OnNotification;
        Fiddler.FiddlerApplication.Log.OnLogString += Log_OnLogString;
        Fiddler.FiddlerApplication.BeforeRequest += FiddlerApplication_BeforeRequest;
        Fiddler.FiddlerApplication.BeforeResponse += FiddlerApplication_BeforeResponse;
        Fiddler.FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;
        Fiddler.CONFIG.IgnoreServerCertErrors = false;
    }

    void FiddlerApplication_AfterSessionComplete(Fiddler.Session oSession)
    {
        Console.WriteLine("Finished session:t" + oSession.fullUrl);
    }

    void FiddlerApplication_BeforeResponse(Fiddler.Session oSession)
    {
        Debug.WriteLine("{0}:HTTP {1} for {2}", oSession.id, oSession.responseCode, oSession.fullUrl);
    }

    void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
    {
        Debug.WriteLine("Before request for:t" + oSession.fullUrl);
        oSession.bBufferResponse = true;
    }

    void FiddlerApplication_OnNotification(object sender, Fiddler.NotificationEventArgs e)
    {
        Debug.WriteLine("** NotifyUser: " + e.NotifyString);
    }
    void Log_OnLogString(object sender, Fiddler.LogEventArgs e)
    {
        Debug.WriteLine("** LogString: " + e.LogString);
    }

    /// <summary>
    /// キャプチャ開始
    /// </summary>
    /// <param name=&quot;sender&quot;></param>
    /// <param name=&quot;e&quot;></param>
    private void button1_Click(object sender, EventArgs e)
    {
        Fiddler.FiddlerApplication.Startup(8877, true, true);

    }

    /// <summary>
    /// キャプチャ終了
    /// </summary>
    /// <param name=&quot;sender&quot;></param>
    /// <param name=&quot;e&quot;></param>
    private void button2_Click(object sender, EventArgs e)
    {
        Debug.WriteLine(&quot;Shutting down...&quot;);
        Fiddler.FiddlerApplication.Shutdown();
    }
}

実行するとこんな感じになります。

Before request for:	http://t.jp.msn.com/
** LogString: Fiddler.Network.AutoProxy> AutoProxy Detection failed.
** LogString: AutoProxy failed. Disabling for this network.
1:HTTP 200 for http://t.jp.msn.com/
Finished session:	http://t.jp.msn.com/
Before request for:	http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
Before request for:	http://c.msn.com/c.gif?udc=true&rid=FE68A2FD2C6040C69F537FF40F542212&rnd=1377519905169&rf=&tp=http%3A%2F%2Ft.jp.msn.com%2F&scr=1920x1080&di=258&pi=9961&ps=26623&lng=ja-jp
Before request for:	http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
2:HTTP 200 for http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
4:HTTP 204 for http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
Finished session:	http://udc.msn.com/c.gif?evt=impr&js=1&rid=FE68A2FD2C6040C69F537FF40F542212&cts=1377519905144&clid=13849A992C36614418429E192836616E&rf=&cu=http%3A%2F%2Ft.jp.msn.com%2F&bh=776&bw=1264&scr=1920x1080&sd=24&dv.Title1=MSN+Japan&di=258&mk=ja-jp&pn=JP_Homepage&su=http%253A%252F%252Ft.jp.msn.com%252F&pid=250048820&pageid=250048820&mv=15&cv.product=tmx&dv.ContnTp=HomePage&cv.partner=&cv.publcat=
Finished session:	http://b.scorecardresearch.com/b?c1=2&c2=3000001&rn=1377519905169&c7=http%3A%2F%2Ft.jp.msn.com%2F&c8=MSN+Japan&c9=
Before request for:	http://kaw.stb01.s-msn.com/i/50/1918772e1d6c3e65af249dfb71f252/_h145_w300_m6_utrue_otrue_lfalse.jpg
Before request for:	http://kaw.stb01.s-msn.com/i/43/b1db42c168f3442eea6c660e454/_h145_w145_m6_utrue_otrue_lfalse.jpg
Before request for:	http://kaw.stb01.s-msn.com/i/53/cadac0dbcd456cef11aec35e1bbe17/_h145_w145_m6_utrue_otrue_lfalse.jpg

手順としては、

  1. トラップするイベントを割り付けておく。
  2. Startup メソッドでプロキシ開始。
  3. データ自体は、AfterSessionComplete イベントの Session オブジェクトで取得。
  4. 終わりは Shutdown を呼び出す。

という流れです。
コードを見るとわかるのですが、Fiddler.FiddlerApplication クラスの static メソッドになっています。つまりは、OS にひとつしかない訳ですね。どうやら、wininet をトラップしているらしく、os 上で動くネットワークを完全にプロキシ

…はしていませんね。wiinet 経由のみ。自前 winsock やっていると駄目? 一応、うちのブラウザIE10でもFirefoxの最新では大丈夫でした。それで十分用途は足りるので。

■フィルタをどうするのか?

ブラウザを複数開いていると(タブでも同じ)、あちこちでアクセスするデータを拾ってきてしまいます。なので、目的のサイトへのアクセスだけをトラップしたい場合は、、AfterSessionComplete イベントの oSession.fullUrl プロパティで判別すると思います。このあたり、いま起動している艦これだけを対象にしたい場合は、横須賀サーバーのIPだけフィルタリングするとか、そういう工夫が必要です。いや、ブラウザのトラップしたいだけなれば、WebBrowser を貼り付けてプロキシ経由にしてしまえば良いのですが。ええ、プロキシに関してはそのうち試してみましょう。

■データをどうやって取得するのか?

レスポンス自体は、oSession.ResponseBody で byte[] で取得するか、oSession.GetResponseBodyAsString() で文字列として取得します。テキストなのかバイナリなのかは、oSession.oResponse.MIMEType でチェックすれば OK ですね。

具体的に動かすのは、横須賀サーバーの復旧待ちということで。

カテゴリー: C# | FiddlerCoreを使ってブラウザアプリをトラップする(前哨戦) はコメントを受け付けていません

ソフトウェア開発委託基本契約書の不備の感想戦

ソフトウェア開発委託基本契約書の不備により、未払い200万円の被害を受ける – Moonmile Solutions Blog
未払金の続きは内容証明で – Moonmile Solutions Blog
未払金の結末 – Moonmile Solutions Blog

のまとめです。

■ソフトウェア開発委託基本契約書の見直し

まずは、未払いなりのトラブルが発生しないように、ソフトウェア開発委託基本契約書の見直しをします。今回の落ち度は、善意に基づき「トラブルが発生した場合の損害賠償の上限を、委託金とする」という条件を入れたのですが、これを外します。ただし、条件がない場合には青天井になって、相手の悪意により(瑕疵とか難癖とかがあるので)こちらの被害が甚大になってしまうので、ある程度の上限が必要です。

  • 支払いの遅延に関しては、年18%とする。
  • 支払いを遅延した場合は、委託金の50%を損害賠償金として支払う。

金額がもっと多い場合(1000万円とか)は、別途損害金の見直しは必要でしょう。個別契約書で変更するのがよいと思います。支払の遅延による年利は銀行からの借入の利率よりも高くしておきます。そうしないと、簡単に遅延されてしまいますからね。あと、損害賠償金を明記しておきます。これは、弁護士費用、裁判費用も込みで上乗せしておくという形ですね。ただし、自転車操業的にお金をまわしている場合は、手元のキャッシュが危うくなるので、この損害賠償金では危ないパターンがあります。もともと、遅延自体がリスクなので、リスク管理的に抑制効果として条項を加えておきます。

逆に、当方の瑕疵によるプロジェクト遅延に対しても損害賠償金を支払う義務が生じます。これは、プロジェクトの遅延をしないように努めること、遅延しそうになったら事前に相手に通知すること(損害賠償金を請求されないように)を行い、事前の合意を取ります。たいていの場合、お客マター(要件定義の遅れとか、要求の肥大化、お客の隠し玉などなど)が多いので、これでクリアできるでしょう。まあ、外注している場合は「できなかった」リスクもあるので、会社としてはフォローすべきかも。フリーランスでやる限りでは、これは大丈夫かと。

■相手の状況を調べる

ホームページがあれば、それで調べるし、社長の名前があれば必ず google で検索をします。あと、2チャンネルで噂になった詐欺師ではないかを調べます。

ただし、与信管理が必要なので、

を事前にやっておきます。帝国データバンクと東京商工リサーチは5,000円ぐらいで済みます。資本金と主要株主、取締役、従業員数が出るので、これを相手の営業なり担当なりの言葉とすり合わせればOKです。このあたりの方法は、孫子の兵法に詳しいです。

■実際に遅延が起こったら(難癖による支払遅延も含む)

で、実際にお客が支払わないよ、という自体が起こったときにはどうするかというと、

今回は、金額が比較的大きいことと、私が個人的に弁護士と知り合いということもあって、弁護士費用を出すことにしましたが(まあ、それ以外の方法を知らなかったというのもあるのですが)、一応、上記2つの方法があります。

下請法の場合は、勧告扱いで実際の取り立てはどうなのかわからないのですが、ホームページに会社名が晒されるし、信用にキズが付くので、支払ってくれるはずです。あと、資本金がそれなりに多ければ100万程度なら大丈夫でしょう。まあ、大抵は会社間ってことになりますね。

支払督促の場合は、裁判所が相手の会社の給与差押えなどをしてくれます。継続して取引がある会社だと困るんでしょうが、未払いが発生するような会社と取引は続けたくないわけで(下請メーカーだと別なんでしょうが)、フリーランスならばもっと優良なお客を掴みましょう(自戒をこめて)。裁判所が強制執行をしてくれるので楽です。そのための税金ですからね。支払督促状自体は、裁判所にPDFがあるし、自分が書ける範囲です。裁判所に出向く必要もありません(郵送でOKだそうです)。値段は5,000円位(通常の訴訟の半額)なので、10万円規模ならば使ってもいいかも。

まあ、どちらにせよ、きっちりと「契約書」が残っていないと駄目なので、メールベースなりPDFなりで、金額が書いてあるものが必要です。これは忘れずに。

あと、商取引的に「手形を切って貰う」という方法もあります。手形を使うと、相手の当座預金からの引き落としができるし、手形自体を信用金庫などに売ることもでるし、それなりに融通が利くのですが、IT業界で手形で取引しているところはないですよね?小切手とか手形を使うと、未払い=即銀行の焦げ付きになるわけで、大抵は期限までに支払ってくれるはずですが、簿記を勉強すると手形の未払金の例題が多いので、まあこのパターンも支払ってもらえないパターン(相手が倒産するパターンですが)が多いのかなと。モノ(在庫)が関わってくる工場とか流通とかはそのパターンが多いかも。

■弁護士費用はどのくらいなの?

弁護士にもよるのでしょうが、経験上、

  • 手付金が10万円程度
  • 日当が3万位(これは法律で決まっている)+諸経費
  • 成功報酬が10%ぐらい(これは弁護士によって異なる)

な感じでしょうか。弁護士も「仕事」でやっているので、それなりの金額が必要です。少額の取引の場合には弁護士費用だけで赤字になってしまうので、頼むことはできなでしょうが。逆に言えば、15万円程度で弁護士を雇うことができるってことです。悪徳弁護士もいるので注意は必要ですが(そういう場合には、弁護士会に連絡すれば、弁護士資格を剥奪することも可能です)、高学歴の方をこき使うというのも面白いかと。まあ、みなさん「先生」つけて余分のですが、私は「さん」づけです。つーか、「先生」ってのは蔑称ですから。

それぞれの地方には弁護士会があるので、そこに連絡するのもありかと。あと、弁護士費用は分割にしてくれるパターンも多いので、最初は相談だけというのもありです。

■泣き寝入りしない

先のブログのコメントやメールなどで頂いたのですが、結構、未払いの例は多いようです。ひどいですよね。私の場合、2,3日寝込んでしまったのは、同時に例の8.1事件があった訳でまた別件も含めてなので(実質的には、トリプルパンチを喰らった状態で、なにがなにやら)ちょっと特殊な環境ではありますが、「泣き寝入り」ないことが重要です。

ビジネス上「はじめてのお客さん」というのは避けられません。新規顧客開拓は必要だし、引き合いでビジネスをやるのは、交渉術のひとつですよね。なので、ガードを緩く見せて、実はガードを固く保つ(あるいは、ノーガード戦法?死にそうですがw)のが良いかと。

なので、フリーランスの場合トラブルに巻き込まれるのは確率的なものです。ブラックな会社に就職しているのと違うので(いや、法務的にトラブルってのもあるし、ブラックじゃなくてもトラブルはあるんですが)、お客を選ぶというのも重要ですよね。逆に「お客に選ばせる」という戦法もあります。

私としては、今回は「泣き寝入り」はしたくなかったので「いい加減にしろ」状態で、あれこれと手を打ってみました。探してみれば、それなりに手はあるわけで、最初は全額諦めなければいけない、という話を何度も聞かされたのですが、結果的には全額支払わせたわけですよね。まあ、偶然的な要素と将棋的な手法(意図的に使いました)が功を奏したと思う訳ですが、逆に言えば、それなりの手を使えば「泣き寝入り」をする必要はありません。「泣き寝入り」を勧める意見を聞く必要もありません。邪魔です。ええ、自分が「正しいことをやっている」のであれば、被害を蒙って泣き寝入りすることはあり得ませんってことです。まあ、そのあたりは「正義」かどうかは別として、高い税金を払っていることだし、役人に動いてもらいましょう、ってことで。

カテゴリー: 仕事 | 2件のコメント

未払金の結末

ソフトウェア開発委託基本契約書の不備により、未払い200万円の被害を受ける – Moonmile Solutions Blog
未払金の続きは内容証明で – Moonmile Solutions Blog

の続きです。

結論から言うと、未払い金250万円を全額返金…というか、即金で支払って貰いました。

先日の内容証明で、分割案がされていたので突っぱねました。これを突っぱねると、先方の会社が倒産するリスクがあるので、未払金が回収できなくなる恐れがあるのですが「200万円程度の金額で、倒産するぐらいであれば、分割にしても支払が滞る可能性が高い」と踏んだのと、「先方の会社が1億円以上の借金を抱えているので、メインバンクとしては、倒産させない方法を取り、200万程度の少額?であれば追加融資せざるを得ないだろう」という私の判断です。まあ、運が良かった(いやいや、未払いが発生する時点で運が悪い)のかもしれないし、なんらかの偶然的な要素があったのかもしれないのですが、ひとまず戦術的には勝利に至った、というところですね。戦略的には、今後の防御策を練ることができた、というのもありますが。弁護士費用分ぐらいの痛手と、去年からの未払いの痛みと、この件について押してしまった本プロジェクトの後始末(なので8月いっぱいが忙しい)に追われるという点で、やっぱり未払いのような経験はしたくないものです。

image

先の分割案から一変して、一括支払いの案が来ました。想像するに、メインバンクの借入が通ったと思われます(まあ、別途、個人的な借金かもしれませんが。あるいは、他の取引会社を未払いにするとか)。合計が150万円なのは、その前に100万円を支払って貰っているからです。

ちなみに駆け引き的な意味で、こちらとしては年末までの分割ならばOK、との回答を用意していました。が、それはこの時点で先方に伝えていません。情報を与える必要はないですからね。月20万円という支払にしたときに、支払能力があるかどうか?(個人としての支払能力を超える金額なので)というのが分岐点です。普通の会社ならば、借入をするハズ。

で、実際に来たのは一括支払案なので「支払う意思あり」と考えられ、これはこれでOKなのですが、もうひと押ししておきます。過怠約款(かたいやっかん)のところですね。過怠約款 とは – コトバンク を見ると「旧民法用語」ということで、単純にいえば遅延したときの賠償金の話です。今回の未払いの件は、そもそもがこの「過怠約款」のところが緩い(損害賠償の条件を請負金額とする、遅延金が書いてないなど)のが問題なので、ここを本来の契約のスタイルに戻します。和解案として遅延損害金が10%ということになっていますが、そもそもが貸し付ける金額ではないので、一般的な貸付の利率 18% にすることと、遅延したときの損害賠償の金額(今回は、「契約金額の半額」ということにしました)を明記します。

このあたり、当方の弁護士とも相談しました。「法的に正しいものになるかわからない」のではありますが、私としては後に契約書を作るときの前例として欲しかったので、和解案を修正して貰うように頼みました。

image

そんな訳で、上記のような合意書に変更して、振込みが完了しています。実際には弁護士の口座に一度振り込んで貰って、弁護士費用を差し引いたうえで、私の口座に振り込みなおして貰うという手順です。これは、私のほうでいちいち口座を確認しないといけないのは面倒/煩雑だからです。期日に支払ったかどうかのチェックは弁護士から直接できたほうがいいですからね。

そんな訳で、決着がついたので、次に感想戦をやります。私の今後のためと記録を残しておくという意味で。

カテゴリー: 仕事 | 未払金の結末 はコメントを受け付けていません

Surface RTでモバイルLinux環境を作る

モバイル環境を作るならば、ノートPCにLinuxを入れればいいじゃん(あるいは、Windows の VMWare 上に Linux を入れればOK)、ってことなのですが、

から、ふと思ったネタ企画です。うまく動けば、9月の.NETラボ勉強会のLTで話しましょう。手元にある、Surface RT と Raspberry PI というミニミニ linux を使います。Raspberry pi 自体は、Raspbarry PI が届いたよ – Moonmile Solutions Blog なところで買った「船便版」の初期購入品です。最近、日経Linuxあたり?で特集になったらしく、いくつかの解説本も出ています。今では、日本でも買いやすくなったので、お試し(3,000円ぐらい)としては面白いおもちゃです。

で、結論から言えば、こんな感じで、自給自足型のモバイル環境が作れました。

  • Raspberry PI に xrdp を入れて、リモートデスクトップ環境を作る。
  • Raspberry PI に USB 型の無線LANを差し込み、設定する。
  • Surface RT から Rassberry PI にリモートデスクトップする
  • Raspberry PI は、Surface RT の USB から給電する

ってことで「無線LANの環境があれば」、モバイル環境が構築できます。本当にモバイルにするには、Pockert WiFi などのルーター機能が必要になるのです(実際、これを使うし)、完全な独立型とは言えませんが、まあ、いいでしょう。それなりに持ち運びができるし。

■Raspberry PI の OS を最新にする

いろいろやって、結果的に OS を最新にしました。Raspberry Pi でOSのインストールと初期設定を行う | よもやま雑記帳

初期の Raspberry PI を買った時の Linux は、デスクトップの操作とが違うし、手元の無線LAN(GW-USMicroNのモジュールが動かなかったり)して、かなりはまりました。OS 自体は、Downloads | Raspberry Pi にある Raspbian “wheezy” を使っています。zip を解凍して、2GB 以上ある SD カードに焼き付けます。適当な SD micro に焼いてカードを差し込めば OK です。

私の環境では、先のURLにある DD for Windows がうまく動かかなかった(書き込み先のドライブが選択できない状態)ので、Win32 Disk Imager | Free Development software downloads at SourceForge.net を使いました。

■Raspberry PI 側の設定

Windows からの接続は、リモートデスクトップ xrdp をインストールします。VNC でもいいのですが Surface RT には VNC クライアントをインストールできないので、リモートデスクトップを使います。Raspberry Piで遊ぼう [No.26:リモートデスクトップ接続をやってみよう]:アシマネのIT奮闘日記:So-netブログ を参考にすると、あっという間に「リモートデスクトップ」を使って接続がでるようになります。最初は、有線LANで試してみてください。無線LAN だと、以下に記しますが結構不安定なので。

USB 型の無線 LAN はできるだけ新しいもののほうがよさそうです。手元にあった昔の PLANEX GW-USMicroN を使ったのですが、結構手間がかかりました。更に 802.11n でつながるはずなのですが、なぜか 802.11g のほうしか認識できません。無線ルーターのほうがおかしいのかもしれないのですが…こっちは、Surface RT とか他のノートPCも繋がっているので。まあ、当時は Draft の規格だったから仕方がないのです。

RaspberryPiでコンパイルとかせずにWifiドングルを使う(US-GWMicroNとか、ralinkの) – midohajiフォト
RaspberryPi奮闘列伝:無線LANアダプタ

あたりを参考にして、rt2800usb のモジュールを手作業で入れていきます。バッファローあたりの無線LANを使うとすんなりと入るらしいので、それを使った方がよいでしょう。どっちにせよ、他の方が「実績」をアップしているので、それを参考にしたほうが早いです。

■Surface RT 側の設定

ストアアプリのリモートデスクトップアプリをインストールします。Windows ストア の Windows 用 リモート デスクトップ アプリ からインストールします。手元の Surface RT は、Windows 8 なのですが、多分 8.1 preview でも使えます。raspberry pi の IP を DHCP にしてしまうと、IP が変わってややこしいので、固定IPがお勧めなのですが、設定がややこしいので現状 DHCP を使っています。個人で遊ぶ分には、大抵は同じ IP に振られるので、それはそれで良いかなと。ただし、raspberry pi にLAN接続しないと(有線、無線を問わず)IPが分からないとジレンマに陥るので、運用的には固定IPが望ましいですね。基本、ディスプレイとキーボードが使わない体制にしたいものですから。

■動いたか?

ええと、動いたかどうかというと、冒頭の写真のように無事に動きました。Surface RT から無線LANを通じてリモートデスクトップ接続ができます。が、運用上、いくつか問題があってですね…というか、致命的な問題があります(苦笑)。

  • Raspberry PI 側で、ソフトウェアキーボードが出せないので、キーが打てない。
    → 何かインストールすればいいんでしょうが、現状、キーが打てません。
  • 無線LANだと帯域が足りないらしく、まともに画面が動きません。
    → かろうじて、ダブルクリックができるぐらいです。
  • USB給電の電圧か電流が落ちると、Raspberry PI のLANがつながらなくなる。
    → なので、一切接続ができなくなります。

この給電の電圧には悩まされました。普通に使っていると、いきなりリモートデスクトップやtera term(これはデスクトップPCから接続)が、切断されます。デスクトップ PC につながっている、ハブ USB につないでも、Raspberry PI は普通に動くので大丈夫かと思っていたのですが、無線LAN は電圧の変化に敏感らしく早めに落ちてしまうようです。これが Linux の仕様なのか、Raspberry PI の制限なのかは分かりません。ためしに、AC電源から直接USB経由で給電をしてやると、無線LANは切れませんでした。最初、ドライバーが壊れたのか?SDカードが壊れたのか?と、再度 OS のインストールからやり直して、2時間ほどつぶしてしまったのですが、どうもUSB給電の電圧っぽいです。

なので、Surface RT のバッテリーが少ない状態になると、この現象に陥ってしまいかなと。Surface RTに電源をつなぎながら使うと「モバイル」とは言えないし、うーむ、ここは悩みどころですね。まあ、PLANEX の古い製品を使っているので最近のだともう少し必要な消費電力は低いかもしれません。

ソフトウェアキーボードの件は、どうしようかな、と悩み中です。リモートデスクトップの帯域と合わせて、ちょっと思案中。

カテゴリー: windows 8 | Surface RTでモバイルLinux環境を作る はコメントを受け付けていません

7/27(土)に.NETラボ勉強会で発表します

荒削りなところもありますが、「バウハウスとフラットデザイン」というタイトルで、.NETラボ勉強会で発表します。Windows 8 はモダンデザインになって、8.1 も同じ、さらに iOS 7 がフラットデザインで、さまざまな WEB サイトがフラットデザインになってしまう中で、どのように「フラットデザイン」を捉えるか?って話ですね。

 

最初は、Microsoft のおひざ元で dis ろうか、という主旨だったのですが(苦笑)、意外とまともなプレゼンになる予定です。場所とか時間とかは、.NETラボ 勉強会 2013年07月 : .NET Lab を参照してください。

カテゴリー: 勉強会 | 7/27(土)に.NETラボ勉強会で発表します はコメントを受け付けていません

未払金の続きは内容証明で

ソフトウェア開発委託基本契約書の不備により、未払い200万円の被害を受ける – Moonmile Solutions Blog の続きです。

弁護士を通じて内容証明を送る、という段階になっています。3週間前に100万円を持ってきましたが半分に足りません(実は全体で250万円なのですよ)。ゼロよりはマシなのですが、それはマシなだけで、半分にも足りません。なので、残金150万円を請求します。

image

という回答が来ていますが、

  • 支払の遅延自体は、先方の一方的な都合であること(貸付にする意思はない)
  • 商習慣の遅延損害金6%では金利として低すぎ、実際の損害に全然足りないこと

を理由に突っぱねます。さて、どうなることやら。

カテゴリー: 仕事 | 未払金の続きは内容証明で はコメントを受け付けていません

小学三年生の夏休みの宿題を10日間で終わらせる計画

「夏休み 宿題」あたりで、小学1年生でもわかる7月中に夏休みの宿題を終わらせる方法 – Moonmile Solutions Blog にたどり着く方が多いみたいなので、今年の夏休みの計画編を書いておきます。

image

娘も小学三年生になったので、宿題も多くなっています。うちは共働きなので夏休みも学童に行くことになるのですが、せっかくの「夏休み」なのだから、他の子の夏休みと同じように勉強時間と遊びの時間を分けておきたい、と思ったのが目的です。まあ、プロジェクト管理(プロダクト管理じゃないよ)の基本でもありますが。

例によって、東京の小学校では夏休みが8月末ではありません。日数にして約30日、土日を除くと約20日になるので、丁度、会社務めの8時間×20日間=160時間勤務と同じになります。ええ、基本は「160時間勤務」ですからねッ!!!

■計画を立てる

さて、今回の夏休みの宿題は主に4種類あります。

  • 漢字スキル/ドリル を16ページ(160熟語)
  • 計算ドリルを40ページ(問題写し、答え合わせ込み)
  • 夏休みの生活表で、一言日記
  • 1行の読書感想を5冊以上

他に自由研究、自主課題の漢字200文字があるわけですが、最初はこの4つに焦点を絞ります。「全体のボリュームを把握する」のが大切です。

ざっと手順を書き下すと、

  1. 全体のボリュームを把握する。
  2. 幾日で夏休みの宿題を終えるのか決める。
  3. 全体のボリュームを、日数で単純に割る。
  4. 1日の宿題の量が、妥当かどうかを検討する。
  5. 難しい場合は、作業日数を増やす。

この手順は、子供単独では無理なので親が手伝います。特に「全体のボリュームを把握する」、「幾日で終えたいか決める」、「1日の宿題の量が可能かどうかを検討する」は、重要です。今回は、夏休みを有意義に過ごしたい(他の日は遊びに行くという意味で)ということで、10日間で終わらせる目標を立てました。これを20日間にしてもよいし、土日なしの30日間に分割しても構いません。要は、「夏休みの宿題を終える」という目標が達成できればよいのです。

この10日間の目標を達成するためには、次の日程が決まります。

  • 漢字スキルを1日16行(16熟語)やる
  • 計算ドリルを1日4ページやる
  • 一言日記は、土曜日にまとめてやる(まとめてもOK)
  • 読書感想文は、先に本を読んでから後で書く

ということにしました。

これを学童に行っている午前中にやります。時々、サマースクール(補修)やプールがあるので、前後することはあるのですが、1日のうちに済ませます。日中にできなかった場合は、家に帰ったときに残りをやります。

■実施する

実践のほうは、小学1年生でもわかる7月中に夏休みの宿題を終わらせる方法 – Moonmile Solutions Blog にもあるのですが、

  • 最低限のノルマを守る(この場合は、漢字スキル16熟語、計算ドリル4ページ)
  • ノルマを超えて、先に進めるのは構わない。ただし、先に進めた分は、次の日のノルマに入れない。

という作業の仕方を守ります。CCPM の基本で「先に進めることによる、作業量の前倒しを許容する」ことになります。そうしないと、実際、(やむなく)ノルマがこなせなかったときの作業量減のところがリカバリーできませんからね。

今回は、作業の10日間を夏休みの最初にとりましたが、夏休みの最後の10日間でも構いません。当然、夏休みの宿題が終わらないリスクは高まりますが、先のような計画をきっちりと立てておくと、日のノルマが明確になるのと、ノルマの前倒しが可能になるので、さほど後ろにずれなくなります。子供によって(≒プロジェクトメンバーによって)遅れる実績がある場合には、適当なバッファ(土日とか、親が介入するとか)を取っておけばよいでしょう。

■漢字200字はどうするのか?

ってなわけで、漢字スキルと計算ドリルの量が多そうなので、漢字200字は保留です。前半の10日間で学校の夏休みの宿題が終われば、漢字200字の先取りをやってみましょう。

カテゴリー: プロジェクト管理, 雑談 | 小学三年生の夏休みの宿題を10日間で終わらせる計画 はコメントを受け付けていません

[WinRT] 独自プロトコルを使ってストアアプリ間で通信する

ってことで、ストアアプリ間で通信を行います。共有コントラクトを使うと相手先を選択しないといけないし、デスクトップアプリ経由(WCFサーバー経由)だとアプリのインストールが必要だし、というわけで、ひとまず、手軽なアプリ間通信は「プロトコル」を使えます。まあ、ワンクッションだけなんですけどね。双方向にプロトコルを設定しておけば、それなりに通信はできるかと。

■送信先のアプリ

ターゲットアプリでは、App.xaml.cs でプロトコルを受けます。OnActivated をオーバーライドして、種別がプロトコル ActivationKind.Protocol の時に処理をするという感じです。
ここでは、画面に表示させるために new Frame をしていますが、アプリ内部で処理する場合は、クラス変数にするのがよいかと。

protected override void OnActivated(IActivatedEventArgs args)
{
    if (args.Kind == ActivationKind.Protocol)
    {
        var ar = args as ProtocolActivatedEventArgs;
        var rootFrame = new Frame();
        rootFrame.Navigate(typeof(BasicPage));
        Window.Current.Content = rootFrame;
        BasicPage p = rootFrame.Content as BasicPage;
        p.UpdateMsg(ar.Uri);
    }
    Window.Current.Activate();
}

プロトコル自体は、マニフェストで設定します。

■送信元のアプリ

private void Button_Click(object sender, RoutedEventArgs e)
{
    string text = this.text1.Text;
    var ret = Windows.System.Launcher.LaunchUriAsync(new Uri(
        "mm-message://" + text));
}

独自に作った「mm-message://」プロトコルを使って、LaunchUriAsync メソッドで呼び出します。ここではテキストしか送っていませんが、ファイル名を送って受信側で処理すれば、ファイルや画像などを送ることも可能です。ファイルに関しては、マイドキュメントを使うとかマイピクチャを使うとかがあるので、まあ、ちょっと細工が必要ですが。

■試してみる

プロトコルなのでURLエンコードをしないと駄目なんですが、通常のアルファベットならばそのまま送ることもできます。

サンプルはこちら
http://sdrv.ms/15cIv1G

カテゴリー: C#, WinRT | [WinRT] 独自プロトコルを使ってストアアプリ間で通信する はコメントを受け付けていません