昔の最近の出来事(2005.01)

2005/01/31

ほんの少し早めに帰着。

ボタン類のフォントサイズを変える方法に悩んでみたり。 リソーススクリプトを使用すればその辺はよきにはからってくれるようですが、 リソーススクリプトを使わない場合は.....ハテ。ウインドクラスの拡張用 メンバーに何かしらのリストを引っ付ければ良さそうな予感がしますが、 具体的に使っている例がほとんど無かったので、Webを探そうとして眠くて死亡。

2005/01/30

昼前に起きてぐうたら過ごしたり。

バーンアウトのクラッシュイベントコンプリート。レースイベントの方は少々 厳しそうな予感。

先日ちょろっと出かけたときに買ってみた「ハッカーと画家」というエッセイ本 をパラパラと斜め読みしてみたり。著者はポール グラハムという人で、知る人ぞ 知るという人らしいです(TANEはよく知りませんでした(^^;)。強力なLISPerの ようで、自身でも新しいLISPの方言を開発しようとしているみたい。 なるほどと思うところもあれば、そうか?と思う所もあり、恐らく人それぞれで 感想は違うのではないかと思いますが、まだ全部をちゃんと読んでないですが、 まぁまぁ面白い本かなという感じです。

TVのチャンネルぐるぐる回していたら、グランツーリスモ4の開発密着ドキュメント をやってたので、思わず見てしまったり。途中から見たので、前半の方はよく判らない のですが、バグが見つかって12/3の発売が12/27に変更になったという辺りから 見ました。私はソフト開発を生業としてはいないのですが、似たような状況はある為、 いやー、ほんと、恐いね。そんな感じに思いました。それにしても、最後、マスターROMを 焼くのに2時間かかるとして、その2時間が時間的に間に合わないとか、最後ちょろっと 起動テストして(編集でそう見えているだけで実際は時間をかけてるのかも知れませんが) マスターアップとか、「え?そんなのでいいの?」と思ったりしました。でも、 2日で100万本の出荷なのですから、「すげ〜〜な〜〜」と思わず声が出てしまいました。

2005/01/29

午後もいい時間に起床。寝過ぎ。

バーンアウトのクラッシュイベントを消化したりしてダラダラ過ごしてみたり。

ダイアログボックスっぽいものを開くクラスを書いてみたり。なんとなくそんな 感じになってみたり。
所で、D言語でクラスを継承する時、スーパークラスとなるソースを更新すると、 継承する子クラス(弟子クラス?)のソースも再コンパイルする必要があるのにハマってみたり。 更新のあったDソースだけを更新するようにMakefileを書くと、スーパークラス となるソースだけを更新した場合、それだけ再コンパイルされる事に なりますが、その後リンクに失敗する場合があります。所が、リンクに失敗 するだけなら良いのですが、コアダンプする実行ファイルを生成する場合が あったりするのがややこしい所です。結局、Javaのそれと同じような話がある という感じでむーん。

2005/01/28

日付け越え。

あまりに眠くて死亡。

2005/01/27

日付け越え前に帰着。

Webを検索していたら、リソースもDialogBox()も使用せずにモーダルダイアログ を実現することが書かれた ページを発見したので眺めてみたり。
なるほど、ウインドを無効化するEnableWindow()とかを初めて知りましたが、 そういうのを使う事を踏まえて考えてみると、単にウインドを生成して ボタンを配置するのと同じなので、特別に難しい事は無いという感じ。

2005/01/26

日付け越え前に帰着。

CreateWindow()でダイアログウインドなスタイルを指定すればそれっぽくなる のかと思ったのですが、そういうものじゃないらしい。

2005/01/25

日付け越え前に帰着。

リソーススクリプトを使わずにダイアログウインドを生成する話。 単純にCreateWindow()でダイアログウインドなスタイルを指定すれば良い感じ。 実際にコードを書いて確認しようと思ったけど眠くて死亡。

2005/01/24

日付け越え直前に帰着。

ちょろっとソースをいじったところで眠くて死亡。

2005/01/23

昼頃起床。

バーンアウトのイベント消化をだらだらと進めてみたり。

ウインドメニューの追加はできるようになったのですが、IDがうまく取得できなかったり。 Webで調べてみた所、InsertMenuItem()実行時に指定するMENUITEMINFOの引数の中の 構造体メンバのどのメンバを反映するのかをフラグ指定する必要があるというのが判ったり。 返すIDは同じでも表示が変化したり(例えば表示OFF/ON切り替えのようなトグルスイッチ みたいなのを実現する時とか)する場合に使い分けるという事らしい。

そういやダイアログウインドを開く際、ダイアログの中身をリソーススクリプト 以外の方法で構築するにはどうすれば?とか思ったり。CreateWindow()と違って、 ウインドサイズを与えたりする方法があるのかしら?とか、イマイチよく判らず。

2005/01/22

昼頃起床。休出。

バーンアウトのイベント消化。

ウインドメニュー操作クラスを追加してみたり。

2005/01/21

飲み会でいつもより早く帰着。

ちょろっとクラスをいじって眠くて死亡。

2005/01/20

日付け越え少し前に帰着。

ちびちびクラスを増やしたり。

2005/01/19

日付け越え少し前に帰着。

ボタン類クラスを増やしてみたり。

2005/01/18

日付け越え前に帰着。

CreateWindow()するとき、ウインドプロシージャの中で更にWM_CREATEメッセージ から子ウインドをCreateWindow()で生成する事は許されます。 現在TANEがDで書いている方法でウインドプロシージャにメソッドを使う事を 行なうと、そのままではCreateWindow()中でCreateWindow()を実行すると 死にます。そんな訳でスタックできる様にして前述の問題を解決してみたり。
ところで、delegate()という機能を使用すれば、メソッドに対する(関数への)ポインタ を宣言する事ができるようで、もしやこれを利用すれば、小細工をせずとも ウインドプロシージャにメソッドを指定できるのでは?と思って書いてみた のですが、なんかうまくゆかず。

2005/01/17

日付け越え前に帰着。

何気にDで書いたWinアプリなOpenGLプログラムのウインドサイズをぐりぐり 変更したらシステムリソースがじわじわ消費されたり。何が原因じゃろうと 探ってみると、一つはGetDC()で得たディスプレイデバイスコンテキストハンドラ をReleaseDCで開放していなかったのが一つ。もうひとつは wglCreateContext()で生成したコンテキストをwglDeleteContext()で 開放していなかったという点。色々試してて気づいたのですが、 例えば一度システムリソースを消費すると、プロセスが消滅しても消費しっぱなし になります。てっきりプロセスが死ねば自動的に開放されるのかと思って いたのですが、そういうものでは無いらしい。しかも、ちょっとずつ消費 していった後、そのうちシステム不安定状態に陥るという感じが非常に 性質が悪いという感じがします。そんな訳でMinGW版のHairMakerはそういう感じになって いるのに今更ながら気づきましたので、そのうち修正しようと思います。

SAIの新しいのが出ていたので、少し試してみました。今回の目玉は、ストロークを ベクタ保持した線画レイヤーでしょう。まだテスト実装という感じがするのですが、 雑感としては次のような感じ。描くのは特に何も問題はありませんでしたが、 編集がまだ非常に行ない辛いと思いました。特に制御点を移動した時の再描画が非常 に重くて、イマイチという感じでした。重なる部分とかの再描画に処理が食われている という感じがしなくもありませんが、あまりにも重いのでリアルタイム描画更新の OFF/ONが切りかえられればもう少し勝手が違う様にも思いました。あとは、消す方の 編集が結構面倒臭いという点でしょうか。 FlashMXは描画ツールの類は全てベクタライスされますが、あれくらいのレスポンス で動いてくれれば大分違うのになぁという所でしょうか。

2005/01/16

昼過ぎ起床。

ボタン類の部品化(クラス化)を考えてみたり。でもうまくまとめられなくて 死亡。

久しぶりにバーンアウト3をちょっと進めてみたり。

とかぐうたら過ごして一日終了。

2005/01/15

朝わりと普通に起きてみたり。雪は降っていない模様。

先日の話の続き。次のような事を考えてみました。
普通にDmain()の中でスレッドを生成して、そのスレッドの中でOpenGLウインドを 開けば、とりあえず初期化問題はクリアできるのではないかと思い、そのように してみました。結果、やはりSetPixelFormat()を実行するとシステムハング状態 になるようで、実行しなければウインドを開く事自体は問題無しという感じ。 クラスを使わないCで書くのと違いの無い方法でもダメで、 ガベージコレクタのようなDの特殊機能が動いていないようなコードでもダメで、 でもGLUTは使えたりする辺り、何かやれば大丈夫な事は間違いないと思われる のですが.....うーむ、かなりお手上げ気味。

所で、Win32APIの中でポインタを引数とするようなものでは、 「NULLを指定した時にはデフォルトの....」という動きを するものが多くあります。所が、Dでは引数のプロトタイプに明示的な型を 指定した場合、その型にキャストする必要がありますが、何故かnullをうまく キャストできなくて、困ってしまいました。プロトタイプでの引数を問答無用で「void *」 にすれば当然入れられる様になるのですが(LPDWORDなどはvoid*の別名になってて それだと何でも入れられる)、そうしてしまうと何でもかんでも入れる事ができ てしまうのでうまくありません。こういう、「nullかそうでなければ指定した型 のどちらかを指定可能」ってのは、どうやってプロトタイプ宣言 すれば良いのかしら?と疑問に思ったりしました。まぁ、なんとなくそういう場合、 メソッドならばオーバーロードして、引数の内容で判断するのでは無い方法を 用いるべきかも知れませんが。

WinMain()から先(クラスレジストとCreateWindow()とメッセージループ)丸ごと Cで書いて、Dmain()からはスレッドを生成してWinMain()を呼ぶようにしてみた 所、うまくOpenGLウインドを開く事ができました。という事はDの初期化の問題 という感じでは無い気がしてきたので、CのコードとDのコードをもう一度よく 見比べてみました。すると、Cの方ではウインドプロシージャはCALLBACK関数 として定義してありますが、Dは特に何も指定無しになってました。 というか、それでリンクできているし、ビットマップの表示もできている ので、問題は無いと思っていたのですが、何気にプロシージャ関数を 「extern (Windows)」宣言してやると、うまく動作するようになりました! てゆーか、確かに「extern (Windows)」してたのが書き換え途中で削ってしまった 気もしなくは無いですが、なんでビットマップ表示は大丈夫なの?そんな感じ。 なんとなく以前GLUTをDで使用した際、関数がリンクできないのを 訳も判らず置き換えて無理矢理リンクを通したら微妙に動いたり動かなかったり する怪しい実行バイナリが生成されましたが、それと似たようなものなのかも。 それにしても、コールバック関数が変だとしてOSごとお亡くなりにならなくても 良いような気がします。むしろ、例外でガッチリガードしてくれる事を期待 していたのですが、Win98ではダメなのかも。
いや、すっかりハマってしまいましたが、やっと先に進めそうな予感。

2005/01/14

日付け越え前に帰着。

phobosのコンパイルオプションを変えてみたり、初期化の方法を変えてみたり 色々やってみましたが、やっぱりハング状態に陥るのには変わりなく。
-vオプションを付けて、ライブラリのリンクについて調べてみたのですが、 phobosをリンクする以外の事に違いは無く。という事はここに秘密があると いう事に?そういえば、ライブラリのリンク順序を変えて、main()からの始まり (正確にはmain()→gcなどの初期化→Dmain()の実行順序なので、D言語上で 実行しているmain()関数は後者のDmain()の方。今言っているのは前者のmain() の事)とWinMain()からの始まりを切り替えてしまってましたが、 WinMain()から始まる場合、本当にgcの初期化だけで良いのか? ファイルディスクリプタ などの初期化などはやらなくてもphobos的に大丈夫なの?という疑問が湧いてみたり。
phobosのソースinternal/dmain2.dを見てみると、version(Win32)の時に、 _minit()という関数が呼ばれていますが、これはgdcで同じ事をやると _minit()という関数が見つからなくてリンクで失敗してしまいます。もし仮に、 この_minit()という関数でファイルディスクリプタなどgcの初期化以外の 初期化を行なっているものだとすれば、関数が見つからないので省略している 今の方法ではマズくて、必要な初期化が抜けていると考えられるような気が してきました。でも、_minit()という関数が実際のところ何をやっているのか、 リンクできないgdc on Cygwin の環境では知る術も無く......

2005/01/13

日付け越え前に帰着。

gdcのビルドはエラー無く終っていたり。phobosのビルドもエラーする事無く終了。 という訳で早速ハングプログラムをコンパイル&実行してみましたが、 やっぱりダメでした(T_T)。

2005/01/12

日付け越え。

gdc-0.10のビルドを仕掛けて終了。 CD-Rのトレーは相変わらず出たり引っ込んだり。

2005/01/11

日付け越え。

ちょっと書き換えたりしてみましたが、やはりハング状態になるのは回避できず。 とかやってたら、いきなりCD-Rのトレーが出たり引っ込んだり(汗; いきなりCD-Rドライブが壊れたっぽい。これまで一度もCD-Rを焼いた事は無い のですが。使わなくても壊れるものなのかと思ったり。

gdc-0.10が出てたり。これに賭けてみるか?

2005/01/10

休出。

OpenGLウインドが開けないのを調べたり。
原因はよく判りませんが、ひっかかるパターンは次のような感じみたい。

  1. CreateWindow()のフラグ引数にWS_VISIBLEがあるとSetPixelFormat()関数を 実行した所で死ぬ。
  2. SetPixelFormat()関数を実行すると死ぬがCreateWindow()のフラグ引数から WS_VISIBLEを無くすと死なない。
  3. 2.の状態でShowWindow()でウインドを可視化しようとすると死ぬ。
  4. OpenGL表示用コンテキスト生成部分はCの関数にくくり出しても死ぬ。ただし、 同じ関数をオールCで書かれたプログラムからWM_CREATE時に呼び出した場合は 正しく動作していそう。

ここで「死ぬ」というのは、Windowsがハング状態になり、キーボード/マウスの入力 が一切受け付けられなくなる状態を指しています。
可視化した瞬間に死ぬ辺りに何か秘密がありそうですが、所々、関数の成功前提で 実行しているところがあるので、それら全てをチェックする必要がありそう。

そういや、Cygwinパッケージに含まれるgcc-3.3.3ベースのgdc(多分dmd 0.80ベース) で実行してみたのですが、extern(Windows)な関数指定がうまく解釈されてなくて、 リンクできないという問題があるようです。OpenGL系関数をCのラッパーで 包んだのと同じ事をWin32APIでも行なう必要がありそうで、結論としては、 以前のバージョンのgdcではWinアプリは書けないかもという感じみたい。

2005/01/09

休出。

DでWinアプリを作成する下地調査を行なってみたり。
とりあえず、ウインドを開いたり、リソースからビットマップを読み込んで表示したり するのはOKそう。少しDっぽく書こうという事で、CreateWindowした時に指定する イベントループ処理関数(ウインドプロシージャ)をメソッドに置きかえられるか試してみたり。 大体次の様な感じ。

class Frame {
  WNDCLASSEX  winc;
  this(char[] title,HINSTANCE hInstance, char[] ClassName) {
    this.winc.cbSize         = WNDCLASSEX.sizeof;
          : ウインドクラスに必要な値をここで設定する
    this.winc.lpszClassName  = ClassName ;
    this.winc.lpfnWndProc    = cast(WNDPROC)(&this.proc) ;
  }
  
  int open(uint flags, int x, int y, int width, int height, HWND phwnd, HMENU hmenu){
    if( !RegisterClassEx(&this.winc) ) return -1 ;
    this.hwnd = CreateWindowEx(0,
                               this.winc.lpszClassName ,
                               this.title,
                               flags,
                               x,y,width,height,
                               phwnd, hmenu, this.winc.hInstance , null
                               );
    if( this.hwnd == null ) return -2 ;
    return 0 ;
  }

  LRESULT proc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp){
     :
     : ここにイベント処理を書く
     :
    return DefWindowProc(hwnd , msg , wp , lp);
  }
}

所がこれはコンパイルエラー。WNDCLASSEX.lpfnWndProcにはメソッドを指定 してはダメでextern (Windows)な関数を指定する必要がありそう。 とは言っても、いちいちウインドプロシージャを外付けで用意するのは 面倒ですし、イマイチ オブジェクト指向言語っぽく無い感じがします。 そんな訳で少々ややこしいですが、ウインドプロシージャ用に次のような 関数を用意してみる事にしました。

LRESULT _WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp)
{
  return( _FrameList[cast(int)(hwnd)].proc(hwnd,msg,wp,lp) ) ;
}

