[AB4]GetOpenFileName と OPENFILENAME について(バグ?)

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
a-code

[AB4]GetOpenFileName と OPENFILENAME について(バグ?)

#1 投稿記事 by a-code »

どうも、初めまして。
ABのバージョン4から、使用させて頂いている。a-code といいます。
AB4.04.00を現在使用中なのですが、
GetOpenFileName のAPIが何故かうまく動作してくれません。

当初、OPENFILENAME の引数を誤って指定しているのかと思い、
色々、試行錯誤しましたが、どうもうまく動作しませんでした。
そこで、ヘルプセンターにあった、
Win32プログラミング講座 ~ Step30. MCIコマンドで音楽ファイルを再生する ~
のURL取得処理をそのまま、自分のソースに記述してみたところ、それでも動作しませんでした。

http://www.discoversoft.net/help_center ... html?win32

Sub MainWnd_OpenButton_Click()
Dim ofn As OPENFILENAME
Dim buffer[MAX_PATH-1] As Byte

'ファイル名を取得
ofn.lStructSize=76
ofn.hwndOwner=hMainWnd
ofn.lpstrFilter=Ex"音楽 ファイル(*.wav;*.mid;*.mp3)\0*.wav;*.mid;*.mp3\0すべてのファイル(*.*)\0*\0\0"
ofn.nFilterIndex=1
ofn.nMaxFile=MAX_PATH
ofn.lpstrFile=buffer
GetOpenFileName(ofn)

'テキストボックスにパスを設定する
SetWindowText(GetDlgItem(hMainWnd,Static_Path),ofn.lpstrFile)
End Sub

発生するエラーは、
『例外処理 code:6B5』というメッセージボックスが表示されます。

また、ActiveBasicLife のusher@@様のサンプルをダウンロードして試しましたが、これも同様のエラーが発生致します。
http://abfan.active.client.jp/030.html

ABのIncludeフォルダの、api_commdlg.sbp にGetOpenFileName と OPENFILENAME が宣言されているのは確認しましたし、
ABにバグがあるのか、上記サンプルを ABのバージョン4で動作させる事に問題があるのかが、分かりません。
Debugでは、『Callback.wbp』にて、ボタンクリック時のエラーとして最終的に出力されるようですが、その原因を特定する事が出来ませんでした。

また、過去ログを検索したところ、
『CallBack関数でアクセス違反が起きる』も同じ原因だと思われます。
http://www.discoversoft.net/forum/viewt ... enFileName

ソース上のミスなのか、AB側のバグなのか、ソースとABバージョンの違いが原因なのか分からないので、一応、プログラミング掲示板に書き込みをさせて頂きました。
原因が、わかる方がいらっしゃいましたら、お力を貸して頂けないでしょうか。
hira
記事: 203
登録日時: 2005年5月31日(火) 20:14
お住まい: 兵庫県
連絡する:

Re: [AB4]GetOpenFileName と OPENFILENAME について

#2 投稿記事 by hira »

