こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

MapViewOfFile() はカウンタを進めない?

Windows APIの質問です。

PINT GetShareInt() {
____HANDLE hmap = CreateFileMapping(
________INVALID_HANDLE_VALUE, NULL,
________PAGE_READWRITE,
________0, sizeof(int),
________TEXT("Share") );

____PINT pi = (PINT)MapViewOfFile(
________hmap, FILE_MAP_WRITE, 0, 0, 0);
____CloseHandle(hmap);
____return pi;
}

こんな感じの関数で変数をプロセス間共有したいのですが、
ファイルマッピングオブジェクトが毎回生成されてしまい、
変数を共有できません。

先にCloseHandleするのは後の処理がUnmapViewOfFileするだけで
すむからです。変則的ですが、MapViewOfFile呼び出ししている以上
hmapが指すカーネルオブジェクトは開放されないと思うのですが。

MapViewOfFileがカーネルオブジェクトの内部カウンタを進めていない、
ということでしょうか?それではマルチスレッドで扱えないような気が
するのですが、私の認識のどこが間違っているのでしょうか?

よろしくご指導お願い申し上げます。

投稿日時 - 2005-03-05 13:08:08

QNo.1251865

暇なときに回答ください

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

#1です。

>クラスオブジェクトのデストラクタとUnmapViewOfFileの機能は違いますよね。
>スマートポインタと言うんでしょうか?
正式な用語で言うところの「スマートポインタ」とは別物ですが、考え方は同じです。
もちろんオブジェクトのデストラクタとUnmapViewOfFileの機能は全然違うものです。しかしデストラクタでUnmapViewOfFileやCloseHandleを呼び出すようにしておけば、Closeし忘れていても自動的に開放されるというわけです。


