Visual Studio Coverage file to Emma converter

CodePlex now!
And 1.0.1.0 released!!

Visual Studio Coverage file to Emma converter : CodePlex


Visual Studio Coverage file to Emma converter.
Simple solution, can apply only one tool to five Visual Studio versions.
Fast multicore processing.

Included:

  • Command line executable.
  • MSBuild custom task.

Thank you choosing this tool, probably use with jenkins.
(I’m not jenkins professional ops, may not operate this tool…)

Require:
.NET Framework 4.5.1 Runtime environment.
Visual Studio 2005, 2008, 2010, 2012 and/or 2013 versions (Require code coverage option)

Setup:
1. Copy VSCoverageToEmma.exe, VSCoverageToEmma.dll to your tool folder.
2. Copy VS
folders (ex:VS2013) to your tool folder.
3. Copy your Visual Studio’s “Microsoft.VisualStudio.Coverage..dll”
(In %VSROOTFOLDER%Common7IDEPrivateAssemblies) into VS
folders.

Tool folder example:

  Tool
    +--- VSCoverageToEmma.exe
    +--- VSCoverageToEmma.Interfaces.dll
    +--- VSCoverageToEmma.Core.dll
    +--- VSCoverageToEmma.VS2005Converter.dll
    +--- VSCoverageToEmma.VS2008Converter.dll
    +--- VSCoverageToEmma.VS2010Converter.dll
    +--- VSCoverageToEmma.VS2012Converter.dll
    +--- VSCoverageToEmma.VS2013Converter.dll
    +--- VS2005
    |       +--- Microsoft.VisualStudio.Coverage.Analysis.dll (From Visual Studio 2005, if use)
    +--- VS2008
    |       +--- Microsoft.VisualStudio.Coverage.Analysis.dll (From Visual Studio 2008, if use)
    +--- VS2010
    |       +--- Microsoft.VisualStudio.Coverage.Analysis.dll (From Visual Studio 2010, if use)
    |       +--- Microsoft.VisualStudio.Coverage.Interop.dll  (From Visual Studio 2010, if use)
    |       +--- Microsoft.VisualStudio.Coverage.Symbols.dll  (From Visual Studio 2010, if use)
    +--- VS2012
    |       +--- Microsoft.VisualStudio.Coverage.Analysis.dll (From Visual Studio 2012, if use)
    |       +--- Microsoft.VisualStudio.Coverage.Interop.dll  (From Visual Studio 2012, if use)
    |       +--- Microsoft.VisualStudio.Coverage.Symbols.dll  (From Visual Studio 2012, if use)
    +--- VS2013
            +--- Microsoft.VisualStudio.Coverage.Analysis.dll (From Visual Studio 2013, if use)
            +--- Microsoft.VisualStudio.Coverage.Interop.dll  (From Visual Studio 2013, if use)
            +--- Microsoft.VisualStudio.Coverage.Symbols.dll  (From Visual Studio 2013, if use)

Command line usage (VS2013):

  C:TEMPVSCoverageToEmmaDebug>VSCoverageToEmma.exe VS2013 "C:TEMPCoverageTargetTestResults" "C:TEMPCoverageTargetbinDebug" "C:TEMPCoverageTargetbinDebug" "C:TEMPCoverageTargetTestResults"

If use VS2010/VS2012/VS2013 converter, automatically recursive search binary/symbol files in nested folders.

MSBuild usage:
Target assembly is “VSCoverageToEmma.Core.dll”, task name is “VSCoverageToEmma”.
ConverterName: required (ex: “VS2005”)
VSCoverageFolderPath: required (path)
BinariesFolderPath: optional (path)
SymbolsFolderPath: optional (path)
EmmaFolderPath: optional (path)
VSCoverageFiles: output (path list)
EmmaFiles: output (path list)
Methods: output (number)

MSBuild limitation: Tool execution failed in 64bit process. (VS Coverage library required 32bit mode)

Download from SkyDrive: VSCoverageToEmma-1.0.zip

Bar Windows 8.1 – BluetoothでGO!

Bar Windows 8 in 名古屋 with 8.1に登壇して、「BluetoothでGO!」というタイトルでセッションしてきました。

ご清聴ありがとうございました。プレゼンを置いておきます。
最後のデモで見せたコードはあまり整理されていません。反響があれば公開したいと思います。→ GitHubで公開しています。

BluetoothでGo!

次回も頑張ります (^^)

名古屋MS秋祭り – LINQソースでGO!

名古屋MS秋祭りにて登壇して、「LINQソースでGO!」というお題目でセッションをさせて頂きました。

詰め込み過ぎなのに時間が短すぎという結果で、大変分かりにくい解説になってしまったようで、またしても反省です m(_ _)m
参加者の皆様、ご静聴いただき、ありがとうございました。次回登壇の際には、これに懲りずに、宜しくお願いします。