ウインドハンドラ hwndをメソッドを引くキーにして、Frameクラスのメソッド proc()を呼び出しているという感じです。こうする事でWNDCLASSEXに指定 するプロシージャ関数は全てに共通なのですが、実行する先はインスタンスごとに分岐 するという感じです。でも、実際にはこれだけではうまくいきませんでした。 原因は、ハンドラhwndを取得できるのは、CreateWindow()を実行した その戻り値なのですが、CreateWindow()から戻って来る前に プロシージャ関数にはWM_CREATEなどの初期化の為のメッセージがいくつか 送られているのです。なので、CreateWindow()を実行する前に hwndに対応するインスタンスを_FrameList[]で引ける様にしなくてはならない という卵と鶏の関係になっているのです。仕方ないので、結局次の様に する必要がありました。

LRESULT _WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp)
{
  if( _CreatingFrame is null ){
    return( _FrameList[cast(int)(hwnd)].proc(hwnd,msg,wp,lp) ) ;
  }else{
    return( _CreatingFrame.proc(hwnd,msg,wp,lp) ) ;
  }
}

CreateWindow()を実行する前に、_CreatingFrameに自分自身(this)を指定 しておきます。CreateWindow()を実行して、_WndProc()関数が実行されたとき、 _CreatingFrameがnullでなければCreateWindow()を実行している最中の ハズという事です。CreateWindow()が終了したら、hwndが得られますので、 自分自身(this)を_FrameList[hwnd]=this でリストに登録して、_CreatingFrameを nullに設定するという感じです。これで取りあえず複数のウインドを開いても 問題無く独立動作できました。一つ問題があるとすれば、マルチスレッドで 動作させようとしたとき、変数_CreatingFrameを排他更新できるようにしないと、 ロック管理が狂うという点が挙げられるでしょうか。

