CATEGORY:.NET
何の因果か、諸事情により生まれて初めてDirectXなる物を触った。C#で。DirectShowLibってのを使ってDirectShowです。DirectShowって、何?っていうレベルなんだけどね。
しかし、.NETでもCOMが使えます!なんつってもデリケートなトコはそんな変わんないからあまりうれしくない。まあExcelを使ったときの隅から隅までReleaseComObject地獄よりはマシだったけど。
例えばね。文字列の配列があって、それを特定の文字で埋めたい。そんな欲求。pythonだと、
s = [0] * 10
#ってのがあったとき、
s = ['X'] * 10
#でいい、のか?
s = ['X' for x in s]
#でも大丈夫?
s = map(lambda: 'X', s)
#みたいな感じでも、まあ出来るっちゃあ出来るのか。
とまあね、多分こういう方法があるんですよ。正直pythonてまだよく分かってないんだけど。
で、だ。VBですよ。VB.NETで同じ事をする場合は、どうしたらいいの?勿論、ループを使わずという事なんだけど。.NET Frameworkライブラリの2.0からArray.ForEachなんてのが出来たらしいけど、これ戻り値無いんだよね。んで、渡すジェネリックの定義も値渡しだから配列を書き換えるメソッドも渡せない。まあそりゃ無茶な気もするけど。どうにかならないのかしら。
Windowsのグローバルフックで、ローレベル(WH_MOUSE_LLとWH_KEYBOARD_LL)フックはDLLを使わずに出来るということを今更ながら知った。衝撃だ。記事の日付がかなり以前であるし、Windowsの開発者達には結構知られていたのだろうか。自分のアンテナの低さにビックリしたし、何より仕事上の説明でグローバルフックは各プロセスがDLLをロードして云々...なのでそのプロセスがアタッチ出来るようネイティブのDLLを作らないとダメですよ、なんて説明を訳知り顔でしていた自分にも更にビックリした。いいけど。もういいけど。まあね、今更そんなこと言われてもね、知りませんよって話ですよね。うん。見なかったことにしよう。
.NET Framework(1.1だけ?)のSplitterクラスが賢くない。Splitterって、何?っていうと、2ペインとかのウィンドウで使われてるヤツで、ウィンドウ内のコントロールの幅をね、ドラッグして変えられたりね、するアレですよ。アレ。アイツがね、スゲー賢くない。何が賢くないかと言うと、SplitterをドラッグしてるときにAlt+Tabでアプリを切り替えるとおかしな事になるのです。ほぼ全てのキーイベントをSplitterがガッチリ横取りしてしまうのですよ。いや分かんないけど。少なくとも他のコントロールがキーイベントを受け取れなくなります。例を挙げて説明します。
ノータッチデプロイメントとClickOnceはどう違うのだろうか?と、未だ.NET Framework1.1で開発しているワタシは思うのであります。ClickOnce!ああ!なんて魅惑的な響きでしょうか!酷く憧れるのであります。何故かというと、ノータッチデプロイメントではWEBサーバ上のアセンブリを検索するときに、アセンブリの拡張子は大文字であるとして検索しに行きやがるからであります。WEBサーバがLinuxとかで動いていると、拡張子が小文字のアセンブリは検索に引っかかってくれないからであります。じゃあアセンブリを作るときに拡張子を大文字にすればいいじゃねーかという気もしますが、Visual Studioで何も考えずにアセンブリを作ると、拡張子が小文字になるのであります。意味が分からない。Linux殺しじゃないか。
だから、ノータッチデプロイメントじゃなくてClickOnceにしたいのです。ClickOnceでこの問題が解決されているかは知らないのだけれど。ClickOnceに。一縷の望みを託して。シンボリックリンクを張るスクリプトとか書くのアホらしいもの。
.NET FrameworkのControl.GetNextControlメソッドが無限ループするケースがあるという事を、声を大にして言いたい。のだけれど、コレを再現させるテストプログラムを作ろうとすると結局無限ループしなかったりという事になって、どうにももどかしい。
.NET FrameworkのControlは、Dispose時に自身を親のControlCollectionから削除させる。んで、この削除を行うControlCollection.Removeというメソッドは、コレクションからコントロールを削除した後、AfterControlRemovedというメソッドを呼び出すのだけれど、そこでアクティブなコントロールの設定が行われる。コントロールが削除されアクティブなコントロールが無くなるのを防ぐ、という事なのだろう。まあいいよ。それはいいよ。しかし、その処理、SelectNextControl(内で呼ばれるGetNextControl)で無限ループが起きるのよ。次のコントロールを延々探し続けるのよ。もの凄い勢いで探し続けるのよ。彼ってば全然諦めないのよ。それが若さか!ってなもんなのよ。そりゃないよ。どういったケースでそれが起きるかというと、前述の通りハッキリさせることが出来ていません。所謂八方塞がりというヤツです。困ったワタシはキーボードの掃除などを始めてみたものの、問題の解決には至りません。何故かというと、キーボードとは多分関係ないからです。マウスの掃除もしましたが結果は同じ。理由も同じです。これ参ったなぁ。
.NET FrameworkのXMLシリアライズ(SOAPも含む)を使用したアプリケーションが、最初のシリアライズ時にフリーズすることがあります。何で?というと、XPのバグらしい。XmlSerializer クラスから起動された csc.exe が一定時間応答を停止する場合がある
と。そのままです。さり気なく致命的です。どうしてそうなるのかというと、
XmlSerializer クラスは自クラスで使用するアセンブリの動的なコンパイル処理を行うために csc.exe を起動します。csc.exe はコンソールアプリケーションのため、Console IME が起動していない場合、コンソールでの日本語入力支援機能として Console IME を起動します。この時、Console IME 起動時の処理でデッドロックが発生しその結果 csc.exeが停止した状態になる場合があります。この現象発生時には、最終的に XmlSerializer を使用するプログラムが一定時間応答を停止した状態となります。
そういうことらしい。うん。やっぱり致命的ですね。さて。解決策は二つ。レジストリを弄ってコンソールでconime.exeが起動されないようにするか、XMLシリアライザをプリコンパイルし、動的にアセンブリを生成しないようにするか。レジストリを弄るわけにもいかないし、プリコンパイルしたアセンブリを使うにも、実行する全てのマシンにパッチをあてないと動かない気がした。以前に別件で試したけど、パッチ当たってないマシンだとXmlSerializerAssemblyAttributeが使えないから動かないんだよね。当たり前だけど。
じゃあどうすんのよ?
こまったさんのカレーライス、知ってるよね?大丈夫だよね?うん。じゃ。
.NET Frameworkには.NET Remotingという機能(?)がある。全体としての定義はぶっちゃけよく知らないのだけれど、異なるプロセス間で通常のメソッド呼び出しが出来ちゃうのですよ。呼び出す対象をipとポートで指定するので、異なるマシン間でもメソッドが呼び出せるという香ばしい機能です。
さて。今日、そいつを使ってちょっと困った問題にぶち当たりました。何が問題かというと、通信のサーバ側で特定のポートをlistenするのですが、そのサーバで別プロセスを実行し、その実行したプロセスを終了せずにサーバを終わらせると、ポートのlistenが終了しないと。だから、もう一度サーバを立ち上げて同じポートをlistenしようとするとbindに失敗して残念な結果に、というものです。えええ、何それ?第一誰がlistenしてんのよ?Frameworkが頑張ってんの?
取りあえず原因が分からないので放って置いたんだけど。で、今以下のようなテストコードを書きました。あ、クライアントコードは必要ないのでありません。
public class Test : MarshalByRefObject {
public static void Main() {
Test obj = new Test();
Process p = null;
try {
p = Process.Start(@"C:\WINDOWS\system32\notepad.exe");
}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
}
finally {
if (p != null)
p.Close();
}
}
TcpChannel chan;
public Test() {
chan = new TcpChannel(8085);
ChannelServices.RegisterChannel(chan);
}
}
かなりガムシャラですが、極限まで削るとこういう事で再現できるはずです。ポートを開いて別プロセスを立ち上げて何もせずに終了。作ったexeを一回実行して終了したらそのままもう一回実行。そうすればTestのコンストラクタで例外が発生するハズ。そのハズでした。が、何事もなく起動。アレ?netstat -aで見ても、8085をlistenしてる人はいません。ぬーーーーん。余りに簡単過ぎるかと思って、Formを使ってみたりと色々やったけど結果再現せず。なーんでーやねーーーーん。UnregisterChannelとかStopListeningとか、色々足掻いてダメだったのに。こういうの、困るよね。再現できるコードが出来ないと問い合わせも出来ない。かといって製品のコードをビローンと見せるわけにもいかないし。狼少年になった気分だよ。オッサンだけど。
.NET Frameworkのアプリで、キーバインドを設定可能にする。設定ファイルで読み書きするキーコードを、標準で用意されているKeysという列挙で行おうとするのは自然な考えであるハズだ。キーコードを数値で書き出すより分かり易いし、読み込んでそのまま使えるからね。
オレメモ。ノータッチデプロイメント+Apacheでアプリに引数を渡そうとする。
http://aaa.com/bin/APP.exe?foo=bar
そうすると、.configファイルを取得するのに/bin/APP.exe?foo=bar.configというリクエストを投げる素敵な.NET Framework君。志村ー!余計なの付いてる!!で、そんなイカしたナイスガイへの対処法。
mod_rewriteでURLでアプリに引数を渡しつつ.configファイルを取得する。
RewriteEngine on
RewriteBase /bin
RewriteCond %{QUERY_STRING} .*\.config
RewriteRule APP\.exe.*\.config$ APP.exe.config [L,PT]
# alias /bin 配置パス