#pragma twice

KAB-studio > プログラミング > #pragma twice > 146 Version 8.04 プロセスとインスタンスハンドル

#pragma twice 146 Version 8.04 プロセスとインスタンスハンドル

前のページへ 表紙・目次へ 次のページへ

 Version 8.04
プロセスとインスタンスハンドル

前回は
っつーか、ここ最近インスタンスハンドルばっかり
インスタンスハンドルというよりは、メモリ関係の話ってところかな。こ
の辺は C++ 言語では切っても切れない話だから
うー
さて、まずは前回見たようなプログラムから

#include <Windows.h>
#include <stdio.h>

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // インスタンスハンドル( p_hPrevInstance )
    // を文字列化します。
    char pchMsg[1024];
    sprintf( pchMsg, "HINSTANCE(PREV) : %x", p_hPrevInstance );
    // それを表示。
    MessageBox( NULL, pchMsg, "WinMain()", MB_OK );
    return 0;
}

ホント、似てるね。んーっと、 p_hInstance が p_hPrevInstance になっ
てるだけだ
そう、今回は p_hPrevInstance 、つまり WinMain() の第2引数に何が渡
されてるかを見ていきます
そういえば第1引数も第2引数もインスタンスハンドルだよね。ちょっと

ではその謎な値を見てみましょう
ビルドして実行! ……あれ?  0 だって
そう、ゼロ。 WinMain() のリファレンスにも書いてあるけど、この第2
引数には必ず 0 が渡されるんです
リファレンスには〈 NULL が渡される〉って書いてあるけど
同じことだよ。 Version 5.11 ( No.076 ) 参照
あー、そっか。ハンドルもポインタだしね
そうそう。で、これがなぜゼロなのか
そうよ、必ず 0 なら、こんな引数要らないじゃない
そう、今はね
今は? これから必要になるの?
これからじゃなくて、昔必要だったんです。実は、昔はインスタンスハン
ドルは一定じゃなかったから
へ? だって、 0x00400000 で全部同じだったじゃない。昔はそうじゃな
かったの?
正確に言えば、 Windows 3.1 以前の OS はそうだったんです。この前、
メモリとかアドレスとかは仮想のものだって言ったよね
うん、ハードウェアのメモリのアドレスじゃなくて、それとは違うアドレ
スなんだよね
そうそう。で、その仮想アドレス、実は Windows 3.1 とか MS-DOS の時
代にはなかったんです
なかった?
その頃は、ハードウェアのメモリに直に実行ファイルや変数が置かれてた
んです
ってことは、アドレスもハードウェアのメモリ上のそのもの?
そのもの。で、実はそれはまずいんです
まずい?
今の仮想メモリの場合……そうだね、前回みたいに何回も起動したとしま

ダブルクリックしまくってね
その中で、一番最初に実行したのから、2番目に実行したのの変数を見た
り書き換えたりするのってどうすればいいと思う?
どうすれば……って、それ無理なんじゃない!?
そう、無理なんです。実行したものそれぞれに仮想メモリが存在するわけ
だから
他の仮想メモリを見たくても、結局自分の仮想メモリを見ちゃうわけね
これはとても安全なんです。他から邪魔されないから
なるほど、ハードウェアのメモリに全部置かれてると、他のアプリの邪魔
が出来ちゃうんだ
わざとするのももちろん、プログラムミスで
げ!
ま、逆にだから速い処理もできたりするんだけどね
速い処理?
……まぁそれは置いといて、歴史的には

MS-DOS や Windows 3.1 : ハードウェアのメモリのアドレス : 危険
Windows95 以降 : 仮想メモリ、仮想アドレス : 安全

っていう経緯があるわけです
安全な方に移ったわけね
で、昔の危険な頃は、ハードウェアのメモリ上にアプリが散在してまし
た。なので、その場所を知る必要があったんです。それがインスタンスハ
ンドル
おお!
この頃は、インスタンスハンドルはまさにアプリのハンドル。ひとつ実行
すると、ひとつメモリに置かれて、その先頭のアドレスがインスタンスハン
ドルとして渡される
実行されるごとの、まさに背番号ね
と、この〈実行される単位〉を【プロセス】って言います
プロセス?
 proccess は〈進行〉とか〈過程〉とか言うんだけど