そんな訳でOpenGLを使えるかどうかを試してみたり。 取りあえずOpenGL表示用のコンテキスト生成ルーチンを組み込んで、 OpenGL(glなんちゃら)による表示は行なわないというコード を書いてみました。所が、コンパイルでは特にエラーしないものの、 実行するとWindows自体が固まってしまい死亡。リセットするしか無い 状態に陥ったり。死ぬ境界線を探した所SetPixelFormat()関数を実行 すると、そのまま死ぬようで、またその死に方も固まる場合もあれば、 赤○白×ウインドが開く場合もあったり、ビデオ表示がおかしくなったり と色々。Dのガベージコレクタに関係するのかと思い、OpenGL表示コンテキスト の生成部分だけをCの関数に括り出してみたのですが、それでも状況変わらず。 むー。

2005/01/08

起きたら日が暮れかけててびっくり。

SAIのテストを少し。スペースキーが効かないのは再現せず。やはり 気づかないうちに日本語変換ONになっていた可能性が大な予感。
別件ですが気づいた事がありました。BMP読み込みで、SAIを終了 せずに違うBMPを読み込んだ時、以下の手順で読み込みを行なうと、 レイヤーリストの縮小表示が更新されないようです。

  1. SAIを起動してBMPファイルを読み込む。
  2. 新規レイヤーを追加する。
  3. もう一度BMPファイルを読み込む。

