My Daily Programming Life...

仮想メモリとアドレス変換

難しい・・・きちんと理解できない。たぶんまだ知識不足だな。
プロセスメモリ空間(論理アドレス)→(Intel x86の場合)セグメンテーション→リニアアドレス→ページング(PTEなどを経由)→物理アドレス・・・なのだと思う。きっと・・・。
よ くわからないのは、x86のセグメンテーションの部分。Windowsのメモリ管理の解説を読むと、たいていこの部分は飛ばしてあるように見える。ページ ングの仕組みがメインなので、ある意味自動的に行われるセグメンテーションは飛ばしているのかもしれない・・・。最初はセグメンテーションは利用しないの かと思った。
この辺がきちんと説明できるようになりたいなぁ。CPUに関しては「はじめて読む486」っていうすばらしい本があって、結構昔に 読んだ。でも実際OSがどんな風に利用しているかはきちんと知らずにいたので、ここへきてちゃんと理解しようと思っていろいろ読んで、かなりいい線まで来 たと思うのだけれど・・・。CPUの機能で実装されている部分と、OSの機能で実装されている部分と、CPUの機能をOSが利用して実装されている部分の 区別がいまいちはっきりつかない。でも結局はすべてCPUの機能をOSが利用しているってことか・・・。
もうちょい勉強が必要。

2009/7/1 追記
前のブログを読み直して、これを見つけた。とりあえず今はだいたい理解しているはず。
セグメンテーションの部分はWindowsもしっかり利用している。でもコードセグメントもデータセグメントもすべて0~4GBの範囲を利用できるようにディスクリプタが設定されているから、仮想アドレス空間内でばらばらに存在するようなことはない。CSもDSも領域がかぶっているような感じかな。

一部間違えた

前に書いたPHPをSSIで動かす話。一部理解を間違えていた。<--#include virtual="foo.php" -->で動かす場合、Content-Typeのヘッダが必要ないと書いたけれど、実際には必要で、だけどPHPだから不必要ということだった。 CGI版PHPでは、勝手にContent-Typeを出力する。だから不必要と言うことだった。だからこれがPerlとかのCGIだったら、 Content-Typeの出力が自分で必要になるはず。今日は色々調べていったら、自分のサーバーではsuPHPを使っているということが分かった。最近はこれになってきているみたいね。確かにユーザー権限ですべてが動くというのは管理も楽だしセキュリティ上もよいはず。

PHPとデフォルト引数と参照渡し

PHPでプログラムを書いていた。PHP4のオブジェクトを利用したプログラム・・・。PHP4のオブジェクトはかなり貧弱なので使いたくないとは思っていたのだけれど、やっぱり使った方が管理が楽と言うことで使ってみた。

んで、やっぱりオブジェクト指向で書いていれば、どうしたって参照渡しが必要になる。

関数を書くときに、よくデフォルト引数を指定する。今回参照渡しの引数に対してNULLをデフォルトで指定したかったのだけれど、ダメだった。できないらしい。検索したけどやっぱりできないって結論のものが見つかった。ちょっと不便かな。

んー、そういえば、ちょっと前にJJFの申し込みフォームを作ってたときは、PHP4のnewが参照ではなくコピーを返すことを知らずにかなり悩ん だ覚えがある。この辺もPHP4でオブジェクトを利用したくない理由。でも結局オブジェクトを使った方が何かと後で変更が楽。んー、悩ましい。PHP5が 使えるレンタルサーバー増えないかな。

ApacheとSSIとPHP

PHPをSSIでインクルードしたい場合にはどうしたらよいのか。今回いろいろ試したので書いておこうと思う。Apacheのバージョンは2.2.3で試した。foo.html内にfoo.phpをインクルードするとする。