ここにオリジナルプレゼンを置いておきます(アニメーションを使用しているので、オリジナルを見た方が良いです)。早すぎて理解不能だった場合の足しにしてください (^^;;

Windowsマーケットプレースで収益を上げる為に

Windows PhoneやXBOX アプリケーションを開発する際に、Microsoftのデベロッパーセンターに、デベロッパーアカウントを登録する必要があります。
(Windows 8 ストアアプリの場合は、ここです。この記事では、基本的にWindows Phoneの話を扱いますが、大枠では同じです)

デベロッパーアカウントの登録は、MSDNライセンス契約があれば、1年間は無料で登録可能です。それ以外は、年間登録料を支払う必要があります(その代わり、個々のアプリケーションの申請費用は不要です、多分何度でも)。

で、登録を行い、Windows Phoneの物理デバイスのアンロック(デベロッパーアカウントを使って、自由にアプリケーションのインストールとデバッグを可能にする)まで行えば、開発と公開の準備が整ったことになります(XBOXはやったことが無いので、詳しくは分かりません)。
実際にアプリケーションの申請を行うと、早く数時間?遅くて5日程度かかるようです。

ところで、ここまでの話は、無料のアプリケーションの公開と配布です。有料アプリケーション・アプリケーション内課金・広告を使用した収入を前提とするのであれば、Microsoftから収益を送金してもらう必要があります。ここでは、実際に手続きを行った際に気が付いた事を(雑多ですが)メモっておきます。

但し、Microsoftを通じて課金しない場合(サービスを提供し、そのサービス対価を、例えばPayPalで独自に課金するなど)は、以下の内容に当てはまりません。この方法は、ひょっとするとグレーゾーンかもしれないので、あらかじめ良く調べてください(私にはわかりません)。


注意:私は税理士ではないので、以下の理解は間違っている可能性があります。慎重に事を進めたいのであれば、必ず専門の税理士にご相談下さい。内容について、一切保証出来ません。

収益を送金する場合、Microsoftに対して、「W-8BEN Form」という申請書を提出する必要があります。米国では、例えばユーザーがアプリケーションを購入した場合、その代金を徴収した時点で、Microsoftが源泉所得税徴収義務者となるようです。そのため、そこで源泉所得税を差し引いてから、送金が行われます。

w-8ben

日本で主たる業務を行う法人事業者がアプリケーションを販売する場合、国内であれば売上と利益を期末に決算処理によって確定し、法人税確定申告を行います。その際に、日本の国内法に基づいて算出した利益(所得、でしたね。税会計は難しい)から税額が確定し、納税を行います。

Microsoft経由でアプリケーションを販売した場合、前述のように、米国内にて米国向けの源泉所得税が(自動的に)徴収されることになります。現行の米国法では、これは売上の30%とのことです(非常に大きい!!)。そして、差し引かれた売上が送金されてきます。

しかし、これは期末の決算処理で損金算入出来ません(出来るのかもしれませんが、ちょっと分からない)。ということは、米国と日本で二重に課税されてしまうのです。
(この部分は、法人ではなく個人でアプリケーションを販売する場合も同様です。そして、更にMicrosoftの取り分がある事をお忘れなく)

幸い、米国と日本は「通常の国交」があり、租税条約が結ばれているため、米国での源泉所得税徴収を免除してもらう事が出来ます。その為には、米国での納税者番号(EIN)が必要です(実際には納税しませんが、納税者番号が必要)。
この番号を申請書類「W-8BEN Form」に記載する事で、米国での源泉所得税が徴収されなくなります。

EINの取得は、IRS(アメリカ合衆国内国歳入庁)から行いますが、当然の事ながら、電話とFAXによる申請を根気よく実行する必要があります。私には不可能に思えたww ので、これを代行してくれる税理士に頼みました。親切に対応して頂き助かりましたが、EINの取得までにはそれなりの時間がかかります。急ぐ場合はあらかじめ相談しましょう。

EIN取得後、デベロッパーセンターの「税務情報」から、W-8BENの申請を行います。この申請はすべてオンラインで行う事が出来ます。Microsoftの米国法人に直接連絡したりする必要はありません。オンラインのフォームを入力すればOKです。

w-8ben2

なお、今のところ、EINの維持には、これ以上の負担はありません。今のところ、というのは、米国の法律が改正されて、例えば毎年更新が必要になったりする可能性が0ではない、と言う事です。まぁ、それは考えても始まらない事でしょう。そして、一度EINを取得すれば、Microsoftだけではなく、Appleや他のApp開発でも勿論使用出来ます。マルチプラットフォーム戦略があるのなら、必ず取得しておきたいところです。

さて、W-8BENをクリアした後は、利益を送金する先の「着金銀行」を入力する必要があります(Windows 8ストアアプリでは順序が逆)が、そこにも問題があります。米国から利益を送金する場合、送金にかかる手数料が馬鹿にならないと言う事です。
送金元銀行から着金先銀行(つまり、自分の銀行)に送金する場合、P2Pの如く直接送金されない可能性が高いのです。その場合は、バケツリレーのように中間経由される銀行が存在し、その度に手数料が徴収されます。

2ホップの例:

  • 送金元→送金元銀行(振込手数料)
  • 送金元銀行→中間転送銀行1(転送手数料)
  • 中間転送銀行1→中間転送銀行2(転送手数料)
  • 中間転送銀行2→着金銀行(着金手数料)
  • 着金銀行→自分の口座(振込手数料・口座維持手数料etc)

(手数料については書きませんが、国内の振込手数料をイメージしていると愕然とします。アプリ何十本分の利益が吹き飛びます)

しかも、どのように転送されるのか(あるいはされないのか)は、あらかじめ分からない可能性があるとの事です(シティバンクにて相談)。そのため、一度にまとまった額で送金する事はもちろん、如何に中間転送を省けるか、着金手数料を省けるかが鍵となります。

実は、着金銀行として選択できる銀行は、国内では事実上二択しかありません。シティバンクか、新生銀行です。しかも、2012年12月までであれば、シティバンク一択だったのです。シティバンクには「eセービング口座」という、とんでもなくおいしい商品がありました。口座維持手数料無料、着金手数料無料なのです。しかも、シティバンクは全世界に沢山の支店を構えています。そのため、中間転送の可能性が大幅に減るのです(支店に転送されれば、日本国内の口座への転送は無料)。

シティバンクは「eセービング口座」の新規受け付けを止めてしまいました。今から口座を開設する場合、口座維持手数料が「月額2,100円」かかります。あり得ないほどお得だったと言う事が分かると思います。

次点の新生銀行も、今のところ口座維持手数料は無料です。但し、今後課金を行う可能性がある事をアナウンスしています。また、着金手数料も無料ですが、シティバンクのように、全世界に支店を持っていないため、中間転送が発生する可能性はあります。

このような銀行間送金を行う場合、突っ込んでやるのであれば、送金の際に中間転送経路を指定する事も出来るようです。この辺りは、株や為替取引をやる人には当たり前かもしれないので、近くに知り合いが居るのであれば聞いてみると良いでしょう。(但し、Microsoftからの送金に、中間転送経路を指定出来るかどうかは分かりません)

そして、この二行以外の銀行が選択としてあり得ないのは、一つは着金手数料がバカ高いこと、もう一つは国内での中間転送がほぼ必ず発生し、その手数料は振込手数料の比ではない事、なのです。そんな事をするぐらいなら、上記二行に着金させた後、手動で振り込んだ方がマシです。

しかし、別の方法もあります。もし、PayPal口座を持つことが可能なら、PayPalも送金先として選択可能になったと言う事です(以前は選択できなかったらしい)。
PayPal強し! 上に挙げた数々の問題は、PayPalでは一切発生しません。PayPalでかかる手数料はシンプルで安く、しかもPayPal口座から国内の銀行への送金は、50,000円以上であれば手数料無料です(記述ミスではありませんよ、「以上」です)。

そのため、個人で利益を受け取る場合や、法人でもPayPal口座を持つことが出来るのであれば(会社のポリシーの話であって、法人口座に制限があるわけではない)、PayPalはお勧めの送金手段です。

PayPalは預金保護の対象となるのかどうかが不透明です。一応、その事を理解しておく必要があります。

もっとも、PayPalがマズい事になったら、世界的にもマズい事になっている気がしますがw

また、現在のところ、Windows 8ストアアプリでは、PayPal口座を送金先にする事は出来ないようです。

デベロッパーセンターも別々の扱いになっており、やる事は殆ど同じであるにも関わらず、面倒な事になっています。

そのため、将来的には統合されるのではないかと思います。

以上の事を調べたことで、得た感想:

  • 「国交」って大切なんだ
  • シティバンク強し!!金融取引も鎖国的な日本
  • シンガポール法人最強伝説(PayPalの事。TaxHeavenとまでは言わないが)

第六回まどべんよっかいち勉強会 LTスライド

第六回まどべんよっかいち勉強会お疲れ様でした。
「DotNetOpenAuthをうまいこと使う」というタイトルで、LTさせて頂きました。スライド置いておきます。

ASP.NET MVC4の新規プロジェクトで使用される「DotNetOpenAuth」ライブラリと、「Facebook C# SDK」を連携させるネタです。オリジナルはUsing OAuth Providers with MVC 4 By Tom FitzMackenですが、ポイントはほぼ一か所なので、LTネタとしては良かったと思います。

良くないのは、LTとして長すぎだったと言う事か orz すいません、時間が押していたのに。精進します。

オリジナルスライドはこちら(アニメーションを多用しているので、オリジナルを見た方が良いです)

なお、時間が無かったので補足しませんでしたが、通常のウェブサイト向け(ASP.NETウェブサイト)のOAuth運用では、アクセストークンを直接取得するのではなく、代わりに「コード」と呼ばれる、ログイン毎に一意の暗号コードを受け取り、暗号コードからアクセストークンを取得します。

The Login Flow for Web (without JavaScript SDK)

そのため、LTで紹介した方法(直接アクセストークンを取得する)は、最後にWindows Phone向けの事を絡めましたが、元々Windows Phoneのようなクライアントアプリケーション向けの処理方法です。

… と言う事を喋る余裕もありませんでしたw

COMのアパートメント (6) アパートメントの種類はどのように決まるのか

(追記:2020/5/26)

COMについて、細々とですがこのページに誘導されてくるのが分かっています。もっとわかりやすく包括的に書いたページがありますが、残念ながら、なぜか検索エンジンのレートから外されているため、ここで案内しておきます。「ChalkTalk CLR – COMのすべて」 を最初に見ることをお勧めします。


ずいぶんご無沙汰になってしまった。未だにCoInitializeExとかRPC_E_CHANGED_MODEで検索してくる方が絶えないので、少しだけ続きを書く。

前回、アパートメントの種類は、ライブラリの呼び出し元(正確にはスレッドを生成したコードの設計者)が知っているはずと述べた。だが、現実には、STAとMTAのどちらを使用すべきか、はっきり分かっていない開発者が多いと思う。
また、STAは重く、MTAにすれば軽いと、「まことしやかに」ささやかれていたりもする。もっと印象的なのは、「マルチスレッド」だからというものだ。

CoInitializeExでSTAかMTAを指定する事の他に、スレッドにアパートメントを指定する「意味づけ」がある。以下にこれらをまとめる。

  • STA – シングルスレッドアパートメント
    あるスレッドがCoInitializeExでSTAに設定した場合、そのスレッドはウインドウのメッセージループを持つと仮定する。つまり、そのスレッドが実行するコードの中核には、GetMessage・TranslateMessage・DispatchMessageによるメッセージループが存在する(しなければならない)。
    これは、極々一般的なWin32アプリケーションのメインスレッドの要件となる。同時に、例えワーカースレッドであっても、その中核がメッセージループで構成されているならば、STAとして設定する必要がある。
    もし、無理やりMTAとする場合、非常に難しい問題を自力で回避しなければならず(ウインドウメッセージとインターフェイス呼び出しの手動マーシャリング)、それが不可能な場合もある。通常はそのような事をする意味はない。
  • MTA – マルチスレッドアパートメント
    あるスレッドがCoInitializeExでMTAに設定した場合、そのスレッドにSTAのようなメッセージループの要件は不要となる。しかし、これは同時に、ウインドウメッセージとの連携は「全くない」と仮定する事と同じである。
    自分がウインドウメッセージと関連が無い(それどころか、ウインドウと関連が無い)と決めてかかるのは危険だ。そのスレッドが、あらゆるユーザーインターフェイスを、「直接的」ないし「間接的」に操作していないと確信できるなら、MTAを使用する事が出来る。これは、特に自分が書いていないサードパーティのコードを流用する場合は難しい。
  • メインSTA
    これはプロセスのメインスレッドがSTAに設定されている場合に、特にその状態を言う。コードの中には、メインスレッドでのみ操作可能な、特別な位置づけのAPIや変数などが存在する場合がある(つまり、例えSTAでも、ワーカースレッドからは操作してはならない、など)。これらを「メインSTAに紐づけられている」、と擬似的に考える。

スレッドにSTAを設定すると、スレッド毎に独立したSTAに所属する。つまり、スレッド=STAとなる。複数のスレッド(メインスレッドやワーカースレッド)が、それぞれCoInitializeExでSTAに設定されると、STAの部屋がそのスレッドの個数用意され、それぞれのスレッドがそれぞれのSTA部屋に入ることになる。

これに対して、スレッドをMTAに設定すると、プロセス当たりたった一つのMTA部屋に、MTA設定されたスレッドが同居する。STAはn個存在する可能性があるが、MTAは常に一つとなる。そして、STAのうちメインスレッドが入ったSTAにのみ、メインSTAという名前がついていると考えればよい。

で、これが何の役に立つのかと言う事だが、スレッド同士が会話したい場合(あるスレッドが、別のスレッドにあるCOMのインスタンスのメソッドを呼び出したりする)、この擬似的な「部屋」によって挙動が変わることになる。

Apartments

例えば、STAスレッド同士が会話する場合、相手のスレッドは別のSTA部屋に存在する(一つのスレッドには一つのSTA部屋が割り当てられるから、必ず別のSTA部屋になる)。すると、会話(メソッド呼び出し)は、ファサードとなるインターフェイスを経由しなければならない。COMの抽象化された世界では、メソッド呼び出しが直接成立しているように見えるが、実際には部屋が遠いので、秘書が電話でやりとりしているようなイメージだ。

物理的にはどうだろうか。それぞれのスレッドは両方ともウインドウメッセージのループを持っている。また、ウインドウメッセージの動作を邪魔すると困るので、お互いのスレッドに関与する場合はPostThreadMessageを使って、メッセージキューに内容を放り込むのが良いだろう(秘書に伝言する)。
時期的に都合がよくなる(ウインドウメッセージに同期)と、そのメッセージが取り出されて(秘書が社長に伝達)、「送り先のスレッド」で処理が実行される。返信も同様だ。元のスレッドのメッセージキューに結果が放り込まれ、元のスレッドの都合が良い時にとり出され、「送り元のスレッド」で処理が継続する。

この挙動が、一般的にWin32でワーカースレッドを生成して、時間のかかる処理をウインドウ処理から外だしした時と殆ど同じに見えるだろうか? 俯瞰して眺めるなら、STAとして設定することで、面倒なスレッド間メッセージングを隠ぺいして、RPCライクに呼び出し出来るようになると言う事だ。

だから、STAは「重い」のだ。

しかし、STAが重いからという理由だけでは、MTAに設定することは難しい。MTA同士の呼び出しでは、秘書も電話も存在しない。MTA部屋は一つしかない。その部屋の中で、社長が隣り合う席で直接話し合うようなイメージだ。ネイティブコードにおけるstd_callによって、直接メソッドが呼び出される。通常のプログラミングにおける「メソッド呼び出し」と完全に等価だ。それはすなわち、ウインドウメッセージやウインドウとの同期を一切行なわないと言う事だ。

仮にメッセージループを持つスレッドが、別のスレッドで生成されたCOMインスタンスのメソッドを直接呼び出した場合、メソッドは呼び出し元のスレッドで実行される。その結果、インスタンスが保持するウインドウハンドル(当然、別のスレッドに紐づいている)を、呼び出し元のスレッドが直接使用してしまうかもしれない。動作は予測不可能なものになる。

また、COMコンポーネントには、アパートメント属性の指定が無いものがある。このコンポーネントは、STAで生成される事を想定しているため、コンポーネント内でスレッド競合を特に考慮していない。MTAで生成すると、COMのインフラによって自動的にファサード(秘書通話に相当)が生成され、スレッド競合が回避される。

そのため、仮にだが、アパートメントを無視したような呼び出しを実行した場合(アパートメントを適当に設定すれば、結果的にそうなる可能性がある)、つまり、STAで生成されたこのようなインスタンスが、別のSTA/MTAからファサードの介在なく直接呼び出されたり、このインスタンスがコールバックすると、ウインドウメッセージの同期破綻はもちろん、ウインドウAPIの無効な呼び出し、スレッド競合による変数の破壊などの深刻な問題が発生する。

#以上の説明には、アパートメント設定の問題の他にも、プログラミング上の問題が含まれているが、そちらについては
#長くなるので、別の機会に。

この事を理解すれば、意味も分からずアパートメントを適当に設定するというのが、いかに危険か分かると思う。背景の理解は大変だが、判断の基準はシンプルで難しくない。

  • スレッドで行われる操作が、ウインドウやウインドウメッセージに及ぶ可能性がある場合(特にメッセージループを内包する場合)は、STAとして設定する。
  • それ以外であればMTAとすればパフォーマンスが向上する可能性があるが、心配ならSTAとして設定してもよい。
  • スレッドを生成したら、即アパートメントを設定する事。
  • COMインスタンスを操作する可能性が(直接的にも、間接的にも)完全にゼロである場合は、アパートメントを設定しなくて良い(CoInitializeExを呼び出す必要はない)。

.NETでコードを書いているのであれば、想像してほしい。Windows FormsならControl.Invoke、WPFならDispatcherを使いたくなる状況かどうかと同じ判断を、アパートメントに対しても行えば良い。これは、結局前回最後に書いた通り、これらのフレームワークのウィザードが生成するコードが「STAThread」とマークされ、メソッド呼び出しにマーシャリングを必要としていることに符丁するわけだ。

パフォーマンスが気になるというのなら、何が問題でSTAは遅いのか、と言う事を考えると答えが得られる。つまり、メソッド呼び出し(メッセージループにメッセージをポストしてやり取りする)にコストがかかることが問題なのであり、頻繁な呼び出しを避ければ良いのだ。プロパティを何度も参照したり、細かいメソッドを何度も呼び出したりすることを避けることで、一般的な使い方であればそうそう困ることはない。

COMコンポーネント側を設計するのであれば、頻繁なメソッド呼び出しを避けることができるように、拡張されたインターフェイスを設計しておくとよい。例えば、すべてのプロパティの値をまとめて取得・設定出来るようなメソッドや、バルク実行できるメソッド等が考えられる。

そして、COMインスタンスの操作を全く行わないのであれば、CoInitializeExを呼び出す必要はない。アパートメントの設定によって、STAならばウインドウメッセージキューが生成されてしまうし、MTAなら図中のスタックビルダーやインフラの準備でスレッドローカルストレージを消費するだろう。

例えば、素のWin32アプリケーションを作る場合、通常はCoInitializeExを呼び出したりはしない。しかし、ウインドウがActiveXコントロールを内包したり、WMI COMインターフェイスを使ったりするなど、直接的・間接的にCOMインスタンスを操作する可能性が生じれば、CoInitializeExでアパートメントを設定しなければならない。しかも、スレッドのエントリポイント(メインSTAなら、WinMain)の出来るだけ早い段階で、だ。

そして、ここが難しいところだが、アパートメントを設定しないのであれば、「間接的にも使われていない」と言う事を確認しておくことが重要だ(だから、心配ならSTAに設定する事をお勧めする)。

.NETのワーカースレッドで、スレッドのアパートメントを殆ど意識しないのは、COMインスタンスを.NETで操作する機会が(一般的には)あまり無いからだ。必要なければ、アパートメントを設定する必要もない。

猫でもわかるExpression Design

Windows Phoneアプリのアイコンを作るのに、VS2012ImageLibraryをいじって手を抜こうとしていたのだが、余計に面倒なことになってきたので、久しぶりにExpression Designを触った。某人からも「手ごろなお絵かきツールない?」と言われていたので、ここは一つチュートリアルを作らねばならないなと。


名称未設定1で、今日のお題はコレ→

分かってしまえば、「3分」で作れます。特にBlendを良く触る人は、「2分」で行けます。

用意するもの:
Microsoft Expression Design 4

3でも2でもあまり違いはありません。1は不明。Designはプロダクトから外れてしまったのですが、幸いなことに正式版が無償で公開されています!!

Microsoft Expression Design 4 (English)

このページは英語版ですが、下のほうに日本語版へのリンクがあるので、そこからダウンロードして下さい。すばらしい!


WS000000では、Designを起動します。

Designのファイルメニューの新規作成で、ドキュメントを作成します。

WS000001この新規作成ダイアログは、ドキュメントのサイズを指定できるようになっています。上の例では1024px×1024pxとしましたが、Designは「ベクター」ベースです。つまり、このサイズはあくまで指標であって、出力時にはスケーラブルに変更する事が出来ます。つまり、Designはペイント系ではなく、Illustratorのようなドロー系です。

ちなみに、Blend同様、数値入力ボックスの上でマウスをドラッグすると、手打ちしなくても値を上下出来ます。クリックすれば手打ちできます。これ良く考えてあるよね。但し、マウスボタンの調子が悪いと発狂するので、新調しましょう。


WS000002とりあえず、何も描かれていない状態です。

分かりにくいのですが、左下に「44%」と表示されています。これはキャンバスの拡大率です。もし、四角形がウインドウに収まっていないのであれば、ここを変更して丁度収まるようにして下さい。
(数値入力ボックスはドラッグできるんですよー?覚えてますか?)

WS000003まず、画角一杯の四角形を描きます。左のツールバーから、四角いアイコンをクリックし、出てきたサブメニューから「四角形」を選択します。

WS000004その後、キャンバスの左上隅から、右下隅までドラッグします。

キャンバスと同じ大きさなので分かりにくいですが、赤線の四角形が出来ました(赤線はこの図形が選択されていることを示します)。

WS000005やってみればわかりますが、キャンバスの四隅にはマウスポインタが「スナッピング」されるので、四隅の選択は非常に簡単です。ぎりぎりを狙って四苦八苦しなくても済みます。

WS000006ここで、右側のプロパティの「外観」に表示されている、色パレット(なんか綺麗にグラデーションしている面)で適当な色をクリックして選んでみて下さい。現在選択されているオブジェクト(つまり、今描いた四角形)の色が変わります。

WS000007もう色々触ってみたくなったカモ?w まぁ、ちょっと我慢して続きを。今回作るアイコンの背景はグラデーションさせたいので、実際にやってみます。ちょっと小さいのですが、基本パレット内のグラデーションパレット(左右に白黒グラデーションしているパレット)を選択します。

WS000008すると、色パレットの下にグラデーションバーが表示されます。ここも見た目と裏腹に非常に高機能なのですが、今回は簡単に2色のグラデーションをちゃっちゃと設定します。グラデーションバーの左側の下に、小さい四角のセレクタがあります。例では黒色ですね。これをクリックします。

WS000009すると、色パレットは、グラデーションバーのクリックした個所の色を指定出来るようになります。そこで、青っぽい色を選択します。この例のように、青が選択できない、青じゃない色しか出ていない場合は、すぐ右側にある虹色の縦のバーから青色付近をクリックすれば、選択できるようになります。

WS000010グラデーションバーの色の変化と同じように、四角形のグラデーションも変化したと思います。今度は右側の四角のセレクタ(白色)をクリックして、同様にちょっと濃さの違う青色を選択します。

WS000012背景完成!と行きたいところですが、グラデーションの方向が違いますね。色パレット右下の、トランスフォームアイコン(形が良く分からないので、スクリーンショットを参考に)をクリックし、回転角度をいじってください。

ここでは90°にしてみました。
(数値入力ボックスはドラッグできるんですよー!?覚えてますか!?)


WS000013これで、当初のもくろみ通りの背景が完成。次はルーペを作ります。ルーペの肝は何といってもレンズの部分でしょう。中抜きの円をどうやって描くかです。心配無用、超簡単。

ツールバーから、楕円を選択します。

そして、円を描くのですが、まずは中抜きの円の外形の大きさにします。四角形と同じようにドラッグで描けますが、そのままでは文字通り「楕円」になってしまいます。ここでは真円にしたいので、シフトキーを押しながらドラッグして下さい。XY軸が1:1の真円として描画されます。

もし、円までグラデーションになってしまったら、円を描いた時点で(つまり円が選択されている状態で)、右側の色パレットの基本パレットから白色を選択します。

WS000014そして、もう一つ円を描いてしまいましょう。コピペ(Ctrl-C、Ctrl-V)でも良いですし、新たに円を描いても良いです。

円の四隅に小さい四角があります。名称が良く分かりませんが、一般的には「アンカー」でしょう。このアンカーをドラッグして、中抜き円の内径に近づけます(シフトキーと併用ですよ!1:1になります)。

図形などのオブジェクトを操作する(移動や変形など)場合は、左側ツールバーの一番上の矢印アイコンを選択しておくと、やりやすくなります。

WS000015さらに円自体をドラッグして、最初の円と同心円付近に持ってきます。

WS000030ありがちなのは、外形が大きい円の「下」に小さい円がもぐりこんでしまって操作出来ないと言う場合です。WordとかExcelで図形を描画した事があるなら分かると思いますが、同じように修正できます。

円を右クリックして「整列」「背面移動」で、図形の順序を変更して下さい。

WS000016さて、準備が出来たら、大小2つの円を同時に選択します。シフトキーを押しながら、二つの図形をクリックします。両方とも赤線で囲われるはずです。

WS000017そして、「オブジェクト」メニューの「パス演算」、「背面マイナス前面」を選択します。

WS000031何が起こったか分かりますか?WPFで言うなら、GeometryCombineMode.Excludeですよー? 内径の大きさとして準備した図形で「引き算」を行ったわけです。これでルーペは出来たも同然。

ちなみに、このパス演算を使用すれば、三日月とか、どこかにありそうなマークとか、簡単に作れますね!
今回の場合、背景がグラデーションではなく単色であれば、内側の円の色を背景と同じにするだけでも行けますが、パス演算は強力なので、紹介しました。


WS000018後はルーペの柄の部分です。もう大体の操作方法は分かったと思いますが、一応やっておきます。まず、四角形ツールで長方形を描きます。

WS000033次にこの長方形を斜めに傾けます。長方形が選択されている状態で、下段中央付近に「回転角度」という数値入力ボックスがあります。これが正に選択しているオブジェクトの角度を表します。

例では(ドラッグして設定したので)45.1°になっていますが、手打ちすれば45°になりますよ。もうそろそろOK?

WS000021で、長方形の幅とか端処理をいじって、それらしくします。四角形の四隅を丸くするには、右のプロパティから「四角形の編集」「角の半径」という数値入力ボックスをいじります。ドラッグでぐわっと変えて、見ながら調節すれば良いでしょう。

WS000022いくぞー合体ー(ry

WS000023おぉ、完成だ! ….って、なんか変?

良く見ると、柄の長方形に縁取りが。

これは、オブジェクトの「ストローク」というやつです。図形を描くと、「ストローク(縁取り)」と「内面の塗りつぶし」の2つの属性が必要になります。今まで描いてきた四角形と円は、どちらも内面の塗りつぶし色だけを指定したため、縁取りがデフォルトのままになっているのです。

対処としては2通り考えられます。縁取りを塗りつぶしと同色にするか、縁取りを消すか、です。単純色なら同色でも問題ありませんが、今回のようにグラデーションを適用したり、テクスチャハッチングとかすると、模様が合わなくなって目立ってしまう可能性もあります。まぁ、そんな事に悩む頃には、どうすれば良いかも分かるでしょう。今は深入りせず、縁取りを消してしまいましょう。

WS000034図形を選択して、色パレットのタブを「ストローク」に変えます。

WS000035そして、基本色パレットから「なし」をクリックして、ストロークを無しにします。

これでOK。色パレット下のコンボボックスに「ストロークなし」と表示されていますね? ここをいじるとストロークの色だけじゃなく、模様とかテクスチャとか。まぁ、後で遊んでみて下さい。

ちなみに、塗りつぶしの色を「なし」にも出来ますよ。ストロークにのみ色を指定すれば、塗りつぶさない図形とか、簡単ですね?


WS000027さあ、完成です (^o^)/~~

WPFやっている人なら、ここまでの時点で「こりゃまんまWPFじゃないか」と思うかもしれません。たぶんそうです。というか、このDesignをWPFで実装しない理由はないでしょう。

WS000028さて、最後にこれをPNGで出力します。ファイルメニューの「エクスポート」で、フォーマットをPNG、画像サイズを256×256にして、パスやファイル名を指定してエクスポート。最初に書いたように、Designはベクターベース(WPFなら当たり前)なので、指定したサイズで綺麗に拡大・縮小されますよ。

WS000029ちなみに、PNGにすればベクターデータはすべて失われてしまいます。ちゃんとDesignのフォーマットでも保存しておきましょう(拡張子はdesign)。エクスポートではなく、普通に名前を付けて保存でOKです。

そして、PNGなら当然、透明色も反映されますよ。半透明や複雑な中抜き形状の図形を、アルファチャネルありで出力できます。図形や文字のアンチエイリアスも反映されます。


DesignとPaint.NETがあれば、とりあえずお絵かきに困ることはないと思いますよ。

ToggleSwitchを分離ストレージに関連付ける

WPFのトグルスイッチは、主に設定に使用する。
これが沢山あると、

ToggleSwitch

XAMLもそうだが、トグルイベントのハンドラもそれに合わせて書かなければならない。設定項目が増えるほど、このハンドラコードをチマチマと追加しなければならず、単純ミスも多くなる。
そこで、これをビヘイビアで何とかしようという話。

アプリケーションが複雑ではない場合、設定情報を単純に分離ストレージに格納すると思う。IsolatedStorageSettings.ApplicationSettingsコレクションを使用すると、出し入れは簡単になる。
ToggleSwitchの状態は、「オン」と「オフ」だけなので、ApplicationSettingsには単純にブール値で格納すれば良い。
そこで:

public sealed class AppSettingsBehavior : Behavior<ToggleSwitch>
{
    public static DependencyProperty SettingNameProperty =
        DependencyProperty.Register(
            "SettingName",
            typeof(string),
            typeof(AppSettingsBehavior),
            new PropertyMetadata(null));

    public static DependencyProperty OnTextProperty =
        DependencyProperty.Register(
            "OnText",
            typeof(string),
            typeof(AppSettingsBehavior),
            new PropertyMetadata("On"));

    public static DependencyProperty OffTextProperty =
        DependencyProperty.Register(
            "OffText",
            typeof(string),
            typeof(AppSettingsBehavior),
            new PropertyMetadata("Off"));

    public AppSettingsBehavior()
    {
    }

    public string SettingName
    {
        get
        {
            return (string)this.GetValue(SettingNameProperty);
        }
        set
        {
            this.SetValue(SettingNameProperty, value);
        }
    }

    public string OnText
    {
        get
        {
            return (string)this.GetValue(OnTextProperty);
        }
        set
        {
            this.SetValue(OnTextProperty, value);
        }
    }

    public string OffText
    {
        get
        {
            return (string)this.GetValue(OffTextProperty);
        }
        set
        {
            this.SetValue(OffTextProperty, value);
        }
    }

    protected override void OnAttached()
    {
        bool value;
        if (IsolatedStorageSettings.ApplicationSettings.TryGetValue(this.SettingName, out value) == false)
        {
            this.AssociatedObject.IsChecked = false;
        }
        else
        {
            this.AssociatedObject.IsChecked = value;
        }

        UpdateContent();

        this.AssociatedObject.Checked += AssociatedObject_Checked;
        this.AssociatedObject.Unchecked += AssociatedObject_Unchecked;
    }

    protected override void OnDetaching()
    {
        this.AssociatedObject.Checked -= AssociatedObject_Checked;
        this.AssociatedObject.Unchecked -= AssociatedObject_Unchecked;
    }

    private void UpdateContent()
    {
        this.AssociatedObject.Content =
            (this.AssociatedObject.IsChecked ?? false) ? this.OnText : this.OffText;
    }

    private void AssociatedObject_Checked(object sender, RoutedEventArgs e)
    {
        IsolatedStorageSettings.ApplicationSettings[this.SettingName] = true;
        UpdateContent();
    }

    private void AssociatedObject_Unchecked(object sender, RoutedEventArgs e)
    {
        IsolatedStorageSettings.ApplicationSettings[this.SettingName] = false;
        UpdateContent();
    }
}

というようなビヘイビアを作っておいて、

<ListBox Grid.Row="1" Margin="0,0,0,0" Padding="0,0,0,0"
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem"
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </ListBox.ItemContainerStyle>

    <toolkit:ToggleSwitch Header="正規表現を使用する">
        <i:Interaction.Behaviors>
            <Behaviors:AppSettingsBehavior SettingName="IsRegexMode" OnText="オン" OffText="オフ" />
        </i:Interaction.Behaviors>
    </toolkit:ToggleSwitch>

    <toolkit:ToggleSwitch Header="大小文字を区別する">
        <i:Interaction.Behaviors>
            <Behaviors:AppSettingsBehavior SettingName="IsCaseSensitiveMode" OnText="オン" OffText="オフ" />
        </i:Interaction.Behaviors>
    </toolkit:ToggleSwitch>
</ListBox>

と書くだけで、次々とToggleSwitch項目を簡単に増やすことができる。SettingNameには、分離ストレージに格納するキーの名前を、OnTextとOffTextはスイッチ左側に表示される状態を示すテキストを指定する。これらは依存関係プロパティにしてあるので、バインディングで多国語化することもできる。

Metro UIのボタンエフェクトをWindows Phoneに適用する

Windows Phoneで遊び始めている。
Windows Phone自体もそうだが、WPFも殆ど触ったことがないので、とても苦しいw
取り合えず、簡単なアプリを実際に公開してみて感触をつかみつつ、WPF理解への足掛かりにしたいなと思っている。

で、早速製作中なのだが、Metro UI(名称がぽしゃったので、何と呼べばいいのか困るなぁ)に使用するユーザーインターフェイスのボタン、

WP8MetroUI

のマウスカーソルのあたりをタップした時に、ボタンの隅が押されて変形したような挙動でフィードバックがある、アレをやりたいと思ったのだが、どうも簡単に出来ないようだ。
で、WPFの変形の基礎とか、コントロールのカスタマイズの方法など、色々調べて以下のコードを書いた。

(ここまで紆余曲折の末、約2日 orz 直前にGeometry/Path/RenderTargetBitmapだけいじっていたのが幸いした。でないと、座標がdoubleというだけでも悶絶していたかもしれない…)

public sealed class TiltBehavior : Behavior&lt;UIElement&gt;
{
    private PlaneProjection projection_;

<pre><code>public TiltBehavior()
{
    this.Depth = 30.0;
    this.Tracking = true;
}

public double Depth
{
    get;
    set;
}

public bool Tracking
{
    get;
    set;
}

protected override void OnAttached()
{
    this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
    this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
    this.AssociatedObject.LostMouseCapture += AssociatedObject_LostMouseCapture;

    if (this.Tracking == true)
    {
        this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
    }
}

protected override void OnDetaching()
{
    this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
    this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
    this.AssociatedObject.LostMouseCapture -= AssociatedObject_LostMouseCapture;

    if (this.Tracking == true)
    {
        this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
    }
}

private static void Apply(Size size, Point point, PlaneProjection projection, double depth)
{
    // コントロールのサイズからノーマライズした割合を得る
    var normalizePoint = new Point(
        point.X / size.Width,
        point.Y / size.Height);

    // 0~1の範囲外を切り捨てる
    var satulatePoint = new Point(
        (normalizePoint.X &amp;gt; 1.0) ? 1.0 : ((normalizePoint.X &amp;lt; 0.0) ? 0.0 : normalizePoint.X),
        (normalizePoint.Y &amp;gt; 1.0) ? 1.0 : ((normalizePoint.Y &amp;lt; 0.0) ? 0.0 : normalizePoint.Y));

    // 中心位置からの割合を得る
    var originPoint = new Point(
        satulatePoint.X * 2.0 - 1.0,
        satulatePoint.Y * 2.0 - 1.0);

    // 絶対位置
    var absolutePoint = new Point(
        Math.Abs(originPoint.X),
        Math.Abs(originPoint.Y));

    // 中心からの位置関係
    var directionX = originPoint.X &amp;gt;= 0.0;
    var directionY = originPoint.Y &amp;gt;= 0.0;

    // タップされた位置に応じて、回転軸位置を固定する(0又は1)
    projection.CenterOfRotationX = directionX ? 0.0 : 1.0;
    projection.CenterOfRotationY = directionY ? 0.0 : 1.0;

    // 辺ではなく、中心をタップした場合にも、フィードバックを得る
    // (辺をタップした場合は0に近づく事で影響を避ける)
    var distance = (absolutePoint.X &amp;gt; absolutePoint.Y) ? absolutePoint.X : absolutePoint.Y;
        projection.GlobalOffsetZ =
        (1.0 - distance) *
        0.5 *       // 中心位置でのZ座標
        (-depth);

    // Rotationは角度なので、計算して算出
    projection.RotationY =
        Math.Atan2(depth * (0.0 - originPoint.X) * 0.5, size.Width) /       // 0.5はGlobalOffsetZに含まれているので
        (Math.PI / 180.0);
    projection.RotationX =
        Math.Atan2(depth * originPoint.Y * 0.5, size.Height) /      // 0.5はGlobalOffsetZに含まれているので
        (Math.PI / 180.0);
}

private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (this.AssociatedObject.Projection == null)
    {
        this.AssociatedObject.CaptureMouse();

        projection_ = new PlaneProjection();
        this.AssociatedObject.Projection = projection_;

        var size = this.AssociatedObject.RenderSize;
        if ((size.Width * size.Height) &amp;gt; 0)
        {
            var point = e.GetPosition(this.AssociatedObject);
            Apply(size, point, projection_, this.Depth);
        }
    }
}

private void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
{
    if (projection_ != null)
    {
        var size = this.AssociatedObject.RenderSize;
        if ((size.Width * size.Height) &amp;gt; 0)
        {
            var point = e.GetPosition(this.AssociatedObject);
            Apply(size, point, projection_, this.Depth);
        }
    }
}

private void Uncapture()
{
    if (object.ReferenceEquals(this.AssociatedObject.Projection, projection_) == true)
    {
        this.AssociatedObject.Projection = null;
        projection_ = null;

        this.AssociatedObject.ReleaseMouseCapture();
    }
}

private void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    Uncapture();
}

private void AssociatedObject_LostMouseCapture(object sender, MouseEventArgs e)
{
    Uncapture();
}
</code></pre>

}