この後、読み込んだBMPファイルのレイヤーをちょっと塗るなどの編集すれば 表示は更新されます。ダメな時は起動後に一番最初のBMP読み込みを行なった 時から更新されない場合があるようです。

もう一点、キャンバスの外のグレーの領域に対してペンなどで描いたとき、 UNDOバッファが更新されるようです。キャンバスの表示 領域の更新が行なわれたときだけUNDOバッファ更新されるのでは?という のが期待値の様に思います。

2005/01/07

日付け越え。

昨日の再ビルドテストはNG。defunctなプロセスが大量に存在した状態 になりました。むーん。

2005/01/06

日付け越え。

Cygwinスナップショットにプロセス管理関連の修正が入っていそうだったので、 ビルドしてみることに。ビルドは完了したのですが、テストの為の自己ビルドは 時間がかかるのでほったらかしで眠くて死亡。

2005/01/05

日付け越え前に帰着。

Webをさまよっていると、windows.hからDのモジュールを生成した 「 Project: windows.h for D」なるページを発見しました。 ダウンロードして中身を眺めてみると、W系API呼び出し固定になって いますが、きちんとA系の方も定義されていたので、ちょいとフィルタスクリプト を書いて A系API呼び出しを行なえる様にしてみました。 所々ハマり事がありましたが、一応使えそうな予感。いや、素晴らしいです。