---Apacheの関係する設定---
OptionsにIncludesは必須。これは普通のSSIと同じ。さて、ここで二つの場合がある。
Includesが指定されている場合 - すべてのSSIコマンドが使える。重要なのは<!--#exec cmd=... -->、<!--#exec cgi=...-->、<!--#include virtual=...-->の三つ。これらすべてが使える。 IncludesNoExecが指定されている場合 - 上記三つのうち、<!--#exec ...-->の二つのコマンドは利用できない。<!--#include virtual=...-->のみが使える。共用サーバーではよくある設定。

--- foo.htmlの設定---
SSI を利用するためには、どこかでAddHandlerを指定しないといけない。共用サーバーなら、.htaccessに書くことになる。パフォーマンス上は 良くないらしいけど、僕はshtmlという拡張子が好きじゃないので、.htmlをすべてSSI有効にしている。つまり以下のようになっている。アクセス のある程度多いWebならshtmlにして別にしたほうがいいと思う。 AddHander server-parsed .html これで.htmlファイルはすべてSSIが有効になって、<!--#....-->の部分が解析されるようになる。 foo.htmlの中身については後述。

--- foo.phpの設定とその中身 ---
.htaccess にAddHander php-script .phpとか書いておけば、通常PHPファイルはApacheがそれを.phpをPHPモジュールで処理してくれる。重要なのはこの場合実行属性は必要な いということ。ただし、今回は、CGIとして実行するわけで、PHPモジュールは動かない。と言うわけで、コマンドラインのPHPを使うことになる。 つまり、コマンドラインで
>./foo.php [ENTER]
として実行ときの実行結果が返されることになる。さて、普通の PHPファイルは実行属性はついていないので当然実行することはできない。なので755あたりのパーミションに変更する。これでうまくいくかというとそう いうわけにもいかず、スクリプトの最初の行に必要に#!/usr/bin/phpが必要になる。これがないとこのスクリプトを何で処理して良いのか分から ないので、うまくいかない。 というわけで、foo.phpはパーミッション755を付けて、中身はたとえばこんな感じ #!/usr/bin/php

--- foo.htmlの中身---
PHPのファイルをSSIでインクルードするにはどの方法が使えるのか。考えられるのはだいたい次のコマンド。 <!--#exec cgi="foo.php" -->
<!--#exec cmd="./foo.php" -->
<!--#exec cmd="php foo.php" -->
<!--#include virtual="foo.php" --> さて、まずはこれらすべてのコマンドが使えるという状況で、それぞれの違いについて。細かい違いはバージョンやプラットフォームで違うらしいので、重要なところだけ。
<!--#exec cgi="foo.php" -->の場合、PHPでContent-type: text/htmlを出力しないといけない。そうでないと失敗する。
<!--#exec cmd="foo.php"-->の場合は、Content-type: text/htmlの出力は必要ない。さらに引数を取ることもプラットフォームによっては可能らしい。<!--#exec cmd="foo.php arg1 arg2" -->のように。ただしSuexecを使っているUNIXやWin32では利用不可らしい・・・。
<!--#exec cmd="php foo.php" -->は、一応利用可能っぽいが、やっぱりSuexecが有効の場合にはつかえないっぽい。
<!--#include virtual="foo.php" -->はContent-typeの出力は必要ない。さらに引数も<!--#include virtual="foo.php?arg1=var1"-->というように指定可能らしい。

--- さらに設定が・・・ ---
こ れですべてうまくいくはずが、まだ考えなくてはいけないことがあった。IncludesNoExecを指定されている場 合、<!--#include virtual="foo.php"-->でしていするファイルのMimeタイプが重要になってくる。普通.phpファイルはMimeタイプとして

AddType application/x-httpd-php .php