結果じゃなくプロセスが大事、とか言うもんね
まぁあんまりニュアンスが分かりづらいから〈処理単位〉くらいに訳した
方がいいかも
テキトーねー
ま、それはともかく。アプリを実行する度に、仮想メモリがひとつ作られ
て、その中に実行ファイルとか変数が置かれます。このかたまりがプロセス
になります
実行する度に作られるものなのね
そうそう。 VC に付いてくる Process Viewer を使うと今作られてるプロ
セス全部を見ることが出来るから、一度見ておいて
はーい。で、話を戻して、もうひとつの p_hPrevInstance はなんなの?
これは previous なインスタンスハンドル。 previous は〈前〉って意

プレビューとか言うもんね。でもひとつ前のインスタンスハンドルっ
て?
そのまま。実行ファイルを数回起動してその都度プロセスが作られた時
に、ひとつ前に作られたプロセスのインスタンスハンドルがそう
??
あ、これは昔のイメージで考えないと分からないよ。たとえば

昔のメモリ
[アドレス]
1000 : ひとつめのプロセスの置かれた場所(=インスタンスハンドル)。
1001
...
3000 : ふたつめのプロセスが置かれた場所。
3001
...
5000 : みっつめのプロセスが置かれた場所。
5001

って場合に、みっつめのプロセスでは p_hPrevInstance には 3000 が渡
されることになります
あ、そういう〈ひとつ前〉ね
そゆこと。で、これが今は 0 なのは分かるよね
もちろん。だって、仮想メモリだと全部同じなんだもの。ひとつまえのイ
ンスタンスハンドルは自分と同じだし、ハードウェアのはもらっても仕方な
いし
そういうこと。こういう経緯で、昔は必要だったんだけど、今は必要な
いっていうかどうしようもないから 0 が渡されるんです
なるほどねー。でも、必要って何に使うの?
たとえば、複数起動を防ぐ場合。アプリの中には〈ひとつだけしか実行さ
せたくない〉って場合あるでしょ
ユーティリティとかそういうの多いよね
昔は、それを実現するために p_hPrevInstance を使ってたんです。 
p_hPrevInstance には直前のプロセスのインスタンスハンドルが入ってるわ
けだけど、もし直前のがない、つまり最初に実行された時には 0 が入って
るんです
ってことは p_hPrevInstance に 0 が入ってたらそのまま実行、それ以外
のが入ってたら何もせずに終了
っていうことをしてたんです。たとえばこんな感じ

#include <Windows.h>

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // NULL じゃないということはすでに実行されているので
    // 何もしません。
    if( p_hPrevInstance != NULL )
    {
        return 0;
    }

    // あとは普通に。
    MessageBox( NULL, "テスト", "WinMain()", MB_OK );
    return 0;
}

なるほどねー
重要なのは、このプログラム、機能はしないけど、エラーにもならないっ
てこと
そりゃそうよね、 p_hPrevInstance は 0 に決まってるんだから
わざとそうしてるってことも言えるかな。もしこれが -1 を返すように
なってたら
このプログラム、使えないね
つまり、 Windows3.1 のプログラムを Windows98 に使えるようにするの
に修正しなきゃいけない
げげ
これは WinMain() もそう。もし p_hPrevInstance が必要ないってことで 
WinMain() の引数が3個になったら
それも修正しなきゃいけない! めんどくさー
今の時代は必要ないものが残ってるのは、そういう理由があるんです
でもそれなら〈いらない〉って一言でいいんじゃ
一言でいいの?
うーん……

/*
    Preview Next Story!
*/
インスタンスハンドル、なんかポインタ編みたいな感じ
実際、このバージョン8はそういう話多いかも
む、結構手強いかも
本当はねー、こういうの知らなくてもプログラム組めるんだけど
ってゆーかずっと知らなかったし
でも一歩上を目指すには必要だから
ホントにぃ?
というわけで次回
< Version 8.05 コマンドラインと表示方法 >
につづく!
頂点を目指すために!
ってゆーか目指す必要あるの?
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。