>次のようにするとマッピングオブジェクトは共有さ>れるようです。
>PVOID GetMem() {
>----HANDLE hMap = CreateFileMapping(...
>----DWORD dwEroor = GetlastError();
>----PVOIE pMem = MapViewOfFle(...
>----if (dwError) CloseHandle(hMap);
>----return pMem;
>}
この場合は2度目の呼び出しのときはCloseHandleが実行されますが、1度目のときは実行されない(dwError==0となる)ので開放し忘れに気をつける必要があると思います。この方法で共有できるようですがやはりMicrososftが意図している通りの順序(Create、Map、Unmap、Close)で使用したほうがいいと思います。



>「共有の制約」とは何のことでしょうか?
>また、今回はページングファイルに支持されたメモリマップドファイルですから例外かもしれません。
確かに考えてみたらまったく関係がないかもしれません。すみません。共有の制約というのはhFileのshare属性のように思えますので。
http://www.microsoft.com/japan/msdn/library/ja/jpmemory/html/_win32_unmapviewoffile.asp

投稿日時 - 2005-03-07 16:29:21

お礼

ご返答ありがとうございます。

単純なデストラクタとCloseHandleのやっていることとは違う、ということを言いたかったんですが、釈迦に説法のようなことをしてしまい、赤面の至りです。

msdnの関数説明のところに書いてあったんですね。文書番号や「共有の制約」などで見当違いな検索をしていました。

>1度目のときは実行されない(dwError==0となる)ので開放し忘れに気をつける必要があると思います

理解しております。今回はシステムフックするDLLにコーディングしています。つまり最初に読み込むプロセスがフックの所有者であるため、このプロセスで解放する必要がないということで前述のコードにしたわけです。

>やはりMicrososftが意図している通りの順序(Create、Map、Unmap、Close)で使用したほうがいいと思います

これについてはもちろん同意します。現在のOSで動くからといってもドキュメントされていない以上、仕様はいつ変更されるかわかりませんよね。(Microsoftは極力、動作互換性を重視してくれるとは思いますが)

SDKを使う際にはメカニズムがどうなっているのかイメージしておきたいという気持ちがありますので、他人には理解されない質問かも、と思っていました。しかし数々のアドバイスをいただき、私なりに大変勉強になりました。

ご回答本当にありがとうございました。

投稿日時 - 2005-03-07 17:22:02

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.4

ファイルマッピングとCloseHandleとはそういうものなのだと思います。

プロセスAでCreateFileMapping(..., TEXT("Share"));
プロセスAでCloseHandle
プロセスBでCreateFileMapping(..., TEXT("Share"));
プロセスBでCloseHandle
としたときに、プロセスBが新しいファイルマッピングオブジェクトを作るのは自然なことに思われます。


>MapViewOfFile呼び出ししている以上
>hmapが指すカーネルオブジェクトは開放されないと思うのですが。
「ユーザは全ハンドルを解放したが、マップトファイルが参照している」という状態で残るのかも…

解決策は、CloseHandleしない、というのが一番いいと思われます…

投稿日時 - 2005-03-07 10:29:24

お礼

私も同じ結論を仮定していました。
「ユーザはマップトファイルの全ハンドルを解放したが、最低ひとつのビューが参照している状態」ではマップトファイルは解放されていないが取得することはできない。
そういうことだと思います。

kmb01さん、回答ありがとうございました。

投稿日時 - 2005-03-07 16:19:59

ANo.3

#1です。補足になります。

MSDNではUnmapViewOfFileについて
----------------------
•Windows 95:1 つのファイルの最後のビューがまだアンマップされていない場合、そのファイルは引き続き開いていて、元のファイルハンドルと同じ共有の制約が適用されます。

•Windows NT/2000:1 つのファイルの最後のビューがまだアンマップされていない場合、そのファイルは引き続き開いていますが、共有の制約は適用されません。
----------------------
とありました。つまり、Win9x系ではyak3141さんの意図する通りに動作するのかもしれません。

投稿日時 - 2005-03-05 15:26:14

補足

次のようにするとマッピングオブジェクトは共有されるようです。

PVOID GetMem() {
----HANDLE hMap = CreateFileMapping(...
----DWORD dwEroor = GetlastError();
----PVOIE pMem = MapViewOfFle(...
----if (dwError) CloseHandle(hMap);
----return pMem;
}

投稿日時 - 2005-03-07 00:47:57

お礼

下の回答も含めてご返事が送れました。本当に丁寧な回答ありがとうございます。

「共有の制約」とは何のことでしょうか?
セキュリティフラグあるいはビューの読み書きモードのことですかね?

また、今回はページングファイルに支持されたメモリマップドファイルですから例外かもしれません。

msdnを早速探してみましたが目的の文書は見つけることはできませんでした。よろしければリンクを教えていただけないでしょうか?

回答のお礼が遅れた上でのあつかましいお願いですが、よろしければもう少しお付き合いくださいませ。

投稿日時 - 2005-03-07 00:38:26

ANo.2

#1です。

>なぜ先にCloseHandleしてはいけないのでしょうか?
>こだわるのは
>1.解放忘れがない
>2.ひとつの変数だけ保持しておけばよいので楽
>というメリットがあるからなのですが、それだけで

詳しいメカニズムについて私は知りませんが。。。普通のメモリに例えるとおそらく以下のようになっているのではないでしょうか?

BYTE* pszBuff;
char* pCopy;

pszBuff = new BYTE[10];  //メモリ確保
pCopy = (char*)pszBuff;  //アドレス取得
delete pszBuff;      //メモリ開放忘れがないように先にdelete
strcpy(pCopy,"asss");   //取得したアドレスだから使えるはずだけど。。。



開放忘れを防ぎたいというのでしたら、以下のようなクラスを作成すればいいかと思います。

class CFileMapping
{
HANDLE _hMap;
HANDLE _hMem;
public:
CFileMapping(){_hMap = NULL;_hMem = NULL;}
~CFileMapping()
{
Unmap();
Close();
}

void Unmap()
{
if(_hMem) UnmapViewOfFile(_hMem);
_hMem = NULL;
}

void Close()
{
if(_hMap) CloseHandle(_hMap);
_hMap = NULL;
}

。。。。。そのたCreateFileMappingやMapViewなどをする関数を用意
};

投稿日時 - 2005-03-05 15:07:14

お礼

再回答ありがとうございます。

クラスオブジェクトのデストラクタとUnmapViewOfFileの機能は違いますよね。スマートポインタと言うんでしょうか?

投稿日時 - 2005-03-07 00:27:10

ANo.1

>先にCloseHandleするのは後の処理がUnmapViewOfFileするだけですむからです。

これが原因ではないでしょうか?

普通は
-----------------
hMap = CreateFileMapping()
pMem = MapViewOfFile()

処理

UnmapViewOfFile (pMem);
CloseHandle(hMap);
-----------------
のように使うかと思います。

投稿日時 - 2005-03-05 13:34:31

お礼

早速の回答ありがとうございます。

質問でも述べさせていただきましたが、
なぜ先にCloseHandleしてはいけないのでしょうか?

こだわるのは
1.解放忘れがない
2.ひとつの変数だけ保持しておけばよいので楽
というメリットがあるからなのですが、それだけではなく
「MapViewOfFileした後なのに、CloseHandleするとマッピングオブジェクトが解放されてしまう」という現象をなぜそうなるのかメカニズムを知りたいと思い、質問させていただきました。

nitscapeさん、回答ありがとうございました。

投稿日時 - 2005-03-05 13:53:34

あなたにオススメの質問