d.sunnyone.org
sunnyone.org

ページ

2013-12-22

PowerShellにMSBuildLauncherで簡易GUIをつける

今日のPowerShell勉強会第1回の運営の方々、発表者の方々、そして参加者の方々お疲れ様でした。どれも面白かったり勉強になったりでよかったです。

さて、Lightning Talkで掲題の話をしたのですが、実用するには速すぎてわからなかったと思うので読み物としてわかるようにまとめたいと思います。

概要

MSBuild(.csprojなんかで使われている)はビルドには必要なんだけど、ちょっとコマンドライン叩くの面倒だよね、適当なGUIないよね。
  →MSBuild Launcherの誕生。

あれ、このGUIなら逆にビルドじゃない用途でも(スクリプト実行の用途でも)MSBuildにExec書いて使ったら便利なんじゃね?
  →MSBuild LauncherありきのMSBuildの邪道な使い方の誕生。

というお話です。

前提として、MSBuild Launcherをインストーラでインストール(関連付けオプション有効)を想定しています。

---

1. シンプルな使い方

単純に.ps1ファイルを置いて、それを実行するだけ。これでも十分に便利。一応、コマンドが長くなりすぎちゃうので、プロパティ(※1)としてpowershellコマンドを別出しにしておくのがおすすめ。

※1: パラメータのようなもの。PropertyGroup要素に好きな名前の要素を置くと、それがプロパティになる。



なお、-NonInteractiveは常に入れておくのがおすすめ。発表時も話したけども、例えば必須引数が足りなかったりすると通常のコンソールでは入力待ちで止まるけども、こいつはそんなことできないので、無言で待ちに入る。そして「進まない!」と悩む。なので-NonInteractiveで即座にエラーにする。

対応するスクリプトは好きな処理を書けばいいのだけど、一応例として。



動かすとこんな感じ。


2. プロパティを持たせる使い方

パラメータが欲しいときは、MSBuildにプロパティを持たせるとよい。そしてコマンドの中で$(Name)で使う。
ただし、Exec Command=""の中身の文字列はcmd解釈?のようなので注意。Command=をくくるのは""にして、プロパティを'$(Name)'という感じにくくるのがおすすめ。



プロパティはLTでは話さなかったけども、候補としてConditionを追加してあげると、コンボボックスの選択になるので、選択のときはそうしてあげるとよいかも。

スクリプトはこんな感じ。paramで受けてあげればいい。



動かすとこんな感じ。右側で設定できる。


3. 複数のターゲットを用意する便利な使い方

複数のやりたいことを一つの画面で行うには、もちろんスクリプトを複数用意してもよいのだけど、処理自体は少ない場合は、モジュール(.psm1)に関数を定義して、それをMSBuildから使う方式がおすすめ。

具体的には、PSCmdの中にImport-Moduleまで入れてしまって、Execの中では関数名を書く形にする。



スクリプトはこんな感じ。



動かすとこんな感じ。


4. PowerShellの便利機能を活用する

PowerShellを簡易GUIっぽくしちゃうことで有名なOut-GridViewやShow-Commandはここでも便利。
ただ1点注意があって、Execで実行するとコンソールと違ってホストが残らないので、そのままだとすぐ画面がいなくなってしまう。
なので、以下のように終了を待ってあげるのがいい。


---
今度こそぜひ活用してあげてください。

2013-12-16

Markdown.XAMLを使ってWPFでMarkdownテキストをレンダリングする

この記事は、XAML Advent Calendar 2013用です。今日は、MarkdownをWPFアプリケーションに表示する方法についてです。
---

Windows Phoneでmarkdownで書いたテキストをhtmlに変換して表示する を見て、そういえばMarkdownを表示するためのライブラリがあったことを思い出した。

その名もMarkdown.XAML。これは、MarkdownテキストをFlowDocumentに変換してくれる。使い方はざっくり言うと、TextToFlowDocumentConverterというコンバータが使えるようになるので、FlowDocumentScrollViewerのようなFlowDocumentを表示してくれるコントロールに、Markdownテキストが入ったプロパティとこのコンバータをセットでバインドしておくだけでOK.

詳しい使い方は以下の通り。

1. 下準備

Markdown.XAMLをclone or zipでダウンロードして、Visual Studioで開き、コンパイルする。

そうすると、build\Markdown.Xaml\(Configuration)のあたりにMarkdown.Xaml.dllができるので、これを、Markdownを表示させたいプロジェクトに持っていって、参照させる。

NuGetになさそうなのが残念だけど、すんなりコンパイルできるのでまぁ。

2. Markdownテキストを適当なプロパティに入れておく

ファイルから読んでとか、いろいろありそうだが、ここの本題ではないので、ここでは適当な文字列を返すプロパティを作っておく。


3. リソースに、MarkdownとTextToFlowDocumentConverterを定義する

TextToFlowDocumentConverterを作り、そこに実体であるMarkdownオブジェクトを紐づける。とりあえずこんなかんじ:


4. FlowDocumentをレンダリングするコントロールを配置する

FlowDocumentScrollViewerを配置して、さきほどのプロパティとコンバータをバインドする。


シンプルに表示したいだけなら、これだけ。

できたものはこんなかんじ:

活用編

FlowDocumentになっているので、もう少しWPFに寄った形で使える。

1. パネルの見た目を変更する

ちゃんとパネルも見えているので、たとえばパネルの背景色を変えたりすることができる。FlowDocumentScrollViewerのプロパティも当然使える。


2. スタイルを設定する

たとえば、文字色を変えたければ、このようにいつもの通りStyleを定義することで、変更することができる。


結果はこんなかんじ:


詳しくはデモがあるので見るとわかりやすいと思う。
https://github.com/theunrepentantgeek/Markdown.XAML/blob/master/src/Markdown.Xaml.Demo/MainWindow.xaml


----

どうでしょうか。わりと簡単に使えると思うので、適当なテキストを出したいときなんかにどうぞ。

2013-12-11

PowerDbg でデバッガ操作をオートメーションする

この記事は、PowerShell Advent Calendar 2013用です。本当は、誰も触れてないPowerShell v4.0の新機能について触れる予定だったのですが、新機能以外の部分で挫折したので実用的な内容に方針転換します。

今回の話題は、WinDbgの操作をオートメーションするスクリプト、PowerDbgの使い方です。これはなにかというと、WinDbgのコンソール版、cdb.exeのフロントエンドです。PowerShellがデバッガになるというよりは、windbgをコントロールできる感じです。

インストール方法

http://powerdbg.codeplex.com/ に行き、Downloadボタンを押すと、zipが落ちてくるので開きます。その中に「Install_PowerDbg.bat」というファイルがあるので、実行するとインストールされます。

といっても、横に置いてある「PowerDbg.psm1」を「%USERPROFILE%\Documents\WindowsPowerShell\Modules\PowerDbg」にコピーするだけなので、手でやっても変わらないです(もっと言うと、好きな場所に置いて毎回Import-Module .\PowerDbg.psm1でもいいです)。

あとは、いくつかの方法のどれかでcdb.exeのあるフォルダを指定します。でも一番簡単なのは.psm1の頭、param(...)のあとに以下のように記述することなので、ここではそれだけ書きます(どうせスクリプトは更新されなさそうだし)。
$debuggerRoot = "C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64"


使い方

「New-DbgSession」コマンドレットで、デバッガを起動できます。-command "コマンド..."で新コマンド起動、-process "プロセス名" でアタッチ、-dump "dumpファイルのパス" でダンプ読み込みです。