何しろWPFは完全に初心者なので、変なことをやっていたり、思想から外れる設計なのかもしれないのであしからず。これはUIElementクラスに適用できるビヘイビアクラスで、プロジェクトに入れておいて、ページのXAMLで以下のような感じで使う。

&lt;ListBox x:Name=&quot;MainListBox&quot; Margin=&quot;0,0,0,0&quot; Padding=&quot;0,0,0,0&quot;&gt;
    &lt;ListBox.ItemTemplate&gt;
        &lt;DataTemplate&gt;
            &lt;StackPanel Margin=&quot;8,0,8,8&quot;&gt;
                &lt;TextBlock Margin=&quot;0,0,0,0&quot; Padding=&quot;0,0,0,0&quot; Text=&quot;{Binding Name}&quot; TextWrapping=&quot;Wrap&quot; Style=&quot;{StaticResource PhoneTextSubtleStyle}&quot;/&gt;
                &lt;TextBlock Margin=&quot;8,8,0,8&quot; Padding=&quot;0,0,0,0&quot; Text=&quot;{Binding Description}&quot; TextWrapping=&quot;Wrap&quot; Style=&quot;{StaticResource PhoneTextSubtleStyle}&quot;/&gt;
                &lt;i:Interaction.Behaviors&gt;   &lt;!-- ココ --&gt;
                    &lt;Behaviors:TiltBehavior /&gt;
                &lt;/i:Interaction.Behaviors&gt;
            &lt;/StackPanel&gt;
        &lt;/DataTemplate&gt;
    &lt;/ListBox.ItemTemplate&gt;