実は、私も同じ現象に遭遇しています(^^;
AB3の頃からですが、一部のXPユーザーに発生しているようです(発生しない環境もあります)。
山本さんからの公式アナウンスがないため、こちらも原因はわかっていません。
私の場合、このようなプログラムをテストするときはリリースコンパイルしたEXEを使う、という方法で回避しています(それでアクセス違反が起こったらその辺を詳しくデバッグコンパイルで確認)。

※タイトルは「長すぎる」と言われたので少し短くさせていただきました。
a-code

ご返信ありがとうございます

#3 投稿記事 by a-code »

hira様、お早いご返信ありがとうございます。

> 実は、私も同じ現象に遭遇しています(^^;
> AB3の頃からですが、一部のXPユーザーに発生しているようです(発生しない環境もあります)。

了解しました。以前より、特定の状況下で発生しているようですね。
ちなみに、私の環境ですが、Win2000 SP4 (フルアップデート済み)です。
NT系統は全て発生するのかもしれませんね。


> 私の場合、このようなプログラムをテストするときはリリースコンパイルしたEXEを使う、という方法で回避しています(それでアクセス違反が起こったらその辺を詳しくデバッグコンパイルで確認)。

私も、上記方法で、問題なく実行できました。
とりあえずは、GetOpenFileNameを使用する処理に関しては、この方法で対処しようと思います。

分かりやすいご回答、ありがとうございました。
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

#4 投稿記事 by マティ »

Win32プログラミング講座 ~ Step8. 構造体とファイルオープンダイアログ ~
ではOPENFILENAME構造体の初期化を行っています。

エラーが発生するケースの未設定パラメータの値を報告して頂けたら調査可能だと思います。

コード: 全て選択


	OPENFILENAME構造体の初期化
	FillMemory(VarPtr(ofn),Len(ofn),0)	'構造体を初期化
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

原因が分かったかも・・・

#5 投稿記事 by マティ »

発生条件としては、ファイルを格納しているパスがMAX_PATHよりも長い場合に発生すると考えられます。
あまり自信が無いので、皆さんで検証願います。

Win32プログラミング講座 ~ Step8. 構造体とファイルオープンダイアログ ~のサンプルでは、

コード: 全て選択


Dim buffer As String
buffer=ZeroString(MAX_PATH)
でバッファーを作成しています。この場合は、MAX_PATH+1文字分のバッファーがヒープ領域に確保されます。

a-codeさんのコードは

コード: 全て選択


Dim buffer[MAX_PATH-1] As Byte
    |
    v
ofn.nMaxFile=MAX_PATH
MAX_PATH-1分のバッファーしか確保していないのに、MAX_PATHバイト使用してもOKと、API(GetOpenFileName)に渡しています。
この為、バッファー用に取得したデータ以上にメモリをアクセスして落ちた可能性が大きいです。

その他
一般的にByte型で宣言した場合、ローカル変数の場合はスタック上に、(ワード単位で)MAX_PATH-1バイト分データ確保すると思われます。
余分にデータを書き込むとリターンアドレスやポインターを破壊して落ちる可能性がありますので・・・
これが原因かな?って思っています。
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

返信@yu0627

#6 投稿記事 by yu0627 »

「CallBack関数でアクセス違反が起きる 」という件名でで投稿したものです。
これは多分僕の文字列用バッファ確保が少なかったために起こったようです。
僕もGetOpenFileName関数を使ったソフトをデバッグすると起きます。
デバッグする時はその部分をコメントアウトしていますが。
僕の場合は「6BA」です。
僕が質問して答えが戻ってきた中によると起こりやすいのは、
「ShellExecute・GetOpenFileName・GetSaveFileName・SHBrowseForFolder」など起こるようです。
コモンダイアログが絡むAPIではほとんど×かもしれないでそうです。
また、以下のようなソースでもアクセス違反は起きます。

コード: 全て選択

'変数宣言
	Dim ofn As OPENFILENAME					'OPENFILENAME構造体
	Dim FileName[MAX_PATH] As Byte			'ファイル名

	'OPENFILENAME構造体の初期化
	FillMemory(VarPtr(ofn), Len(ofn), 0)
	ofn.lStructSize=Len(ofn)
	ofn.hwndOwner=hMainWnd
	ofn.lpstrFilter=Ex"全てのファイル(*.*)\0*\0\0"
	ofn.nFilterIndex=1
	ofn.lpstrFile=FileName
	ofn.nMaxFile=MAX_PATH
	ofn.lpstrTitle="マクロファイルを指定"
	ofn.Flags=OFN_FILEMUSTEXIST or OFN_HIDEREADONLY or OFN_PATHMUSTEXIST
	ofn.lpstrDefExt=""
このようにどちらもMAX_PATHでもアクセス違反が起きます。
あと、既出かもしれませんが「ofn.lStructSize=76」は「ofn.lStructSize=Len(ofn)」の方がいいと思います。
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

勘違いしていました。

#7 投稿記事 by マティ »

RADツールでのみ発生し、リリースコンパイルするとOKだけで判断すると、
たとえば、単体で動かすとOKであるが、SubやFunctionを経由していくと動作が不安定になっていくのなら、スタック領域不足が原因と思われます。

スタック領域不足が原因なら、領域を大きくするかローカル変数の使用量を減らして、ヒープ領域で確保するようにするしかありません。
(デフォルトのスタック領域を増やすとか、アップリが確保する領域を増やすツールもあったような気がしますが・・・やめておいた方が良いと思います)

PS.
新しいOSはスタックの消費量が増えているそうです。
http://www.microsoft.com/japan/technet/ ... pcomp.mspx
a-code

Re: 勘違いしていました。

#8 投稿記事 by a-code »

yu0627さん
追記の説明ありがとうございます。

>「ShellExecute・GetOpenFileName・GetSaveFileName・SHBrowseForFolder」など起こるようです。

これらを使用する際にも、今後確認してみたいと思います。




マティさん。

細かな説明ありがとうございます。

> RADツールでのみ発生し、リリースコンパイルするとOKだけで判断すると、
> たとえば、単体で動かすとOKであるが、SubやFunctionを経由していくと動作が不安定になっていくのなら、スタック領域不足が原因と思われます。
>
> スタック領域不足が原因なら、領域を大きくするかローカル変数の使用量を減らして、ヒープ領域で確保するようにするしかありません。

これに対してですが、FormにButtonを一つ付けただけで、GetOpenFileName関数の動作確認をするだけのアプリを作成しても発生してしまいます。
尚、これは最初に書き込みの際に、挙げたActiveBasicLife のusher@@様のサンプルとほぼ同じものです。
そこから考えると、このエラーが発生するPCで、ローカル変数の使用量を減らしても問題の解決に至るのはむずかしいと思われます。


> PS.
> 新しいOSはスタックの消費量が増えているそうです。
> http://www.microsoft.com/japan/technet/ ... pcomp.mspx

リンク先の方を確認させて頂きました。

メモリ管理
スタック消費の増加
『Windows XP では、Windows NT 4.0 より多くのスタック領域を必要とします。小さなスタックを使用するようコンパイルおよびリンクされているアプリケーションは、すぐにスタック領域を使い果たす可能性があります。』

確かに、この部分とこの先の記述を見ると、スタック領域不足が原因のような気がします。
このあたりの調査となると、C言語を得意とする人でないと調査は難しいかもしれませんね。
また、このあたりの話は、私には解りかねますが、これが原因だとすると、Win2000の私のPCでも発生する事から、それほどスペックが高くないXPユーザーの場合それなりの頻度で発生してしまうのではないかなと考えてしまいます。

Helpもしくは、制限事項等などの項目を設けて、そういったエラーが発生する可能がある事を記述した方がよりと思うのですが、いかがでしょう。
製作者の山本様も拝見する機会があったら、頭の隅にでも入れておいて下さればと思います。
まぁ、これは原因が特定された場合の話ではありますが。
返信する