2009年4月11日土曜日

ToolStripMenuItem.CheckOnClick

こんな機能が欲しかった!
ToolStripMenuItem.CheckOnClickより

ToolStripMenuItemが自動的にチェックされた状態で表示され、クリックしたときにチェック解除されるかどうかを示す値を取得または設定します。
...
クリックしたときにToolStripMenuItemが自動的にチェックされた状態で表示される場合はtrue。それ以外の場合はfalse。既定値はfalseです。
何か矛盾してる。ソースコードを追ってみたところ、前半はウソ。後半が正しい。もう一度、引用しよう。
クリックしたときにToolStripMenuItemが自動的にチェックされた状態で表示される場合はtrue。それ以外の場合はfalse。
翻訳すると、trueにした場合の振る舞いとして、このメニューをクリックするとチェックが付く…チェックを外す方法については言及していません。

大事なことなので2度言いましたよ。

2009年4月4日土曜日

C#でできることはC++/CLIでもできる

私にもそう思っていた頃がありました。
ADO.NET周りに新機能が多くて何か使ってみようと思って調べてみました。

Data Entity Framework
C#とVB.NETのみ。code generatorがC++/CLIに対応してない。ちなみにVisual Studioが生成するファイルとcode generatorが引数に要求するファイルは異なるので自分で処理するのは面倒。次バージョンに期待。
SQL Server Compact 3.5 SP1
C++/CLIからも使用可能。やったね☆
Linq to SQL
さすがにC#のような構文拡張はC++/CLIに期待しないとして…C#とVB.NETのみ。code generatorがC++/CLIに対応してない。更にSQL Server Compact 3.5 SP1はLinq to SQLに未対応。
型指定されたDataSet
C#とVB.NETのみ。code generatorがC++/CLIに対応してよくわからないエラーを吐く。そのためなのか、Visual Studioでも「新しい項目の追加」のテンプレートからも外されている。
Linq to DataSet
型指定されたDataSetが作れない時点で終わってます。
番外編…Settings.settings
動いてるような、動いてないような。型指定されたwrapperクラスを作ろうとSettings.hファイルを作成しstdafx.hに書き込むところまで自動でやってくれます。Settings.hファイルの中身? しらんがな。そのためなのか、Visual Studioでも「新しい項目の追加」のテンプレートからも外されている。

C++/CLIはnativeと.NETとの橋渡し程度に考えておくべきかもしれません…。

2009年4月2日木曜日

逆double thunking

double thunkingに逆も何もないけどなんとなく…。

状況としては次の関数をnative C++でコンパイルしa.dllに入れます。

__declspec(dllexport) LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam );

そしてa.dllにリンクするb.exe内でC++/CLIを使って次の呼び出しをします。
HINSTANCE module = GetModuleHandleW( L"a.dll" );
SetWindowsHookExW( WH_CBT, CBTProc, module, 0 );
するとどうなるか。

コンパイラは単なる関数ポインタCBTProcをmanaged codeから呼べるようwrapします(1段目のthunk)。
次にwrapされたmanagedな関数ポインタをunmanaged codeから呼べるようにwrapします(2段目のthunk)。
この2重にthunkされた関数ポインタをSetWindowsHookExW()に渡します。

#pragma unmanagedとか試してみましたが変化しませんでした。結局、この部分だけソースコードを独立させ、/clrコンパイルオプションを外して強制的にnative C++としてコンパイルすることで回避できました。もっとsmartな方法がありそうですが、見つけられなかった。

2009年3月29日日曜日

/NODEFAULTLIB:msvcmrt.lib

どこかでVS2008のC++/CLIだと.NET Frameworkを使用しているのにVC++ランタイムライブラリとの依存関係が切れなくて、結局VC++ランタイムライブラリもインストール必要になってしまう&x86とx64で共存できない、というような記述を見かけた…気がしました。
後になって探したのですがどこで見かけたのやら。

で、方法 : CRT ライブラリ DLL との依存関係を削除して部分信頼アプリケーションを作成するによると/NODEFAULTLIB:msvcmrt.libを指定することにより依存関係を切れるとのこと。ただしこれでは必要な処理が足りていないのでptrustm.libかptrustmd.libのどちらかとリンクすること。

えっとこの.libによってx86かx64のどちらかに固定されてしまうのか。でも.NET Frameworkだけで動作できるようになる、VC++ランタイムライブラリのインストール不要となるならそれはそれで大きいかな。

あ、ちなみに結果がどうなるか試してません。

2009年3月28日土曜日

zh-Hansとzh-CHS

