• ベストアンサー

ウィンドウクラスの指定について

いつもお世話になっていますGedankenです。 ウィンドウズプログラムについて素朴な質問があります。 Win32 API プログラミング(C言語)ではRegisterClass などで登録した ウィンドウクラスをCreateWindow を使う時"文字列"で指定すると思いますが なぜそんなに回りくどいことをするのでしょうか。 普通に考えれば構造体へのポインタなどで指定した方がスマートだと 思うのですが、どうなのでしょうか。 多分ちゃんとした理由があると思いますが、そこについて解説お願いします。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

> ここの部分がちょっと分からないのですが、システムがそれぞれのウィンドウクラスを > 把握する必要があるのはどうしてですか?やはり、プロセス同士の連携でしょうか。 > そこらへんの理由を教えていただきたいです。 アーキテクチャがそうなっているから。という答えじゃだめですかね? たとえばWindows以外のWindowシステムの例として X (X Window System)と Macintosh (Classicのほう)を考えてみましょう。 たとえばごく単純なMac用のプログラムは以下のような感じになります。 void main(void) {   WindowPtr a_window;   PicHandle picture;   Handle a_menu;   Rect pict_rect;   ToolboxInitialize();   a_menu = GetNewMBar(128);   if(a_menu == NULL) ExitToShell();   SetMenuBar(a_menu);   DrawMenuBar();   a_window = GetNewCWindow(128, 0, (WindowPtr)-1);   picture = GetPicture(128);   pict_rect.top = 10;   pict_rect.left = 10;   pict_rect.right = pict_rect.top + 50;   pict_rect.bottom = pict_rect.right + 50;   SetPort(a_window);   DrawPicture(picture, &pict_rect);   EventLoop();   DisposeWindow(a_window);   ReleaseResource((Handle)picture); } void EventLoop(void) {   EventRecord loop;   while(1){     if(WaitNextEvent(everyEvent, &loop, 0, 0L) == true){       switch(loop.what){       case mouseDown:         if(MouseEvent(&loop) == QUIT) return;         break;       case autoKey:       case keyDown:         if(KeyEvent(&loop) == QUIT) return;         break;       case updateEvt:/*アップデートイベント*/         EventUpdate(&loop);         break;       }     }   } } もうひとつ、X での例を挙げるとこう。 main(int argc, char **argv) { Display *mydisplay; Window mywindow; GC mygc; XEvent myevent; XSizeHints myhint; int myscreen; unsigned long myforeground, mybackground; int n;   // Xサーバに接続する   mydisplay = XOpenDisplay(""); myscreen = DefaultScreen( mydisplay ); // Xサーバで使用されている基本色を得る mybackground = WhitePixel( mydisplay, myscreen ); myforeground = BlackPixel( mydisplay, myscreen ); // ウィンドウの位置、大きさを指定 myhint.x = 200; myhint.y = 200; myhint.width = 300; myhint.height = 200; myhint.flags = PPosition | PSize; // ウィンドウを生成 mywindow = XCreateSimpleWindow ( mydisplay,     DefaultRootWindow( mydisplay ),     myhint.x, myhint.y, myhint.width, myhint.height,      5, myforeground, mybackground); // 生成したウィンドウの情報をシステムに知らせる XSetStandardProperties( mydisplay, mywindow, hello, hello,      None, argv, argc, &myhint ); // グラフィックを描くための準備 mygc = XCreateGC( mydisplay, mywindow, 0, 0); XSetBackground( mydisplay, mygc, mybackground ); XSetForeground( mydisplay, mygc, myforeground ); // 受け取るイベントの選択 XSelectInput( mydisplay, mywindow,    ButtonPressMask | ExposureMask ); // ウィンドウを表示 XMapRaised( mydisplay, mywindow ); // イベントループ n = 0; while ( n < 10 ){         // イベントの取り出し    XNextEvent ( mydisplay, &myevent );    switch ( myevent.type ){   // 再描画要求    case Expose: if ( myevent.xexpose.count == 0 ){    printf("repaint\n");       XDrawImageString(         myevent.xexpose.display,         myevent.xexpose.window,          mygc,50,50,          hello, strlen (hello) );   } break; // マウスのボタンが押された    case ButtonPress:   XBell( mydisplay, 0 );      printf( "button down %d \n", n++ );       break; } } XFreeGC(mydisplay, mygc); // コンテキスト解放 XDestroyWindow(mydisplay, mywindow); // ウィンドウの破棄 XCloseDisplay(mydisplay); // 接続の解除 exit (0); } Windowsを含めてこれら三つのウィンドウシステムを考えたとき、XとMacは イベントループはユーザープログラム自身が制御しています。 >  EventLoop(); この関数の中身でやっていることとか、 > while ( n < 10 ){ >         // イベントの取り出し >    XNextEvent ( mydisplay, &myevent ); このループでやっていることです。ところがWindowsに関しては LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) { if (msg == WM_LBUTTONUP) { MessageBox(hwnd , TEXT("終わるにゃん") , TEXT("Kitty") , MB_ICONINFORMATION); exit(0); } return DefWindowProc(hwnd , msg , wp , lp); } のような、システムから呼ばれる(コールバックされる)形をとっています。あるウィンドウクラスのコールバック関数はただひとつですから、 両者の対応をシステムが把握していなければならないというわけです (=RegisterClassで登録する)。 わたしはWindowsのアーキテクトでもなんでもありませんから推測しかできませんが、 おそらくこのような形にすることで同じウィンドウクラスのイベントループ処理の ルーチンをひとつにまとめることができるので、このような形にしたのではないかと思います。 Windows 1.0とかだとメモリ要求もきついですからね。 Macintoshも初期はそれほどメモリが潤沢に使えなかったと思いますが、 非常によくできたROMルーチン(toolbox)がありますからその点でアドバンテージがあります。 C言語によるMacintosh Toolboxプログラミング~ http://delegate.uec.ac.jp:8081/club/x68/press/2001/lecture/mac_toolbox.html ウィンドウの表示 http://homepage3.nifty.com/rio_i/lab/xlib/001window.htm http://wwwdoi.elec.nara-k.ac.jp/html/jisyu/xprg/index.html ウィンドウプロシージャ http://wisdom.sakura.ne.jp/system/winapi/win32/win10.html マイナーなところだと、X 68000というパソコン用の SX-Windowとか Ko-Windowとかいうのもありますが、まあ興味があったら調べてみてください。

Gedanken
質問者

お礼

sakusaker7さん、再びの回答ありがとうございます。 また、お礼が遅れて申し訳ないです。 この説明で、よく理解できました。 いつかまたお世話になるかもしれませんが、よろしくお願いします。

その他の回答 (3)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

構造体へのポインタが使えないのは、システムにおける一意性が確保できない(保証できない)からでしょう。 それと、登録したときのプロセスが(UnregisterClassをしないで)消滅したときの 処理が簡単になるからではないかと思います。 RegisterClass/RegisterClassExの説明をよく読んでもらいたいのですが、これらの関数は > 関数が成功すると、登録されたクラスを一意的に識別するアトムが返ります。 > このアトムは、CreateWindowEx 関数、CreateWindowEx 関数、および > UnregisterClass 関数でしか使用できません。 とあります。内部的にはAtom(システムでひとつしかない文字列テーブル)としてRegisterClass/RegisterClassExに渡されたクラス名を 登録しています。 一意性を確保した上で、たぶんメモリの節約を主な理由として RegisterClass→CreateWindow という手順をとるようにしているのではないかと思います。 Windows 1.0だの2.0だのの時代のプログラミングはさすがにやっておりませんので 詳しくはわかりません。

Gedanken
質問者

お礼

sakusaker7さん、回答ありがとうございます。 >構造体へのポインタが使えないのは、システムにおける一意性が確保できない(保証できない)からでしょう。 ここの部分がちょっと分からないのですが、システムがそれぞれのウィンドウクラスを 把握する必要があるのはどうしてですか?やはり、プロセス同士の連携でしょうか。 そこらへんの理由を教えていただきたいです。

noname#30727
noname#30727
回答No.2

ウィンドウメッセージはプロセス間通信の一種なので、ウィンドウプロシージャがウィンドウを作成するプロセス上に存在しない事もありえます。 他のプロセスのメモリにはアクセスできないので、この仕様は仕方の無いところです。

Gedanken
質問者

お礼

inthefloiさん、回答ありがとうございます。 違うプロセスからも使えるようにプログラムがOSにウィンドウクラスの 登録を頼んでいる、みたいな感じですかね。 ポインタは違うプロセスでは使えないですし。 少し理解できた気がしました。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.1

★ちゃんと解説できるか不安ですが、私なりのとらえ方を記述します。 ・通常、ウインドウクラスは1つしか RegisterClass で登録しなかったり、CreateWindow でも  1つのメイン・ウインドウしか作りませんよね。→小規模では。  この場合では、管理構造体を引数で渡した方が確かにスマートかもしれません。 ・でもね。ボタン、リストボックス、コンボボックス、エディットボックスなどなども Windows では  1つの子ウインドウとして管理しています。そして、ダイアログ・アプリケーションで電卓ソフトを  作ったとすると『ボタン』という子ウインドウをたくさん作りますよね。  でもたくさんの『ボタン』は押されたときに、親ウインドウに WM_COMMAND などを通知しますが、  この仕組みはすべてのボタン・コントロールで同じになります。すると同じ管理構造体を多数定義して  引数に渡すのは面倒ですし、管理構造体が増えすぎます。ここを1つの共通に出来れば、処理も1つに  できます。そして、1つの処理にするには最初に管理構造体のようなものを登録する必要があるのです。  これが RegisterClass 関数で登録するウィンドウクラスと思えば分かりやすいと思います。 ・1つのクラスに1つのプロシージャしか関連付けれませんが、同じクラスを持つ『ボタン』のような  コントロールを独自開発した場合、最初に独自コントロールの登録をすれば、それに関連付けられた  プロシージャを呼び出すだけですべての処理を共通に出来ます。→とても便利です。 ・1つのプログラムで複数の独自コントロールを使い、かつ複数の同じコントロールを使う場合には  最初にウインドウクラスを登録して、それ専用のプロシージャを関連付けれることで処理コード部も  削減(圧縮)にも繋がります。 ・中規模や、大規模のプログラムでは、独自コントロールなどを開発して使ったりしますので、標準の  ボタン、リストボックス、コンボボックス、エディットボックスも自前で作るときには、どうしても  RegisterClass 関数の仕組みがないと Windows ではボタン1つでさえも上手く管理できません。  私はウィンドウクラスの登録や、それに対するプロシージャの関連付けなどの仕組みが、GUI プログラムの  利点だと考えています。 余談: ・MS-DOS 時代に作成していたソフトも同じ考えを取り入れていれば、もっと効率の良いプログラミングが  出来たことでしょう。今、思うと懐かしいです。 ・以上。私なりのとらえ方でした。→参考に。

Gedanken
質問者

お礼

Oh-Orangeさん、大変詳しい回答ありがとうございます。 汎用性の高い設定を構造体にして使いまわすという"ウィンドウクラス"の 仕組みは分かるのですが、なぜ RegisterClass という関数を使って"登録"する のかが分かりません。 つまるところ、RegisterClass が何をやっているのかが知りたいです。 そこの所を教えて下さるとありがたいです。 よろしくお願いします。

関連するQ&A

  • windowsでの自動化

    windowsで、画面上の色を取得して、自動的にクリックするプログラムを作りたいのですが、 必要なものがわかりません。 調べてみると、win32apiとvisual C++を使う方法があるようですが、他の方法はあるのでしょうか。 ちなみにプログラミングの経験は、C言語でCUIのプログラミングをしたことがある程度です。 簡単なデータ構造やアルゴリズムもわかります。 ですが言語は問いません。 よろしくお願いします。

  • RubyでWin32APIのCreateWindow

    RubyでWin32APIのCreateWindow 初めまして。RubyでWin32APIを使ってプログラミングをしようとしています。 RubyもWin32APIも勉強を始めて間もないのですが、RubyリファレンスマニュアルのWin32APIのページやグーグル検索などを利用し一通り調べて (test.rb) require 'Win32API' createwindow = Win32API.new('user32', 'CreateWindow', %w(l p l i i i i l l l p), 'l') createwindow.call(0, "HELLO", 0xc00000, 100, 100, 100, 100, 0, 0, 0, nil) としてみました。しかしエラーで、 test.rb:2:in `initialize': GetProcAddress: CreateWindow or CreateWindo wA (RuntimeError) となりました。 rubyのバージョンは ruby 1.8.6 です。 コードのどこが間違っているのか、エラーの意味、参考になるwebサイト(rubyでWin32APIのCGIを扱っているサイト)を教えていただきたいです。 よろしくお願いします。

    • ベストアンサー
    • Ruby
  • C++のクラスについて

    C++を勉強しているC言語経験者です。 C++のクラスについてですが、クラスのメリットとはなんでしょうか?なんだか関数ポインタを持った構造体にしか見えないと言うか・・・(あと隠蔽化機能も持ってるんですね)。私が小規模なプログラムを組んだことしかない為か、クラスの必要性が全くわかりません。クラスは具体的にどう使い、どう役に立つものなのでしょうか? 回答よろしくお願いします。

  • char型の文字列をウィンドウに表示させる。

    c言語のAPIを用いてプログラミングをしているものです。 char*型の文字列をウィンドウに表示させるにはどうしたらいいでしょうか。できれば、例を挙げて教えていただけないでしょうか。 よろしくお願いします。

  • BUTTON型のウィンドウに入力欄を作りたい。

    Win32API初心者です。 灰色(BUTTON型?)のウィンドウにエディットボックスを入れたいのですが、 ウィンドウクラスの設定の仕方がよくわかりません。 CreateWindow()関数のlpClassNameにBUTTONとやらずにウィンドウクラスを自前で作ってIEのインターネットオプションを開いた時みたいなウィンドウにしたいのですがやり方がよくわかりません。 お願いします。

  • C++とWIN32APIとゲームプログラミング

    WINDOWSで動くゲームを作りたくて3日ほど前からC++の勉強を始めました。 (最終的にはグラディウスのような横スクロールシューティングが作りたいです。) そこで質問なんですが 1、Win32APIについて調べるとC言語を使っての入門サイトばかりがヒットします。 Win32APIはC言語で書くものなんでしょうか? そうなってくると今WindowsのGUIアプリを作るのにC++を勉強していますが無駄ってことでしょうか? 例: 猫でもわかるプログラミング http://www.kumei.ne.jp/c_lang/index.html Win32API入門 http://wisdom.sakura.ne.jp/system/winapi/win32/index.html ちなみに今学習に利用しているサイトは以下のサイトです。 C++入門 http://www.asahi-net.or.jp/~yf8k-kbys/newcpp0.html 2、ポインタの概念について ポインタのイメージですが値を格納している場所みたいな感じで大方あってますでしょうか? 僕は組み込み系をやっているのでアセンブラにどっぷり漬かっています。 なんていうかレジスタの番地がポインタに該当するのかなって思っています。 ↓みたいなイメージで考えています。 ポインタ=データの場所=レジスタ番地 これであってますか? 3、まだGUIには進んでませんがウインドウのメニュー(ファイル、編集等)を作るのにリソースファイルも作るって説明が上記ページ(猫でもわかる)に書いてましたがリソーススクリプトとかヘッダーもプログラム言語とは別に勉強する必要があるんでしょうか? 4、C++のクラス概念について クラスとは複数の関数をひとまとめにしてグループ管理(おおざっぱに言うとサブルーチンの集まり的な)するようなものってイメージであってますか? 5、WindowのGUIアプリのプログラムの概要ですが各オブジェクト(ウインドウやボタン、マウスポインタ等)に対して「クリックされた」とかのアクションに対して動作するプログラムを書くって事でいいんでしょうか? 6、お勧めの参考書籍について 今までアセンブラをはじめPerlやJavaScript、C言語のお勧め入門書をいろんなサイトのレビューを見て買いましたが本よりネットの入門サイトのほうがかなり役にたってきました。それでも入門書を買うのは気持ち的に安心するからなんですが・・・ それを踏まえた上で僕の最終的な目的にあうような本があったら是非教えてください。 7、勉強の進め方や「合わせてこれも勉強しろ」っていう項目があれば教えてください。 現状としては 「C++の基礎(必要ですか?)」→「Win32API」→「DirectX」で行こうと思っています。

  • android-JNIでクラス配列参照方法について

    androidのJNIで関数引数をクラス配列にした場合、C側ではこのポインタをどのようにすれば取得出来るのでしょうか? 一応GetByteArrayElements()を使用してクラス配列の要素数までは取得できましたが、このクラスのポインタの取得方法が出来ません。 ※クラス配列にある変数をC言語側で参照したいと考えております。 (このクラスはC言語の構造体として扱うようにしています)

  • VC++でwin32APIを作っているのですが・・・

    こんにちは。私はwin32APIを勉強しているc言語初心者です。 私はMicrosoft Visual C++ 2008を使ってc言語のwin32APIをプログラミングしているのですが、独学でやっているので物凄く邪道なwin32APIプログラミングをしているような気がするのです。 ・c言語のプログラムを書いて、C++のwin32APIプロジェクトとしてビルドする。 ・ヘッダーファイルにwin32API関数がなかったので、自分のwindowOSからwin32API関数を探し出してVC++2008のなかのincludeフォルダ内にコピー&ペーストして使えるようにした。 これって邪道ですか?一応何の問題もなくwin32APIプログラムが作れるのですが、もっと正規なやり方があるでしょうか。回答よろしくお願いします。

  • Java:クラスをたくさん使ったプログラミング?

    Java言語勉強中のものです。 Eclipseをつかっています。 初心者ですので、易しい言葉でご回答いただければ幸いです。 Javaの基礎についてひととおり勉強しました。 オブジェクト指向についても、だいたい・・なんとなくは理解できていると思います。 ただ、自分で作成するときに、 うまくオブジェクト指向を取り入れたプログラミングができません。 なんだかあっちこっちのものを呼び出してきてとてもややこしいです。 クラスがたくさんつかわれているプログラムは、 ほかの人がつくったプログラムをなんとかがんばって読む、というのが精一杯です。 自分ではとても思いつかない構造ばかりです。 あっちこっちからよんできているので、図やらリストやらを書いて 本当に「なんとか」理解できた、というレベルです。 クラスが5個以上になると正直もう嫌だってなります。。実用レベルにはまだまだ至っていません。 本当の意味でオブジェクト指向を理解できていないのかもしれません。 どうすればそういった、オブジェクト指向をとりいれたプログラムが書けるようになるのでしょうか? いろんなプログラムを見る、数をこなすことでしょうか? 何かおすすめの参考書や、 「こういう考え方をすれば・・・」というものがありましたら教えてください。 よろしくお願いいたします。

    • ベストアンサー
    • Java
  • 用語の違い教えてください

    win32apiというのはプログラム言語なのでしょうか?(C言語とかと同格なのか?) あとwin32api と SDK の用語の違いを教えていただけないでしょうか? WIN32APIにより作ったプログラムがSDK(マルチウィンドウではないときに限る)という意味ですか?

専門家に質問してみよう