の ように指定されている。ApacheはIncludesNoExecを処理するとき、その対象ファイルのMimeタイプを見て、それがtext/*でない とエラーにするというようになっている。なぜかは分からないがセキュリティ上の都合だろうか。そのままfoo.phpをvirtualに指定すると
unable to include potential exec
というエラーが出てしまう。直訳すると「潜在的なExecはインクルードできない」となる。これの対処方法は二つ。一つはfoo.phpをfoo.cgiにしてしまうこと。こうするとfoo.cgiは普通に実行されてその結果が返る。た だ、どうしてもphpファイルの拡張子は.phpがよいと感じたので、その方法も探った。まあ、簡単なことだけど、foo.phpのあるフォルダ の.htaccessに AddHander cgi-script .php
AddType text/html .php の2行を書く。ただしこうすると、そのフォルダ内のPHPは普通のPHPとしては動かなくなるので注意。

--- まとめ ---
PHPをSSIでインクルードするにはCGIでPHPを動かす。
PHPファイルには#!/usr/bin/phpといった1行目が必要。
PHPファイルには実行権限を付ける
IncludesNoExec下で、<!--#include virtual=...-->でインクルードする場合は、拡張子を.cgiにするか、AddHander,AddTypeの二つを用いて、.phpの扱いを変更する。

--- その後追記 ---
こちらをご覧ください

Illustratorで連番印刷

母親が今度コンサートを開くことになり、そのチケット作成を頼まれた。B5サイズの紙を5等分にして、それが1枚のチケットのサイズになるようにする。IllustratorでB5サイズの紙に5枚分のチケットを印刷するようにして、後でカッターで切る。

問 題は各チケットにナンバーを振る作業。通し番号を振らなくてはいけない。Illustratorそのものに連番印刷の機能は、ない。検索するとナンバリン グ用のプラグインがいくつか売られてた。でもたったこれだけのことに2,3万するプラグインなんて買う気にならないし・・・。

というわけ でいろいろ調べていたら、IllustratorやPhotoshopはJavaScriptでいろいろ操作できることがわかった。 Document Object Modelを操作することでいろいろ自動的にできる。面白そうだしやってみようと思って書いてみた。
チケットがすでに描かれているイラストレータドキュメントがあって、その中のナンバリングの部分(5ヶ所)に名前を付ける。名前はレイヤーウィンドウから 階層をたどっていって、ナンバリング用のテキストオブジェクトをダブルクリックすれば付けられる。名前はNo.1~No.5と付けた。この状態で次のスク リプトを動かす。

docObj = activeDocument;
var minNum=prompt("チケットナンバーの開始値");
var maxNum = prompt("チケットナンバーの終了値");
var ticketsPerPage = 5; //一ページ当たりのチケット枚数
var printPageNum = Math.ceil( (maxNum - (minNum-1))/5 ); // 何ページ印刷するか
var maxDegit = 3; //最大桁数。これに基づいて、テキスト整形
var prefix = "No. "; //連番のプリフィックス
var suffix = " "; //連番のサフィックス

for(var i = 0 ; i < printPageNum ; i++){ //必要なページ数ループ
for(var h = 0 ; h < ticketsPerPage ; h++){ //各ページにはticketPerPageだけナンバーを設定
var obj_name = "No."+(h+1); //テキストオブジェクトの名前(事前にaiファイルで編集・設定)
var numberItem = docObj.pageItems.getByName(obj_name);//テキストオブジェクトの取得
numberItem.contents= getNumberText(i*ticketsPerPage + Number(minNum)+ Number(h)); //ナンバーを設定
}

//プリント
docObj.print();
}

//数値を受け取って、ナンバリング用文字列を返す
function getNumberText(num){
var len = num.length;
var numText = prefix;
for( var i = 0 ; i < maxDegit - len ; i++){
numText += " ";
}
numText += num;
return numText + suffix.toString();
}

最初にナンバリングの最小値と最大値を受け取って、それを1ページ当たりのチケット枚数(今回は5)で割って、何ページ印刷すればよいか判別して、各ページに着き順番に、No.1~No.5のオブジェクトを取得してそのcontentsをナンバーで書き換えて印刷する。
こいつを動かすだけでナンバリングはばっちりできた。

うーん、さすがIllustrator。なかなかすばらしい。

こういったスクリプトは多くのドキュメントや画像を処理する際にもかなり役立ちそう。Webページ作成では結構本物画像から解像度を小さくしたサムネイルを作成する作業は多いから、そういうのもすぐに自動化できそう。

それにしてもJavaScriptもっとちゃんと勉強しないと・・・。いまいちよくわかってないな。

継承とオーバーロード

プログラム書いててよく分からないことになった。どうなってんだ?と思って調べたら、やっぱり重要なこととして書いてあった

http://www.fides.dti.ne.jp/~oka-t/cpplab-hide-overload.html

驚くだろうと書かれているけど、僕も驚いた。というかやっぱりこれは混乱する。呼び出せるはずのものが呼び出せない。C++の仕様なんだそうだ。でも解決方法もここで知ることができたしよかった。ふーん、using base::foo()なんてのがあるのね。全然知らなかった。usingなんてnamespaceでしか使ったこと無かったよ。

フック



フックのお話。別に船長じゃないです。

Windowsのフック。イベントを横取りして処理をするための機構です。フックを設定しておけば、別アプリケーションの操作が可能になったりします。キーボードに対してフックをすればすべてのキー入力を監視することができます。キーロガーというやつですね。

今はキーロガーとマウスロガーを作ろうと思って勉強中。なぜかというと、ウィルスを作ってそこにキーロガーを・・・ではなく、操作ログを取るためのアプリがほしいと思ったのです。どのタイミングでどのウィンドウに対してどういう操作が行われたのか。

実は先日母親がPCを使っていて、とあるファイルを消してしまったのです。何をしたのか聞いても、母親は??といった感じで、どうにも原因がつかめない。今回だけじゃなく、何度とこういった経験をしてきているので、この際何をしたのか記録しといたらいいんじゃないかと。と考えたわけで、そういうアプリがないか探したのです。そしたらやっぱりいろいろあって、そういうのを使おうと思ったわけです。

んじゃ、作る必要ないじゃんってことなんですが、そこはなんか作ってみたかったんですよ。勉強のために。おもしろそうだし。

まあ、実際に使うかどうかは別として、作ってみてどうなっているか知っておくのは重要。

メッセージループ

Windowsアプリケーションを作るとき、今までは普通のメッセージループを使ってきた。でも、DirectXで(DirectXに限らないけど)リアルタイムで描画をするには別のメッセージループが必要となることを知った。
//通常アプリケーションのメッセージ処理
while(::GetMessage(&msg , NULL, 0 , 0 )){
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}



//リアルタイム処理が必要な場合のメッセージ処理
while(TRUE){
if(::PeekMessage(&msg , NULL , NULL , NULL , PM_REMOVE)){
//メッセージを取得できた場合
if(msg.message == WM_QUIT) break;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else{
//リアルタイム処理
}

}

普通のアプリケーションなら、メッセージが送られてきたときに初めて何かが動き出せばよい。GetMessageはメッセージが来るまでは待機して制御を返さない。

一方リアルタイム処理が必要な場合には、常に処理をし続けなくてはいけない。メッセージがあるかどうかをPeekMessageで見て、あればその処理をするけど、なければそれ以外のリアルタイムで処理しなければ行けない部分を行う。アニメーションの場合にはここに描画処理が来ることになる。

ちなみにこのリアルタイム処理を行うアプリケーションを動かすと、CPUの使用率は異常にあがる。そりゃそうだ、常に動いているから。僕のPCの場合DualCoreなので、50%まで上がる(まだシングルスレッドのアプリなので)。

実際、市販のゲームとかはどうかと思って、僕のやっている大航海時代を起動すると、やはりこちらも50%常に使っていることになる。おそらくマルチスレッドになっていることと思うので、ゲーム最中にはさらに使用率は上がるのだと思う。

ということでこのループを使いながら、ボールが落ちてくるようなアニメーションを作成中。クラスとかを設計しながらやっているので、どちらかというとそっちに時間がかかる。でも一度作ればいろいろ遊べて楽しいかも。

DirectX

昨日、たまたま久しぶりにJuggleMasterを見た。Webページのリンクたどっていったら、DOS版のやつがあって、ソースも一緒にあった。

んで、ソースを読んでいてなとなく頭の中に出てきたのが、たしかナランハでもこんなソフト売ってたよなぁ、3Dのやつ → そういえば3Dの物体が動くようなプログラムは作ったことがないなぁ → DirectXか・・・

ということで、さっそくDirectX SDKをダウンロード。COMの知識もそれほどないけど、使うだけなら簡単。それっぽいメソッドを呼び出せば勝手にオブジェクトは作られる。

とはいってもDirectXはまったくの初めて。最初は画面に何か表示することすらできず・・・

そしていろいろ悩みながら、途中グローバル変数だと思ってアクセスしていた変数がローカル変数だったなんていうやってはいけないようなミスをしながら、2時間ほどでまずは画面表示ができた。できた画面がこれw

DX1.gif
普通のウィンドウじゃん!・・・全くその通り。でもこの色が重要。この色はDirectXで書いたものなのです!正確にはバックグラウンドを設定したということ。プログラミングやってるとこの瞬間が楽しい。

ここまででDirectX初期化の基本的なやり方は理解。んじゃ、次は3Dボールを描こう・・・と思った僕が間違ってました。ボールなんてきっとAPIにボールみたいなオブジェクトがあって、それ作って貼り付ければ・・・って思ったのに全然違った。

メッシュってなにさ?頂点バッファって・・・テクスチャを貼り付ける・・・どうやるの?まあ、そこまで一足飛びにやろうとして、意味の分からないことだらけ。ということでドキュメントを読んで基本から。

3D座標系には右手系と左手系があるだの、3Dプリミティブだの、頂点法線ベクトルだのいろいろ言葉を学びながらやっていった。3Dオブジェクトを いきなり描くのは大変そうだったので、とりあえず3次元上にある2Dオブジェクトを描画することに。頂点の座標を3つ(全部XY平面上でZは0)を頂点 バッファなるものに入れて、それを描画させる。三角形ができるはず。いろいろ試行錯誤しながらできた。

んじゃ次はこれを動かそう。座標変換を行って、それを元に回転やら移動やらをさせる・・・わけですが、その前に座標についてかなり分け分からなくなった。

頂点を表現するのには、未座標変換済みと、座標変換済みとがあるらしい。さっき描いた三角形は座標変換済みを使った。だから直接画面の座標をそのま ま入れればよかったらしい。でも今度は違うらしい。動かすために座標変換を行うから、座標変換済みではいけないらしい。なんかここら辺はよく分からない。 座標にRHWっていう値を持たせると座標変換済みになるらしい。同次座標ベクトルベクトルってのが関係してるらしいんだけど、RHWとか・・・意味分かん ない。

とりあえず、そこは飛ばして、サンプルを見ながらなんとなく作成。少しずつ分かってきた。とりあえず今はRHWとかは無視してよさそう。

他にもポリゴンの表面と裏面の両方を描くようにするためのカリングモードの変更だとか、ライトのOn Off(今回はOffで色は自分で付ける。)だとか、サンプルをいろいろいじりながらやっていった。

とにかく3Dオブジェクト一つ描くにもそうとういろんなことやらなくてはいけなくて大変。今日は3次元空間に平面の3角形を書いて、それをY軸を中心にぐるぐる回し、それを斜め45度に視点を回転して眺めるというところまでやった。

DX2.gif
画像だから止まっているけど、本物のウィンドウでは斜め方向にこの3角形が回転している。

次はもう少し3Dオブジェクトっぽいものを作って、ライトを使うようにしよう。そうすれば少しは3Dグラフィックっぽくなるはずだ。

とりあえず最終的な目標はボールを作って、それを弾ませるアニメーションを作るところまで。

feedSubscribe to my feed