&lt;/ListBox&gt;

ListBoxにコレクションをバインディングし、その要素毎にStackPanelで表示する。そのStackPanelにビヘイビアの指定を行うと、対応するクラスのビヘイビアが呼び出される。名前空間「i」は、System.Windows.Interactivityで、これはWindows Phone以外ではアセンブリが違うかもしれないが存在すると思う。最初にxmlns:iで宣言しておくこと。

なお、Buttonに適用するとうまく動かない。何故かは、これから悩むところ (^^;; StackPanelのクリックを検出する方向で逃げたほうがいいのか、Buttonで真面目にやるほうがいいのか、それすら分からないのが困ったものだ…

ThinkPad X201sで3G通信する

ThinkPad X201s

ThinkPadのよいところは、(保証に目をつむれば)カスタマイズの範囲が広い事だが、X系列は3G通信(WWAN)のオプションが搭載できる点でも良い。しかし、国内向けにはWWANオプションの選択肢が少ないか、あるいは提供されていない。

そんなわけで、どうすればそのようなX201sに3G通信の能力を与えられるか、というメモ。
(トライする場合は自己責任で、念のため)

  • QualComm Gobi2000 Mini PCIex moduleを買う。
    注意点は、ThinkPadの場合モジュールロックがあるので、ThinkPad用として販売されているモジュールしか使えない。例えば、Gobi2000はQualComm(Sierra)純正のモジュールが存在するが、これを取り付けるとBIOSがエラーを発してしまう。mod BIOSを入れるという選択肢もあるが、リスクを承知していない普通の人は手を出すべきではないだろう。特に純正モジュールは安かったりするので、飛びつかないように注意。
    もう一点は通信方式で、EVDO/EDGEタイプを買ってはいけない。国内の場合、DoCoMoかSoftBankに接続しなければならない。KDDIはEVDOの周波数帯は一致しているものの、KDDI側に機器の登録が必要らしいので、事実上使えない。
    今なら、Gobi3000やGobi4000(LTE)という選択肢もある。
    なお、これらモジュールは、技適マークがついている筈。
  • WWAN用無線アンテナを買う。
    国内向けThinkPadには、殆どのモデルでWWANアンテナが内蔵されていない。そのため、機種にあったWWANアンテナを入手する必要がある。ここで問題になるのが、アンテナの種類で、ヤフオクで売っているアンテナの大半は、GPSに対応していない。GobiシリーズはGPSにも対応しているのだが、こういったアンテナを買うと、WWAN通信は出来るがGPSは電波を拾えない。そんなわけで、GPSも使えるようにしたいのなら、Tycoのアンテナは多分ダメで、可能なら純正アンテナを入手するのが良い。
    X201sについての補足として、高解像度LCDを使っている場合は、そもそもWWANオプションは(世界的にも)存在しない。どうも天板の形状が通常LCDモデルと異なるようなので、仮に純正のアンテナを買うと、高解像度LCDモデルには取り付けできない可能性がある。
    なお、Gobi2000の場合は、アンテナは2系統必要。Gobi4000は、写真を見る限りでは3系統必要なようだ。私は、天板を外すのが面倒なので、3系統入れてしまった。Tycoのアンテナなので、GPSは使えない。取り付け位置は(幸いTycoは小型なので)適当に張り付けた。
  • SIMを入手する。
    国内では徐々に選択肢が増えてきた。手元で確認したのは、
    b-mobile ZSIM(使用しなければ0円のお手軽契約)
    DTI ServersMan SIM 3G 100(オプションなしで500円、100kbps)
    で、どちらもOKだった。ちなみに両方とも回線はDoCoMoを使う。

あとはドライバだが、Lenovo USA他の海外サイトから入手可能。変なドライバサイトからダウンロードしなければトラブルはないはず。これらはThinkVantageアプリケーションシリーズとして扱われており、Access Connection、GPSがある。但し、新品SIMのアクティベーションには以下のドライバが必要だが、この事はあまり書かれていないので注意(入れるだけでOK)。

Lenovo Mobile Broadband Activation (Windowsのバージョンが違う場合は探す事)

3GSIMを素で運用する場合、初めての場合は知らないかもしれないが、APNと呼ばれる識別子を設定する必要がある。b-mobileもDTIも説明書に書いてあるので、それに従ってAccess Connectionsのプロファイルを作ればよい。ユーザー名・パスワードも固定だが、忘れずに指定するように。

ACSettings1

ACSettings2

ACSettings3

晴れて接続できれば、以下のようになる。

Access Connection