2005/01/04

背筋が寒くて少し室温高めに設定して寝てたらいつのまにか暑くて布団がどけられてて 風邪悪化。なんだそれ。

SAIのスペースキーが効かなくなるのを再現させてて一つ気づいたのですが、 日本語変換がONになっている場合、スペースキーを押しても押した事になりません。 これには気づいていたのですが、ふと思い返すと、スペースキーが効かなくなったと 認識した時に、日本語入力の状態がどうなっていたか?というのを確認した記憶が ありません。という訳で、もしかすると、日本語入力が気づかないうちに (スペースキーの隣の変換キーを思わず押して)ONになっていた可能性が考えられ る気がしてきました。もし今度再現したと認識した時は、日本語入力状態を 確認してみる事にします。もし、「スペースキーが効かないと思った時==日本語入力ON」 であればそういう事で、「スペースキーが効かないと思った時!=日本語入力ON」ならば やはり何かしらのハマりパターンが存在するという感じかも。

2005/01/03

昼過ぎ起床。

TV観ながらSAIでラクガキ。041224版を使用したのですが、スペースキー反応しなく なる問題がやっぱり発生したり(汗; 今回も再現パターンがイマイチ掴めてないです。 KOJIさんちで掴んだ対処が入っているのかどうか判りませんが、もし入っている ようならば、ちょいと本腰入れて再現パターンを探らないとマズイっすね。

オノマトペ。日本語の擬音語や擬態語(動物の鳴き声やら シーンやガーンといった 様子を文字化した言葉)の総称らしい。特に日本はオノマトペが多いらしい。 「シーン」という静かな様子を表す言葉を最初に使ったのは手塚治虫という 事にへぇ。

2005/01/02

昼過ぎ起床。

ぐうたら過ごしていたら寒くて死亡。風邪気味になって寝てたら一日終了。
起きたらカンフーハッスルの特番をやってたり。その後 昔のチャウ・シンチー監督 作品である所の「食神」をやってたり。料理の鉄人をパロった感じ でしたが、結構ムチャな感じが笑えました。この頃はCGをバリバリ使った感じには なってません(94年作品だったと記憶)が、使うと確かに少林サッカーのような 映像を作りそうな、そんな感じがしました。以下個人的な印象。少林サッカーの 時も思ったのですが、今回観た食神も なんかセリフが少々乱暴というか、 「それは言い過ぎ」みたいに感じる所がちょいちょいありました。訳の問題とか 香港という国柄があるのかも知れませんが、あまりに酷過ぎて 笑い所が逆に ひいてしまうように感じる点があったりするのが勿体無いなぁと思ったり思わなかったり。

2005/01/01

起きたらすっかりイイ時間。あけましておめでとうございますm(_'_)m

年越し番組を観ながらDでWindowsプログラムの実験をしていたのですが、 どうにもPAINTSTRUCTがうまく解釈されなくて悩んでみたり。 std.c.windows.windowsの中で構造体としてPAINTSTRUCTは定義されている ようなのですが、リンク時にエラーするようで、それを見ているとどうやらクラス定義 だと解釈されてしまっているようです。
他、CではCreateWindowなどは実際にはUNICODE対応にするかどうかでCreateWindowA()とCreateWindowW() のようなA系とW系とを切り替えているのですが、DのそれにはA系だけが定義されているようです。 他にも定義されていないAPIがいくつかある感じですが、原理的にはリンクさえできるように してしまえばOKなハズなので、まぁ、やれば良いだけなのかも。

そういや、Win32APIのリンクの方法を調べていると、「extern (Windows)」で関数 定義すると、以前OpenGLのリンクで問題と なった、「@」付き関数名に置き換わるのをうまくリンクできるようになるようです。 試しにいくつかのOpenGL関数をextern (Windows)定義にしてやるとリンクOKとなりました。 ただ、例えば、関数へのポインタを引数とするようなglutDisplayFunc()のような のを「extern (Windows) void glutDisplayFunc(void (*func)()) ;」と定義すると、 引数となる関数(へのポインタ)もextern (Windows) 定義しておく必要があるようです。 なので、関数自体は extern (Windows)だけど引数とする関数(へのポインタ)は extern (C) というのはNGみたい。という訳で、ラッパー関数無しでも良いかも 知れずという事が判りました。でも、OpenGL系関数のextern定義を切りかえるのは モジュールでやるから良いとしても、引数となる関数までプラットホームで 定義を分けなくてはならないのはあまりうまく無いなぁという気がします。

隠し芸大会観たり、トリビアの泉のスペシャル観たり。 以前、日本刀とピストルのどちらが強いか? というトリビアの種が再放送されていたのですが、その後に、日本刀とマシンガンの どちらが強いかというのもやっていたらしく、思わず見入ってしまったり。 結果は日本刀が折れてマシンガンの勝ちでしたが、折れるまでの間に6発の弾丸を 受けており、それらは全て真っ二つに切られているというのに感動すら覚えてしまい ました。日本刀スゲー。

という訳で、全てのOpenGL系関数を extern (Windows)属性に変えて、ラッパー無しでリンク してみた所、リンクはエラー無くできたのですが、何故か core dumpする実行 ファイルが出来あがったり。なんせコンパイル時にエラーしないものですから、 何が悪いのか全く見当が付かなかったり。世の中うまくゆかないなぁと思ったり。

Win32APIの方を調べたり。
どうやら、PAINTSTRUCTの方は、「PAINTSTRUCT ps;」みたいに変数定義していたのを、 「static PAINTSTRUCT ps;」とすればうまくリンクできる様になりました。 それよりも謎なのが、PAINTSTRUCTのすぐ上にあるRECT構造体は、「RECT rect;」とやっても 正しくリンクできてしまう点です。std.c.windows.windows内での記述はどちらも 全く同じ様に見えるのに、何故PAINTSTRUCTの方だけ実体のリンクに失敗するのかが よく判らない所。
もうひとつ、switch()文でdefaultが無い時、 コンパイル時にはエラーしないのに実行時に例外が発生するようです。こんなのコンパイル時に チェックすれーって感じなのですが仕様の様です。何故なのやら。

PAINTSTRUCTのリンクに失敗するのと同じ状況を再現させてみたり。次のように書くと ダメらしい。

windows% cat -n test_mod.d
     1  module test_mod.d ;
     2  
     3  struct Test1{
     4    int A,B,C ;
     5  }
     6  
     7  struct Test2{
     8    int a,b,c ;
     9    ubyte dim[32];
    10  } 
    11  
windows% cat -n test.d
     1  import test_mod ;
     2  
     3  int main()
     4  {
     5    Test1 test1 ;
     6    Test2 test2 ;
     7  
     8    printf("A=%d : B=%d : C=%d\n",test1.A,test1.B,test1.C) ;
     9    printf("a=%d : b=%d : c=%d\n",test2.a,test2.b,test2.c) ;
    10    
    11    return(0) ;
    12  }
windows% gdc test.d
/cygdrive/c/windows/TEMP/cc3IVHK1.o(.text+0x20):test.d: undefined reference to `__init_8test_mod1d5Test2'
collect2: ld returned 1 exit status

パターンを絞り込むと、次のような感じみたい。

  1. struct宣言を外部のモジュールで行なうとダメらしい。同じモジュール内で行なう分にはOKっぽい。
  2. 構造体の中に配列を持つとダメらしい。因みに、配列サイズを変更すると([16]とか)、何故かリンク時のエラー メッセージが増えます。
  3. test_mod.dの9行目の配列部分を、「static ubyte dim[32];」などと書きかえればOKらしい。 もしくは、test.dの6行目を「static Test2 test2;」と書き換えてもOKらしい。後者は PAINTSTRUCTがうまくいかなかったのを解決したのと同じ方法。

キモは構造体の中に配列を含んでいて、且つ外部モジュールでstruct宣言している場合に ハマるという事みたい。gdc-0.9でも、Cygwinパッケージのgcc-3.3.3ベースのgdcでも 同じ結果になるみたい。dmdでの振るまいはよく判らず。てゆーか、dmdのオリジナルの コンパイラは使った事が無いので(^^;;;;;;;;


TOP PREV