PS> New-DbgSession -command "C:\Program Files (x86)\MsbuildLauncher\MsbuildLauncher.exe"

そして、「Invoke-DbgCommand」でデバッガコマンドを送れます。
PS> Invoke-DbgCommand 'bp $exentry'

「g」は「Send-DbgGo」というコマンドレットが用意されているので使えます。
PS> Send-DbgGo
Send-DbgGoすると、止まるまでブロックします。Ctrl+Cで抜けることも可能。

終わりたいときは、「Exit-DbgSession」で終われます。
PS> Exit-DbgSession

.loadby sos clrみたいに拡張をロードしたいときは、Load-DbgExtensionが使えます。
PS> Load-DbgExtension sos clr

Invoke-DbgCommandで何を送るかが肝で、PowerShell固有の操作はほとんどありません。(引数名がcamelCaseなのがいけてない感じですがスルーでおねがいします…)

実用例1: 異常終了したときに.NETのスタックトレース等を表示するスクリプト

前にやった「WinDbgとSOS拡張でVSを使わずに.NETアプリをデバッグ - 異常終了時の調査」を自動でやれます。



実行するとこんな感じ。
PS> > .\PrintExceptionSecondChance.ps1 -Command "C:\temp\MsbuildLauncher-0.1.1\MsbuildLauncher\MsbuildLauncher.exe"
ModLoad: 000007fe`f7200000 000007fe`f7b60000   C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
ntdll!ZwMapViewOfSection+0xa:
00000000`7755153a c3              ret
(1340.8e8): Unknown exception - code 04242420 (first chance)
ModLoad: 000007fe`f5a60000 000007fe`f5b8e000   C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clrjit.dll
ntdll!ZwMapViewOfSection+0xa:
00000000`7755153a c3              ret
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): CLR exception - code e0434352 (first chance)     ←ここでエディタパスをおかしくして「Edit」ボタンをクリック
(1340.16c0): Unknown exception - code 000006ba (first chance)
(1340.8e8): CLR exception - code e0434352 (first chance)
(1340.8e8): CLR exception - code e0434352 (!!! second chance !!!)
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\system32\KERNELBASE.dll -
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\Microsoft.NET\Framework64\v4.0.3
0319\clr.dll -
KERNELBASE!RaiseException+0x3d:
000007fe`fd6a940d 4881c4c8000000  add     rsp,0C8h
PDB symbol for clr.dll not loaded
Exception object: 0000000002b0eeb8
Exception type:   System.ComponentModel.Win32Exception
Message:          指定されたファイルが見つかりません。
InnerException:   
StackTrace (generated):
(略)


実用例2: .NETなプログラムのプロセスのダンプファイルを読み取ってスタックトレースを出力するスクリプト

実はいつもやってる「clr.dllが読み込まれるまで進める」という処理が必要なければ、New-DbgSessionは-sosというオプションでsos.dllを自動で読んでくれるのです。それを利用すると、これだけ簡潔にできます。




どうでしょうか?今回の例はとくにPowerShellらしさはないですが、特定のブレイクポイントを一気に仕掛けるとか、結果に応じてどうこうするなんて用途には便利かと思います。

蛇足

WDK 8.1についてるWinDbgでSOS拡張をロードして、SOS系のコマンドを打つと、一発目がExceptionになって、二発目以降に成功するようになる。8.0ではそんなことはないので、WDK 8.0についてるWinDbgがおすすめ。






2013-11-30

MSBuild Launcher 0.2.2 をリリース

MSBuild Launcherの0.2.2をリリースしました。「ターゲットがたくさんあるMSBuildファイルで、何度も同じものを実行したいときに今のUIだとつらい」という要望があったので、前回実行したターゲットの色を変えるようにした、というのが今回の変更です。


あと、WindowsXPでクラッシュする問題への対策もだいぶ前に入れたので、今は大丈夫のはずです。

2013-11-18

SQL Server データベース間でちょっとだけデータを移行する

ローカルだったらSQL Server Management StudioでGUIでぽちぽちやるだけで簡単なんだけど、SQL Azureだと機能が制限されているようなので、ここではbcpを使う。

テーブルが1テーブルで、大きくなければ、2コマンドだけ。まぁ、expdp/impdpとかpg_dump/pg_restoreとか結局こんなもんだよね。

データ吸い出し
bcp TableName out c:\temp\tablename.dat -S 移行元データベースサーバ -d データベース名 -U ユーザー名 -P パスワード -n -q

データ流し込み
bcp TableName in c:\temp\tablename.dat -S 移行先データベースサーバ -d データベース名 -U ユーザー名 -P パスワード -n -q

bcp.exeは、C:\Program Files\Microsoft SQL Server\110\Tools\Binnとかにある。

さくっとできちゃうので、接続先には強く気をつけること。ちなみに、-U/-Pの代わりに、-T でWindows統合認証。

なお、データがたくさんの場合は、 バッチサイズを指定したり、テーブルロックにするようにしたりと、いくつか気にしたほうがいいポイントがあるので、気をつける。

参考:

2013-10-14

PSWFWeb (PowerShell Workflow WebConsole) v0.0.1 をリリース

PSWFWeb (PowerShell Workflow WebConsole) version 0.0.1 をリリースしました。こんな感じで、ブラウザからPSWorkflowを走らせたり状態が見られたりするソフトです。


ダウンロードはこちらから。使い方は、READMEを見てください。


途中で挫折しかけてお蔵入りになるところだったのですが、スクリーンショットで反響を頂いたので、仕様を絞って最低限試せるレベルまで作ってみました。とはいえ自分でもあまり試せていないレベルなので、アグレッシブなことをすると、なにが起きるかはわかりません :)

ただでさえPowerShellはユーザーが多くないと思われるのに、PowerShell Workflowを使う人はさらに少ないと思いますが、ピンと来た人はぜひ使ってみてください。


造りとしては、Nancy という.NET向けのSinatraライクなフレームワークを使っています。これは主に、自身でWindowsサービスとなってWebをホストする(self-hosting)ためです。動作ユーザーを好きにさせるためと、将来(があれば)たぶん状態を持ってポーリングとかするだろうなと思ってWindowsサービスにするためにしています。

実際使ってみると、ASP.NET MVC (空)よりずっと依存関係が少なく、Sinatraの感覚がわかる人にはけっこうおすすめで使える感じです。内蔵のSuper Simple View Engineは、かなーりシンプルなのでRazorを持ってきたほうがいいかもしれませんが。

画面のほうは、PureというYahooが出しているWebフレームワークを使ってみました。Emailというレイアウトサンプルをほぼそのままの感じです。

ちなみに、Runtimeをhostingするわけではなく、Get-Job等々をPowerShellで呼び出しています。ほんとに*-Jobのwrapperというかんじ。

2013-09-25

AndroidからBluetooth機器にSPP (Serial Port Profile) で接続する

作ったデバイスにAndroidからつないでみようと思ってやってみた。まっとうに使ってもらおうとすると、他にもけっこういろいろ必要なのだけど、自分で使うくらいならわりと簡単にできる。

やりかた

  1. BluetoothAdapter.getDefaultAdapter()を使って、アダプタを得る。
  2. アダプタにisEnabled()を呼び出して、Bluetooth設定が有効なことを確認する。
    • インテントを出してユーザーに有効にしてもらうことも可能だけど、ここではしない。
  3. アダプタにgetBondedDevices()を呼び出して、ペアリングされたデバイスの一覧を得る。
    • 探索してペアリングされたデバイス以外から探すことも可能だけど、ここではしない。
  4. デバイスのプロパティを見て、欲しいデバイスを探し出す。
    • 本当はUI出して選んでもらうのがいいと思うけど、ここではしない。
  5. 欲しいデバイスにcreateRfcommSocketToServiceRecord()を呼び、必要なサービスのBluetoothSocketを得る。
    • SPP (Serial Port Profile)のUUID(00001101-0000-1000-8000-00805F9B34FB)を渡す必要があるので、定数定義しておく。
  6. BluetoothSocketにconnect()を呼ぶ。
  7. BluetoothSocketにgetInputStream() / getOutputStream()を呼んで、適当に操作する。
  8. BluetoothSocketにclose()を呼ぶ。


このへんのページのほうが詳しいので、「ここではしない」ことがしたければこちらを参考に...

罠1) getDefaultAdapter()は、Gingerbread (2.3)では、UIスレッドでしか呼べない。


いかにもUIなんか関係なさげなメソッドなのに、Handlerが取れなくて例外が出る。4.1では起きないらしいけど、2.3じゃダメだと…ねぇ?
cf: https://groups.google.com/forum/#!msg/android-developers/wFbD5V2DWRc/gv0VF4Y6ICwJ

罠2) BluetoothSocket#connect()は「Service discovery failed」でたまに失敗する

Webを見るとよくある話のようで、ウエイトを入れたり、アダプタにcancelDiscoveryをさせろとか、リフレクションで中のメソッドを呼び出せとか、いろいろある。どうにもすっきりしないし、時間がかかってNGなので、何かのタイムアウトなんだと思う。なので、とりあえずリトライすることにした(リトライの条件はもう少ししっかりしたほうがいいかも)
cf:  http://stackoverflow.com/questions/3397071/service-discovery-failed-exception-using-bluetooth-on-android

コード

ASCIIで1行書き込むと、1行返ってくる感じのサンプル。

本当はすべてUIじゃないスレッドの中でのコードにしたかったのだけど、上述の罠があって、getDefaultAdapter()だけUIスレッドで渡すようにしているので、コピペでは現実的に動かない。

close()漏れとかあるので、ためしに書いてみるてな感じの参考程度に。sendLogMessage()は、適当なTextViewにログを出すためのメソッドなので、Log.dとかでよいです。


2013-09-21

Arduino + USB ホストシールド + BTドングルでBluetooth Lチカ

このあたりを参考にしたら、思ったよりも圧倒的に簡単にできたので、思わず記事にする。ArduinoとUSBホストシールドにBluetoothドングルを使うと、SPP (Serial Port Profile)を使って簡単にLEDチカチカできちゃう。

1. 機器を準備する

必要なものは、ArduinoとUSBホストシールド2.0とBluetoothドングル。今回は、以下を使った。
最後のBluetoothドングルはもう売ってないと思うけど、似たようなやつが千円くらいで買えると思う。だいたい使えそうな気がするけど、Linuxで使える報告があがってるやつとかが無難なのかな?

USBホストシールドは2.0なものを選ばないとたいへんらしい

2. つなぐ

USBホストシールドにBluetoothドングルを差して、Arduino Unoに重ねて、適当なデジタルピンにLEDと抵抗のセットをつなげばいい。ただし、デジタル8~13は使っているらしいので注意。今回は6番を使った。

3. Arduino IDEの所定のディレクトリにzipを展開する

https://github.com/felis/USB_Host_Shield_2.0 から、zipアーカイブをダウンロードして、/usr/share/arduino/libraries/USB_Host_Shield_20 に展開する。

4. SPPサンプルを開く

Arduino IDEのメニューからUSB_Host_Shield_20のBluetoothのSPPのサンプルを開く。

5. ちょちょいと書き換えて転送する

サンプルはSerialとSerialBTでお互いにechoする感じなので、適当にif文を書き換えてdigitalWrite(ピン, HIGH/LOW); でチカチカさせるようにする。

変更した部分はこんなかんじ(全体は最後に)。
if (SerialBT.available()) {
  char c = SerialBT.read();
  if (c == '1') {
    digitalWrite(6, HIGH);
  } else {
    digitalWrite(6, LOW);
  }
  Serial.write(c);
}

あとは転送する。

6. ペアリングして通信する


ターミナル的なソフトが使えれば、WindowsでもLinuxでもなんでもいいと思うけど、今回はAndroidとS2 Terminal for Bluetooth Free を使った。1とか0とか送ってチカチカすれば成功!

ソース全体でもこれだけ。eneloop スティックブースターで動くし、お手軽にライトな無線機器を作るのにいいと思う。



2013-09-16

照明On/OffのAndroidクライアントを作った

前に自室の照明をスマートフォンからOn/Offする CGI を作ったのだけど、ブラウザで見ると不便な点がいくつかあったので、このくらいならすぐできるだろうとAndroidクライアントを作った。実行すると以下の絵のようなダイアログがポップアップする。


ダウンロードはこちらから→https://github.com/sunnyone/LightControllerAndroid/releases/tag/release-0-0-1 (GitHubのリリース機能をはじめて使ってみた。)

十中八九この環境でしか使われないくせに設定画面(メニューから呼び出し)がついてるので、URLは設定でコントロールできる。ただ、認証とかには対応してないので、secureなLANで使ってください。

本当はウィジットで作りたかったんだけど、1x1じゃ使いづらそうな割に2x1や1x2は場所取り過ぎなのと、ウィジットでのクリックと処理実装が(やりたいことのわりに)面倒そうだったので、ダイアログテーマのアクティビティで実装した。本当は文字列をリソースから引いたりしないといけないんだけど、自分の中でAndroidのHello, World的位置付けなのでとりあえずここまで。

このシンプルなアプリですらかなりはまったので、はまったポイントを環境構築編のみダイジェストでお届け。Androidがもし無名の環境であれば、このシンプルな画面すらたどりついていなかった。

ウィンドウ>Android SDKマネージャーが表示されない

 パースペクティブのカスタマイズのコマンド・グループ可用性で「Android SDK および AVD マネージャー」をチェックすること。参考:http://www.devlog.alt-area.org/?p=547

SDK マネージャーが起動しない(C:\Windows\system32\java.exeを使おうとする)

Windows 64bitの問題らしい? がんばってjavaを探そうとしている adt-bundle-windows-x86_64-20130729\sdk\tools\lib\find_java.batの先頭を以下のように書き換え(path-to-javaは自分用に)
@echo off
set java_exe="path-to-java\bin\java.exe"
set javaw_exe="path-to-java\bin\javaw.exe"
goto :EOF

参考:http://d.hatena.ne.jp/thinkAmi/20120730/1343600121

Emulatorがメモリ確保に失敗して起動しない

AVDの設定画面を見ると、Windowsで768MB以上だと失敗するかもみたいなことが書いてある。とりあえず512MBにしてようやく起動。



2013-09-14

LibreOffice Calcの選択セルをMediaWiki表形式に変換するBasicマクロを作った

MediaWikiで表を書くとき、最初に作るときにフォーマットを思い出すのが辛いので、LibreOffice Calcの選択セルをMediaWikiの表形式に変換するマクロを書いてみた。ずっと書こうと思っていたのだけど、ようやく書けた。LibreOfficeにしておけば、気兼ねなくインストールして使えるので。



使い方は簡単で、選択してこのマクロを実行するだけ。そうするとメッセージボックスが出てくるので、このボックスはテキスト選択可能なのでコピペすればOK。ツールバーの空き部分にでもボタンを貼っておけばいいと思う。MediaWikiの表は、もっと高機能だけど、ひとまずプレーンな形に整形するだけ。

これがマクロ。

全然エレガントじゃない。

書くときのポイント

  • LibreOfficeについているマクロエディタは補完もないので、最初はNotepad++でVBモードで書くのがおすすめ。

参考にしたもの

辛かったこと

  • 流儀がわからない
    • プロパティ?の参照は .Abc = "ABC" だったり、setAbc("ABC") だったり書いてある場所によってぶれぶれ。変数名の命名はoから?とか。まぁ最初は動けばいいんだろうけど、結局すっきり書けなかった。
  • クリップボードがめちゃくちゃつらい。Win32 APIプログラミングですかっていう低レベルさ。
 プログラミングを始めたときのようなもどかしさを味わうことができた。



2013-07-28

「仕組み」の名前の考え方

名前に関する記事のタイトルがいまいちなのはさすがによくないので、タイトルを直した(2013/7/29)
---

最近ちょっと近くで話題になっていた「名前」の考えていきかたについて整理してみた。

ブランド名のように、独自性を持たせることを目的とするのではなく、後で呼びやすく混乱しないための名前付け。主に「それ」を知る人間同士がその物を識別するために使うための名前のガイドライン。「わかりやすい」「混乱しにくい」名前をつけるにはどう考えていけばいいか、というお話。

自分の立ち位置的に、ソフトウェア設計の視点が強くなってしまうが、仕組みを作る立場であれば似たような話になると思う。

経験がたまれば、更新するかも。

1) 文をそのまま使う

「これは何ですか?(何をするものですか?何をすることですか?)」と聞かれたと想定して、それで出てきた説明文をそのまま呼び名にすることを検討する。「何ですか?」の回答そのものなので、意図が伝わりやすい。長くなりがちだが、明快な説明ができる人間の命名であれば、短いことを上回るメリットがあることが多い。

確認ポイント

使う頻度は高くないか?
使う頻度が少ない(例えば、個別の機能のいちモジュール名だったり、年一回の事務処理の細かい手順のひとつだったり)のであれば、意図が伝わりやすいことのメリットが大きい。 しかし、毎日呼び合うような名前だと、短い名前をつけることを検討したあと、決定したほうがよい。 なぜかというと、ただ呼びやすいだけのあまり考えられていない(混乱しやすい・わかりにくい)名前で呼ばれてしまいやすくなるから。
一部の単語だけピックアップして呼び続けられたりしないか?ピックアップされても混乱はないか?
ピックアップしても区別できないから、本当に汎用な言葉がピックアップされることは少ない。例えば「顧客情報データ」を「データ」と略して呼び続けることは少ない。 しかし、文脈を共有すると選んで呼びやすくなってしまう語がある。例えば「クライアント」とか。 混乱がなければそれでもいいのだけど、混乱することがすでに想定できるのであれば、別の名前をつけてあげるのがよい。
そこから頭字語・略語はできるか?
これでつけてみた名前で、頭文字を取ったらいい感じに呼べる名前だったとか、略したら呼びやすかったりしたら、最初から略はこうです、という形で 明示しておくと混乱がない。一方で、その略語が他と同じ場合、かえって混乱を招くので、そもそも略していない状態でも他の呼び名を検討する。

2) 同じジャンルの意図することそのものの単語を使う

1) のそのまま使うパターンにマッチせず、意図した内容が既に一般的な名前として決まっている場合(「一般的に決まった名前」は以後、「定義された名前」とする)は、それを使うことを検討する。ずばりそのものということなので、ほとんどの場合良いが、安易に使うと大混乱を招くケースがある。

確認ポイント

元の語と明白に異なる意図を持っていないか?
新しくつける名前側が従で、定義された名前のほうが先に来ているようなケースでは、それが前提である以上、異なる意図は存在しにくいので、この名前付けパターンは良い選択である。 例えば、定義された名前が何かの規格で、その規格に乗ることこそ意図されたような場合であれば、それを名前につけるのは、受け取る側の意識付けの意味としても、非常に有効である。 しかし、定義された名前が従の場合、注意が必要である。「これこれはAで、あれそれはB…これってXYZって名前ついてるじゃん!」というケース。 こういった場合、一部の重要な部分が異なる場合がある。例えば、「定義された名前ではそれそれはCなんだけど、自分が考えるのはそれそれはDなんだよね…」といった感じ。 このようなことが名前付けの段階で明らかに分かっている場合は、その名前は使うべきではないことが多い。 なぜかというと、聞いた側は、名前が既に定義されているが故、その定義側の意図のほうを名前に感じてしまうから。 「俺のXYZはそうじゃないんだ!」といっても、最初はいいかもしれないが、よっぽどの強さがないと、元の語の意図を書き換えるのは難しいので、どんどんその意図は薄れて行ってしまう。
元の語に付加したい強い意図は持っていないか?意図を狭めたくはないか?
定義された名前は確かにずばりなんだけれど、もっと範囲を狭めておきたいという意図がある場合は、言葉を付加するなり、別の名前付けをするなりを検討すべき。 そうしておけば、広すぎて何を言っているかわからないという事態を避けられる。

3) 別ジャンルの意図することと関係のある単語を使う

文そのものでも、既存の言葉もない場合は、別ジャンルの近そうな言葉がないかを考える。メタファー/こじつけの世界。
一回目は聞いてもわからないが、わからない故、確認が必要となる。ゆえに、混乱を招きにくい。比喩になっているので、一回認識してしまえば、覚えやすい。

確認ポイント

選んだ言葉から受ける意図が、他の一面と衝突しないか?
単語の持つ意味は一面ではないことがあるので、ある面を見て比喩を選んでも、別の面で衝突している可能性がある。 例えば、固いイメージを与えたいからといって「フライパン」と名付けたとしても、冷たいという意図を併せ持つものだったりすると、「フライパン」の持つ熱せられそうなイメージと衝突するので、混乱を招く。
元のジャンルでその言葉は別の意味を持っていたりしないか?
比喩として使われていたりなどで、すでに使われていないか。強い意図を持ってジャンルの壁を越えてきているので、うっかりこの ケースで意図がバッティングすると、大混乱を招く。

4) 別ジャンルの全く関係ない単語を使う

3)に近いが、名前付けに意図がないので、さらにぱっと見/ぱっと聞きでわかりにくくなるが、混乱も小さくなる。
数が必要な場合に選ぶとよい。

5) 新単語を作る

どうしても困る場合は、新しい言葉を作ってしまうのもひとつ(文を略語化するのもこのパターンの一つなんだけど)。

決めた後の確認

似たような意図の語がすでに用意されていないか?それとの違いは何か?
最初にやるべきだけど、名前をつけることで明確になることもあるので、再度確認する。
似たような単語が既に使われていないか?
別の意図なのに、同じあるいは同じような用語が使われていないか確認する。

2013-07-12

Azure WebRole開発で使われるIIS Expressの設定(applicationHost.config)を変更する

Azure WebRole開発で(設定で選択した場合)利用されるIIS Expressの設定を変更する方法がちょっとトリッキーなので記録しておく(Azure SDK 2.0向け…Azureはどんどん変わるので)。このブログでAzureが登場するのは初めてかも。

結論

c:\Program Files\IIS Express\AppServer\applicationHost.configを変更する。

うまくいかなかったら、下に書いた方法で調べるといいかも。

詳細

Web Roleのアプリケーションを開発する際は、開発環境でIIS Expressを使うかIISを使うかをクラウドサービスプロジェクトの設定で選べる。
この設定でIIS Expressを使用するを選んだ場合、IIS Expressが利用される。AzureのIISの設定は、 startup taskでappcmd.exeを叩く(いつもお世話になっているブチザッキさんのブログ)とか、Microsoft.Web.Administartion(NuGet)を使ってC#から変更するといった方法が使えるのだけど、IIS Expressの場合はIISではないので、この方法では設定が反映されない。

IIS Expressの設定ファイルはDocuments\IIS Express\config\applicationHost.config をいじれという情報がWebにある(例えばいつもお世話になっているブチザッキさんのブログ)ので、「これだ!」と思って変更するものの、反映されない。

そこで、Process Explorerでiisexpress.exeのコマンドラインを調べてみると、applicationHost.configの場所が明示的に指定されていることがわかった。

指定されているのがどう見ても一時的なパスなので、もしかして埋め込まれてたりして変えられないのかなーと思ってProcess Monitorで見たら、WaHostBootstrapper.exeがc:\Program Files\IIS Express\AppServer\applicationHost.config を読んで、上記の一時的なパスに書き込んでいることがわかったので、元のファイルを書き換えてみると無事反映された。


めでたしめでたし。
(自分の環境で、「IIS Web サーバーを使用する」で動くようにしろという話ではあるが)

2013-06-19

PowerShell での Hyper-V Snapshot操作のまとめ

ポイント(=罠)がいくつかあるのでまとめた。

Snapshotの一覧を得る

Get-VMSnapshot -VMName [machineName]
唯一なにも考えなくてもいいのがこれ。

Snapshotを作成する

Checkpoint-VM -Name [machineName] -SnapshotName [snapshotName]
Checkpointを見つけるのは無理ゲーすぎる。しかもここはマシン名が-Nameなので注意。このverbいらなくない?

Snapshotに戻す (ロールバックする)

Restore-VMSnapshot -VMName [machineName] -Name (SnapshotName) -Confirm:$true
確認されたくないときは-Confirm:$falseをつける。

Snapshotを削除する

Remove-VMSnapshot -VMName [machineName] -Name [snapshotName] -IncludeAllChildSnapshots
-IncludeAllChildSnapshots がポイント。

Get-VMSnapshotしたものをRemove-VMSnapshotで受けたりもできるが、この4つの名前がわかればget-helpで戦えると思う。

2013-06-15

MSBuild Launcher 0.2.1 リリース

MSBuild Launcher 0.2.1を出しました。

一部から希望されていたフォント設定と、MSBuild Launcher自体を管理者として起動する(=管理者でビルドする)機能が登場。
前者は出力テキストを等幅に設定したいという妥当な話だけど、後者はMSBuild (Launcher)をコンソール出力つきコマンド実行ランチャーとして使うという、まがった使い方のためのもの。

たとえばこんなPowerShellとMSBuildファイルを書くと、特権で処理してその出力をMSBuild Launcherで出せる。繰り返し作業におすすめ。





以下のように、普段はエラーだけど、Adminボタンを押すと、"special work"が出力される。

2013-04-14

WinDbgとSOS拡張でVSを使わずに.NETアプリをデバッグ - 異常終了時の調査

.NET Frameworkには「SOS デバッガー拡張」という機能があり、デバッガからCLRの状態を追いかけることができる。これを使うと、重いVisual Studioを使わなくても、WinDbgで.NET Frameworkのアプリケーションをデバッグすることができる。今回は、.NETアプリが異常終了したときにその状態を調べるという方法について。

この役に立たないダイアログも、価値のあるものになるはず。


設定編

1. WinDbgをインストールする

今回はWinDbgを使うことにするので、WinDbgをインストールする。WinDbgをインストールするには「Windows 用デバッグ ツールのダウンロードとインストール」にある通り、WDKあるいはWindows SDKをインストールすればついてくる。途中でコンポーネント選択の画面があるので、デバッガのみ選べば、他のコンポーネントをインストールしないことも可能。

2. 自動デバッガの設定をする

上の「役に立たないダイアログ」の「プログラムをデバッグします」で起動するプログラムを変更する。やりかたは「Configuring Automatic Debugging」に書いてある通り、レジストリキー「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug」にある「Debugger」文字列値を追加/変更し、以下のようにする。
"C:\Program Files\Windows Kits\8.0\Debuggers\x86\windbg.exe" -p %ld -e %ld -g

x64版Windowsの場合は、SOS拡張を利用するには、実行するアプリケーションと同じアーキテクチャのwindbg.exeを使う必要があるので、上記のキーはx64版のwindbg.exeに向ける。
"C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\windbg.exe" -p %ld -e %ld -g

x86版のアプリを起動したとき向けに、WOW64側のレジストリキー「HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug」の「Debugger」文字列値をx86版windbg.exeに向けておく。
"C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64\windbg.exe" -p %ld -e %ld -g

一応、上記のパスにインストールされていた場合(=Windows8 SDKでWinDbgをデフォルト設定でインストールした場合)に使えるregファイルを置いておいた。
x64用 / x86用

Visual Studioがインストールされている場合、Visual Studioのデバッガを使うようすでに構成されているため、注意が必要(上記の設定をするとこのダイアログからVisual Studioが使えなくなる)。

これで設定は完了。

実行編

MSBuild Launcher v0.1.1には、「存在しないエディタが設定されていると、異常終了する」というバグがあるので、これを例にする。なお、ポイントとなりそうな部分は勝手に太字にしてある。

基本的には、「SOS.dll (SOS デバッガー拡張)」を見てコマンドを選ぶことになる。

1. 異常終了+デバッガ起動

MSBuild Launcherの「Settings」ボタンをクリックし、「Editor」テキストボックスに存在しないパスを入力する。その後、適当なmsbuildファイルを開き、「Edit」ボタンを押すと、異常終了し、上の役に立たないダイアログが出てくるので、「プログラムをデバッグします」をクリックすると、WinDbgが立ちあがる。ワークスペースを保存するか聞かれるので、Noを選ぶと、以下の画面になる。


2. SOS拡張のロード

上記の状態になったら以下の通り入力する。
0:000> .loadby sos clr
これは「clr.dllの横にあるsos.dllをロードする」という意味。今回のケースではすでにclr.dllがロードされているので、特にメッセージなく終了するはず。なお、「clr」とするのは.NET Framework 4の場合で、.NET Frameworkの2.0/3.xの場合「clr」は「mscorwks」とする。

今回のケースとはずれるが、ロードされていない場合、例えば起動直後の場合、
0:000> sxe ld clr
としてclrのロードで止めるよう設定して
0:000> g
で進めたあと「.loadby~」を行うか、「.load」で直接DLLの場所を指定してもOK(この場合、.NETのバージョンやアーキテクチャに注意する)。
0:000> .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\SOS.dll

これで、SOS拡張がロードされた。

3. Exceptionの内容を表示する(!pe)

「CLR exception - code e0434352」が出ている通り、Exceptionが発生しているので、最後のExceptionの内容を表示する!pe (!PrintException)を実行する。

0:000> !pe
PDB symbol for clr.dll not loaded
Exception object: 0000000003078d10
Exception type:   System.ComponentModel.Win32Exception
Message:          指定されたファイルが見つかりません。
InnerException:   
StackTrace (generated):
    SP               IP               Function
    00000000001BD130 000007FEEB0CCBF3 System_ni!System.Diagnostics.Process.StartWithShellExecuteEx(System.Diagnostics.ProcessStartInfo)+0x4a3
    00000000001BD220 000007FEEB0CD03C System_ni!System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo)+0x3c
    00000000001BD260 000007FEE9BD1C51 PresentationCore_ni!System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean)+0x271
    00000000001BD490 000007FEE9BB8BBC PresentationCore_ni!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject, System.Windows.RoutedEventArgs)+0x15c
    00000000001BD520 000007FEE91EC26D PresentationFramework_ni!System.Windows.Controls.Button.OnClick()+0xad
    00000000001BD590 000007FEE914B868 PresentationFramework_ni!System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs)+0x148
(中略)
    00000000001BE9D0 000007FEE85486DF PresentationFramework_ni!System.Windows.Application.RunInternal(System.Windows.Window)+0x12f
    00000000001BEA40 000007FEE8547CEB PresentationFramework_ni!System.Windows.Application.Run()+0xbb
    00000000001BEA90 000007FF0015024F MsbuildLauncher!MsbuildLauncher.App.Main()+0x12f

StackTraceString: 
HResult: 80004005

これでもう「System.Diagnostics.Process.StartWithShellExecuteEx」を呼んだ結果「System.ComponentModel.Win32Exception」が発生し「指定されたファイルが見つかりません。」というメッセージが出ていることがわかった。MSBuild Launcherにおいて「System.Windows.Controls.Button.OnClick」から「System.Diagnostics.Process.Start」を呼ぶところなんて限られてくるので、もうわかったも同然なのだが、もう少し調べてみる。

4. スタックのオブジェクトを一覧する(!dso)

今回の場合「InnerException」がnoneなので、そこは調べられない。SOS拡張では、!dso (!DumpStackObjects)で、スタックのオブジェクトを一覧できるので、表示してみる。
0:000> !dso
OS Thread Id: 0x1208 (0)
RSP/REG          Object           Name
r15              0000000002e69448 System.Windows.Input.NotifyInputEventArgs
00000000001BCE68 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BCF08 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BCF50 0000000003074ca0 System.Windows.EventRoute
00000000001BCF68 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BCF80 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BCF98 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BCFA0 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BD030 0000000003074ca0 System.Windows.EventRoute
00000000001BD048 0000000003078db0 System.Text.StringBuilder
00000000001BD080 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BD090 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BD0B0 0000000003074ca0 System.Windows.EventRoute
00000000001BD0B8 0000000002e69448 System.Windows.Input.NotifyInputEventArgs
00000000001BD120 0000000003078c40 Microsoft.Win32.NativeMethods+ShellExecuteInfo
00000000001BD130 0000000003078d10 System.ComponentModel.Win32Exception
00000000001BD168 0000000003078360 System.Windows.RoutedEventArgs
00000000001BD1D0 0000000003078c40 Microsoft.Win32.NativeMethods+ShellExecuteInfo
00000000001BD1F8 0000000003078860 System.Diagnostics.ProcessStartInfo
00000000001BD200 0000000003078360 System.Windows.RoutedEventArgs
00000000001BD210 0000000003078b28 System.Diagnostics.Process
00000000001BD220 0000000003078b28 System.Diagnostics.Process
(略)

太字の 「System.Diagnostics.ProcessStartInfo」オブジェクトを見ればもうすこしわかりそうなので、表示してみることにする。

5. オブジェクトの内容を表示する(!do)

オブジェクトの内容を表示するには、!do (!DumpObj)コマンドを使う。引数には、先程の「System.Diagnostics.ProcessStartInfo」のオブジェクトアドレスを指定する。

0:000> !do 0000000003078860
Name:        System.Diagnostics.ProcessStartInfo
MethodTable: 000007feeab807a0
EEClass:     000007feea86a628
Size:        128(0x80) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feeb866738  4002fc9        8        System.String  0 instance 0000000003078808 fileName
000007feeb866738  4002fca       10        System.String  0 instance 0000000003078aa8 arguments
000007feeb866738  4002fcb       18        System.String  0 instance 0000000000000000 directory
000007feeb866738  4002fcc       20        System.String  0 instance 0000000000000000 verb
000007feeabb2ae8  4002fcd       68         System.Int32  1 instance                0 windowStyle
000007feeb86d450  4002fce       6c       System.Boolean  1 instance                0 errorDialog
000007feeb873318  4002fcf       60        System.IntPtr  1 instance                0 errorDialogParentHandle
000007feeb86d450  4002fd0       6d       System.Boolean  1 instance                1 useShellExecute
000007feeb866738  4002fd1       28        System.String  0 instance 0000000000000000 userName
000007feeb866738  4002fd2       30        System.String  0 instance 0000000000000000 domain
000007feeb87e6d0  4002fd3       38 ...rity.SecureString  0 instance 0000000000000000 password
000007feeb86d450  4002fd4       6e       System.Boolean  1 instance                0 loadUserProfile
000007feeb86d450  4002fd5       6f       System.Boolean  1 instance                0 redirectStandardInput
000007feeb86d450  4002fd6       70       System.Boolean  1 instance                0 redirectStandardOutput
000007feeb86d450  4002fd7       71       System.Boolean  1 instance                0 redirectStandardError
000007feeb873738  4002fd8       40 System.Text.Encoding  0 instance 0000000000000000 standardOutputEncoding
000007feeb873738  4002fd9       48 System.Text.Encoding  0 instance 0000000000000000 standardErrorEncoding
000007feeb86d450  4002fda       72       System.Boolean  1 instance                0 createNoWindow
000007feeb887510  4002fdb       50 System.WeakReference  0 instance 0000000000000000 weakParentProcess
000007feeab80948  4002fdc       58 ....StringDictionary  0 instance 0000000000000000 environmentVariables

「fileName」が使えそうなので、さらに表示してみる。

0:000> !do 0000000003078808
Name:        System.String
MethodTable: 000007feeb866738
EEClass:     000007feeb3eed68
Size:        86(0x56) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      C:\Windows\invalid-notepad.exe
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feeb86c620  4000103        8         System.Int32  1 instance               30 m_stringLength
000007feeb86b160  4000104        c          System.Char  1 instance               43 m_firstChar
000007feeb866738  4000105       10        System.String  0   shared           static Empty
                                 >> Domain:Value  00000000002dafa0:0000000002a11420 <<

これで、「C:\Windows\invalid-notepad.exe」という文字列がfileNameに入っていることがわかった。これでは実行できそうもない。

---
と、このような感じで、異常終了時の例外情報を調べるくらいならわりと簡単にできる。.NETプログラマなら覚えておくのがおすすめ。

本当は、AppDomainの中を旅するだけの機能もついているのだけど、それはまた機会があれば。

2013-03-20

Loqui 0.5.5リリース/LoquiのISO-2022-JP半自前変換の仕組み

Loqui 0.5.5を出しました。受信時に行なっていたISO-2022-JPの半自前変換を、送信時にも行うようにしました。ただし、受信時と異なり、「半角カナ」などの文字は、エラーにします。

これもまたSolaris用で、Solaris iconvでUTF-8からISO-2022-JPに変換すると、IRCNet的に困ったエスケープシーケンスをつけてしまうことへの対応です。Solarisで起きる現象については、この一連のスレッドにまとまっています(もう少しするとopensolaris.orgがなくなるので消えてしまうのですが…)

GNU iconvではこのようなことがないので、Linuxユーザの方は今までのままで大丈夫です(0.5.5からLinuxでも自前になるので、かえってあやしいかもしれません。うまく変換できていたのにいかなくなったケースがあれば教えてもらえると助かります。)

さて、せっかくなのでずっと前から実装されていた半自前変換について書いておこうと思います。UTF-8⇔ISO-2022-JP変換をする人の参考になれば。(パフォーマンスはよくないし、ISO-2022-JP-2004なども視野に入れるとやることが増えるので、対応できるケースは限られるのですが…)

Loquiの半自前UTF-8⇔ISO-2022-JP変換


Loquiでは、アカウント設定の「コード」の「一覧から選択する」で「Japanese」を選んだ場合、あるいは「ロケール情報から自動判定する」を選んで「ja_JP」から始まるlocaleで利用している場合、(ただのiconv呼び出しでない)ISO-2022-JP向けの文字コード変換ロジックが動きます。

この変換ロジックはいわゆる「半角カナ」や機種依存文字(の一部:NEC特殊文字(13区))を受信しても化けずに表示させるためのものなのですが、ざっくり言うと、「iconvが失敗しそうな文字は自前で変換」「そうでない文字はiconvに変換してもらう」(半自前変換)という処理になっています。ただし、以下の図のような、ちょっと変わった流れをしています。


Gtk+(2以降)は、画面に表示するためにUTF-8を要求するのですが、日本語でIRCを使おうとすると、ISO-2022-JPを使っていることがあるので、この場合ISO-2022-JPからUTF-8に変換しないといけません。pureにISO-2022-JPのバイト列が来るならGLibのiconv wrapperでさくっと変換するだけで良いのですが、先の「半角カナ」があったりするので、手を入れないといけないわけです。

まぁ、変換処理を自前で持とう、という話になるのですが、ISO-2022-JPは漢字にJIS X 0208という文字セットを使っているのに対し、UTF-8はUnicodeなので、基本的には1文字1文字の変換テーブルを持つ必要があり、いろいろな意味でちょっとつらいです。そのため、「特殊な対応が必要な文字だけ自前で変換し、そうでないものはiconvに変換してもらう」というアプローチを考えます。

ところが、そうすると1文字1文字変換する必要がでてきますが、困ったことにISO-2022-JPは「ここからJIS X 0208の漢字だよー」といったような、文字セットの呼び出しがあり、コンテキストに意味をもったエンコーディングなのです。そのため、ISO-2022-JPのバイト列のままiconvに渡そうとすると、特殊な文字が入ってきたりこなかったりして、状態の管理がちょっとしんどくなります。

そこでどうするかというと、いったんISO-2022-JPからEUC-JPに変換します。EUC-JPでもJIS X 0208を使っているので、ISO-2022-JPからは計算式的に変換できる一方で、EUC-JPはISO-2022-JPと異なり、持続する文字セットの呼び出し(コンテキストの永続的変更)がない(次の文字だけ変更というのはあります)ので、状態の管理が簡単になります。これが上図のようなちょっと変わった流れをしている理由です。

詳しく知りたい方は、loqui_codeconv_tools.cを見てください。

ちなみに、Loquiはこういった言語ごとの特殊ロジックとlocale名の対応テーブルを持っています。10年以上に渡り、日本語以外に使われたことはないのですが…

余談

0.5.5を出してこの図を描こうと思ったら、いつのまにか横道にそれてました

2013-03-12

LibreOffice用カラーテーブルを作った

[2014/12/14追記] LibreOffice 4.2以降では、12色になったことによってこの8色版はまだらになってしまいます。12色対応版をどうぞ

LibreOfficeは、もうちょっとした表や図を作るには十分なのだけど、デフォルトだと色が選択しにくい。いくつかプリセットがあるもの、どうもしっくりこなかったので、自分で作った。






ダウンロードはここから: https://github.com/sunnyone/locolor/raw/master/sunnyone.soc

作ってみたはいいものの、使い勝手がいいかどうかはまだわからない。

特徴

色相と明度/彩度の2軸で選択可能

デフォルトのカラーテーブルは一部そういう部分もあるものの、表で見たときけっこうまばらなので選びづらい。


順番に並んでいるカラーテーブルもあるのだけど、横8列であることを意識して作られていないので、まだらになってしまっている。

同じ色は縦に並んでいる(似通った濃さは横に並んでいる)

LibreOfficeは一番上のスクリーンショットの通り、2通りの色選択のUIがあり、リスト形式の場合は表の横の順に8つ出てくる。つまり、表の横1列が表示される。オフィスソフトで色を選択するときは、色相よりも先にトーン(濃さだとか)が決まっていることが多いので、同一トーンのものが一画面に出てくると選びやすい(はず)。

使い方

一時的に試してみたい場合は、適当に図を挿入して、右クリック→「領域...」でダイアログが出てくるので、「色」タブからフォルダのアイコンをクリックして出てくるファイル選択の画面でsunnyone.socを選べばOK。



デフォルトの設定にしてしまいたい場合は、LibreOfficeをいったん閉じたあと、configのディレクトリ(最近のWindowsならC:\Users\(Username)\AppData\Roaming\LibreOffice\4\user\config)のstandard.socをバックアップした後、入れ替えればOK。

作りかた

上の配色が気にいらない場合でも、このカラーテーブルの作りかたは参考になるかもしれないので、一応書いておく。

1. 色相を選択する

マンセル環から色をチョイスする。マンセル表色系の色相は、5色とその間の5色、さらに倍…という感じなので、8色はちょっとつらいんだけど、がんばって4色+補色を選んだ。


2. 彩度/明度を選択する

マンセル表色系では、色相によって最高彩度が違うのでしんどいのだけど、概ね横の三角形の形をしているので、三角形の頂点を決めたあと、間の点を機械的に選んだ(実際はマンセルの等色相面はいびつな形をしているので、本当はない色があるかもしれない)。



詳しくはレポジトリに置いてあるシートを参照。

3. Color::Model::Munsell::Utilを使ってマンセル値からRGB値に変換

マンセル表色系に対応しているライブラリはけっこう少ないのだけど、PerlのColor::Model::Munsell::Utilは対応していたので、これで変換した。
マンセル値は直接RGBにはできないので、テーブルでCIE-XYZに変換して、そこからsRGBに変換している(はず)。
出力はLibreOfficeで使っている簡単なXMLにするだけで、完了。

詳しくはリポジトリに置いてあるスクリプトを参照。

Q&A

なんでPCCSじゃないの?

色彩+トーン(彩度・明度)という考え方は、まさしくPCCS向けなのだけど、PCCSは(恐らく)物の色向けで、かつトーンの名前が人の感覚でつけられているので、RGBの世界に持ってくると、この手の世界になじみがない自分にはちょっと違和感があった。なので、類似した感じのマンセル表色系で色をチョイスした。

↑これが、「v2」というvトーンの赤、つまりvividなred (4R 4.5 / 14)をRGBに変換した色なんだけど、画面で見るとにぶく見える気がするのよねぇ。

機械的に計算するならHSVのほうがいいんじゃ?

できたあとに思った。実験してみてないのだけど、高明度の色は、HSVで機械的に出したほうがきれいな薄い色になったんじゃないかなーと思ったりもする。

が、マンセル値にしておけば、表記が人の理解できる範囲になると思うので、これはこれでいいかなと思っている。

なんで色を選ぶUIが2種類あるの?

ひとつだったらもう少し作りやすかったのに…

2013-03-08

MSBuild Launcher 0.2.0 リリース

MSBuild Launcher 0.2.0が出ました

0.1.xのヘンテコなJSON記法は廃止し、プロパティはファイルから取るようになりました。
右のFile Propertiesには、ImportedだとかSpecialなプロパティは出てこない(あると出すぎる)ので、
もし必要であれば、Settingからプロパティ名を追加してください。特殊なプロパティも定義されていれば表示されます。

あと、インストーラができたので、そのほうが好きな方はどうぞ。関連付けができます。
ただ、一度手動で関連付けていると、関連付かないことがあるので、そのときはいったんアンインストールして
HKCRのゴミを消してからまたインストールしてみてください(ちょっとひどい話ですが)。

---
WiXでのインストーラの作り方も記事にしようかと思ったんだけど、あまり「これだ!」という感じにならなかったので、見送り。

2013-02-19

MSBuildからAssemblyInfoを生成する

結論から言うと、MSBuild Community TasksAssemblyInfoタスクを使えばできる。

おすすめじゃない方法

おすすめじゃないけど簡単な方法として、既存のAssemblyInfo.csを置き変えてしまう方法がある。
Community Tasksの.targetsをImportしたあと、以下の感じのターゲットを作れば、既存のAssemblyInfo.csを置き変えることができる。



しかし、この方法ではプロジェクトが複数あった場合に、プロジェクト別に値を設定することができない。
これを作ったあと、Community Tasks的におすすめな方法があることがわかった(雛形がある)。

おすすめの方法

ざっくり言うと、GlobalAssemblyInfo.csを作り、それを参照する。

1. GlobalAssemblyInfo生成ターゲットを作る

Community Tasksをインポート後、このようなターゲットを作る。


次のプロセスのために1回実行しておく。

2. GlobalAssemblyInfo.csをリンクとして追加する

各プロジェクトで、GlobalAssemblyInfo.csを追加する。Visual Studioからは、「追加>既存の項目...」で追加するが、
追加ボタンの右の▼を押して、リンクとして追加するのを忘れない。


3. 既存のAssemblyInfo.csから重複する値を削除する

GlobalAssemblyInfoに定義した値は、既存のAssemblyInfo.csから削除しておく。

これで、各プロジェクト個別の値をセットすることを可能にしつつも、バージョン等々をMSBuildから管理できるようになった。

GlobalAssemblyInfoの情報を取得する

アセンブリの情報は、リフレクションで取得することが可能だが、GetCustomAttributesが冗長な記述を要求したりして面倒。
しかし、AssemblyInfoタスクで、GenerateClass="true"にしておくと、「ThisAssembly」クラスを作ってくれる。
そのため、以下のようなシンプルな形でコードから情報を取得可能。

  string product = ThisAssembly.AssemblyProduct;

2013-02-09

PowerShellを使ってインストールされたファイルのパスからプロダクトを調べる

rpm -qf /usr/bin/hogehogeや、dpkg -S bin/hogehogeなどとしてファイルパスからどのパッケージに入っているのか調べることありますよね?そのWindows版です。

(残念ながら入れないといけないのですが)Windows Installer PowerShell Moduleをインストールして、トップページに書いてある通り、PowerShellから以下のように打てばOKです。
PS C:\> Import-Module msi
PS C:\> Get-MSIComponentInfo | where { $_.path -eq "C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramew
ork\v4.0\System.dll" }  | Get-MSIProductInfo

ProductCode                            ProductVersion      ProductName
-----------                            --------------      -----------
{CFEF48A8-BFB8-3EAC-8BA5-DE4F8AA267CE} 4.0.30319           Microsoft .NET Framework 4 Multi-Targeting Pack

Windows Installer (msi) で入っていないものには使えないですが、参考になるかもしれません。

2013-02-06

MSBuild Launcher 0.1.0 リリース

最近またMSBuildをちょっと使うようになったので、MSBuild Launcherの新版をリリースしました。
  http://msbuildlauncher.codeplex.com/
githubダウンロード機能削除を受けて、これもCodeplexに移行です。

あと、プロパティ編集機能という大き目の機能がついたので、0.0.3ではなく0.1.0になりました。

MSBuildファイルの中のコメントに以下の感じのJSONを書くと、右側のペインにテキストボックスかコンボボックスが現れます。


本当はオレオレnamespaceを用意してオレオレ属性をプロパティのタグにつけたかったんだけど、そういうXMLファイルは食べてくれなかったので仕方なく。コメントの中にXMLが現れるとまたカオスなことになりそうなので、いっそJSONということでJSONになりました。

ちなみに上の「Common Properties」は実行ファイルと同じ場所にあるCommonProperties.jsonというファイルにJSONが書かれています(編集可能)。

これらのプロパティは、変更したものだけ(=右側のトグルボタンがオンになっているときだけ)ビルド時に指定されるようになっています。


あとは、似非Editボタン(.xmlに関連付いたプログラムを起動する)とか、既定のターゲットを実行するBuildボタンがついたりしました。

[2013/2/7追記]
いくつかバグってたので直して0.1.1を出しました。疑似Editボタンは、設定を用意してちゃんと(?)Editボタンになりました。

[2012/2/9追記]
MSBuild LauncherのビルドをMSBuildでやるようにした関係もあって、0.1.1はAnyCPUにしたんだけど、x64環境ではx86のアセンブリがロードできずに動かないケースがあるとのこと。 そりゃそうだ。ということで、0.1.2が出て、x86に戻りました。うざったいメッセージボックスもログウィンドウに出してうざくなくしたよ。


2013-01-27

Loqui 0.5.4 released (bug fix for Solaris11)

久々に出しました。Loqui 0.5.4です。ほぼほぼSolaris11で動くようにしただけなので、すでに動いてる環境の方々は別に上げなくても大丈夫です。具体例がSolaris11ですが、特殊対応をしたわけではなく、「これだと裏でunsigned使われてたらうまくいかないよなぁ」という感じのものを直しただけなので、もしかしたら前は動かなかったけどこれで動くようになったプラットフォームがあるかもしれません。

aboutの画面を書きかえたときに、「Copyright (C) 2002-2013」というのを見て、ブランクがあるとはいえ結構な時間たってるんだなーと思ってちょっと驚いた。もう10年以上経つのね...

2013-01-08

ドラッグした範囲をキャプチャしてMediaWikiに上げるツール「ScreenToWiki」を作った

MediaWikiは画像のアップロード面倒だよねーという話があったのですが、「MediaWikiほどにもなればAPIついてるんじゃね?」と「WPFで全画面に透明ウィンドウ張れば、gyazo的範囲選択も別に難しくないよね」「画像保存もKiritoriMageの感じでやればいいよね」となったので、「Wikiにいきなりアップロードするツール作るの簡単じゃね?」ということで作ってみました。その名もScreenToWiki

ダウンロード

ダウンロードはこちらから。
例によって.NET Framework 4.0が必要です。

使い方

使い方は、実行すれば選択範囲の選択がでてくるので、ドラッグで選んだあと、WikiのURLとかユーザ名とかを入力すればアップロードできます。gyazoだと思えば概ねOKだと思います。ただ、エラーハンドリングは弱いので、なにかあるとあまりわかりません…。

パスワードの保存は、人が見えない程度にしか変えない(Base64するだけ)ので、まったくおすすめできないです。セキュリティはWikiごとの事情があると思うので、事情に応じておねがいします。

MediaWiki 1.16以降でないとuploadのAPIがないそうなので動きません。Ubuntu 12.04が1.15でしばらく悩みました。

その他

MediaWikiしか使えないのにToWikiはおかしいじゃないかって?今のところその通りです。

でも他のものにも対応できるようにMEFでクラスを取ってくるようにしているので、IImageUploaderを実装したクラスを作れば他のWikiにもアップロードできますよ! Wikiでなくてもおもしろいかも。

もともとGitHubであげようと思っていたのですが、Goodbye, Uploadsということで、アーカイブのアップロードがなくなってしまったので、オープンソースなWindows系ソフトだったらcodeplexかなぁということでCodeplexに載せてみました。ダウンロードが目立つのでユーザには使いやすいかも。