カルチャには特定カルチャとニュートラルカルチャとインバリアントカルチャがある。
特定カルチャはja-JPとかen-USとか、言語+地域情報を持つもの。
ニュートラルカルチャはjaとかenとか、言語だけで地域情報を持たないもの。特定カルチャで完全一致できなかった場合にニュートラルカルチャにフォールバックします。
インバリアントカルチャは言語も地域も表さないもの。「要するに、体系を体系たらしめるために要請される意味の不在を否定する記号なんだよ。そのアナログなのが神で、デジタルなのがゼロ。どうかな?」

で、ニュートラルカルチャには唯一の例外としてzh-CHSとzh-CHTがある。中国語には簡体字と繁体字があるから。そしてこのカルチャ名はWindows Vistaからzh-Hansとzh-Hantに変更されてたりする。

  • Windows XP上の.NET Framework 2.0 SPなしだとzh-Hansを認識しない
  • Windows XP上の.NET Framework 2.0 SP1以降だとzh-Hansを認識し、zh-CHS→zh-Hansの順でフォールバックする
  • Windows Vista上の.NET Framework 2.0 SPなし(SP1以降も)zh-CHSを認識し、zh-CHS→zh-Hansの順でフォールバックする
結局の所、Windows XPを意識するならzh-CHSを使うことになるが、例えば.NET Framework 3.5 SP1 Client Profileだと.NET Framework 2.0 SP2を含むのでzh-Hansでもいいかもしれない。

2009年3月22日日曜日

自作ツールのWindows 7対応

対応に向けて調査を始めました。途中で飽きたらそのまま放置になりますが…。
まず今のツールはUIを設計する気がないため設定項目は全てiniを使い、タスクトレイに置いたアイコンのメニューから最低限の操作ができるようになっています。
Windows 7ではタスクトレイはデフォルトで非表示なので困ってしまうため抜本的な見直しを行うことにしました。

Windows Live Messengerがtaskbarを使いこなしているためこれを参考に調査を進めます。まずWindows 7環境ではこんな感じ。

タスクトレイにはアイコンが出なくなります。メインウィンドウの他にもう一つウィンドウが存在するような。そしてタスクバーを右クリックするとこんな感じ。
プログラムから好きなメニューを登録できます。ちなみにこのメニューはスタートメニューにも表示されてこんな感じ。

さてメインウィンドウを閉じるとこんな感じ。

やはり何かいるようです。spyで見ると


とんでもない座標に隠しWindowがいました。これを参考にしてみようと思います。

2009年3月19日木曜日

二項係数

どこかの影響を受けて書いてみました。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>二項係数</title>
<base href="http://ajax.googleapis.com/ajax/libs/dojo/1.2.3/" />
<link rel="stylesheet" type="text/css" href="dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css" href="dijit/themes/soria/soria.css" />
<script type="text/javascript" src="dojo/dojo.xd.js" djconfig="parseOnLoad: true"></script>
<script type="text/javascript">
// <![CDATA[
dojo.require("dijit.form.NumberTextBox");
var MAX = 10000000;
function onChange() {
var n = N.attr('value');
var k = K.attr('value');
if (isNaN(n) || isNaN(k) || k > n)
return;
k = Math.min(k, n - k);
if(k == 0)
k = 1;
else {
var numerator = [];
for(var i = 0; i < k; i++)
numerator.push(n - i);

for(var i = 2; i <= k; i++) {
var j = i;
for(var p = 2; j > 1; p++) {
while(j % p == 0) {
j /= p;
for(var l = 0; l < numerator.length; l++) {
if(numerator[l] % p == 0) {
numerator[l] /= p;
break;
}
}
}
}
}
var result = [1];
dojo.forEach(numerator, function(i) {
var rest = 0;
for(var j = 0; j < result.length; j++) {
var k = result[j] * i + rest;
result[j] = k % MAX;
rest = (k - result[j]) / MAX;
}
if(rest > 0)
result.push(rest);
});
k = result.pop().toFixed();
dojo.forEach(result.reverse(), function(i) {
k += (i + MAX).toFixed().substr(1);
});
}
dojo.byId('result').innerHTML = k;
}
// ]]>
</script>
</head>
<body class="soria">
<h1><sub>n</sub>C<sub>k</sub></h1>
n = <input type="text" dojotype="dijit.form.NumberTextBox" jsid="N" value="0"
required="true" constraints="{fractional: false, min: 0}" intermediatechanges="true" onchange="onChange" /><br />
k = <input type="text" dojotype="dijit.form.NumberTextBox" jsid="K" value="0"
required="true" constraints="{fractional: false, min: 0}" intermediatechanges="true" onchange="onChange" /><br />
<span id="result"></span>
</body>
</html>