LHA圧縮ファイルの解凍プログラムを作っています。
色々調べて次のコードを書きました。
HARC hArc = UnlhaOpenArchive(m_hWnd, _T(NOTE.lzh), M_ERROR_MESSAGE_ON);
INDIVIDUALINFO g_ii;
UnlhaFindFirst(hArc, _T(*.*), &g_ii);
UnlhaCloseArchive(hArc);
DWORD g_len = g_ii.dwOriginalSize;
TCHAR szBuf[256];
wsprintf(szBuf, _T(NOTE.lzh c: %s), g_ii.szFileName);
BYTE* g_buf = new BYTE[g_len];
UnlhaExtractMem(m_hWnd, szBuf, g_buf, g_len, NULL, NULL, &g_len);
if (g_buf) delete [] g_buf;
Debug で実行すると、「0x75327ee4 で初回の例外が発生しました: 0xC0000005: 場所
0x00000000 を読み込み中にアクセス違反が発生しました。」というメッセージが出ま
す。
UnlhaExtractMem() の前の行まではOKです。
g_buf に原因がありそうですが何故か解りません。
初心者です。どうぞよろしくお願いいたします。
>場所 0x00000000 を読み込み中にアクセス違反が発生しました。
0 番地にアクセスしようとしたのだからアクセス違反となるのは
当たり前のように思います。
ただ、使用しているOSのバージョンが不明なので 0 番地にアクセス
しただけで、アクセス違反になると判断するのは危険ですが....。
XP 以降のOSであればヌルポインターによるアクセス検出のために
若い番地はアクセス違反になるようになっています。
使用しているコンパイラーやOSについての情報は忘れずに書いてください。
何故 0 番地にアクセスするのかが解らないのです。
開発環境は Windows 7、Viaual Studio 2010 で、MFC、ダイアログベース・アプリで
す。
メモリ(g_buf)にファイルの内容が正しく入っていることを、この後のコードで確認して
います。
UNLHA32使ったプログラミングしたことはありませんが……
>wsprintf(szBuf, _T(NOTE.lzh c: %s), g_ii.szFileName);
メモリに展開するならばc:は不要だったりしませんか?
>INDIVIDUALINFO g_ii;
>DWORD g_len = g_ii.dwOriginalSize;
>BYTE* g_buf = new BYTE[g_len];
プレフィクスにg_とかついていますが、グローバル変数とかそういったことは?
寿命や他で書き換えているとかそういうコトはない…ですよね?
UnlhaFindFirst()で失敗していて、g_iiに不正な値が入っていた…とかいうことはありま
せんか?
手掛かりが足りなくて何がいけないかまでは分りません。
そもそも UnlhaXXXX() という関数があなたの自作なのか、
どこかからダウンロードした DLL の関数なのかも分りません。
>HARC hArc = UnlhaOpenArchive(m_hWnd, _T(NOTE.lzh), M_ERROR_MESSAGE_ON);
>UnlhaFindFirst(hArc, _T(*.*), &g_ii);
>BYTE* g_buf = new BYTE[g_len];
1-1)hArc にはどんな値が返ってきましたか?
1-2)UnlhaFindFirst() の戻り値は何でしょうか?
1-3)g_buf にはどんな値が入りましたか?
UnlhaExtractMem() の中で 0 番地にアクセスしていることが確かなら
UnlhaExtractMem() の中に入ってデバッガーで追いかけてみるといいかもしれません。
>メモリ(g_buf)にファイルの内容が正しく入っていることを、この後のコードで
>確認しています。
UnlhaExtractMem() で落ちるのに、その後のコードで中身が確認できるとは意味が
よく分りません。
2-1)正しい内容とは、圧縮した結果が入っているということなのか、
伸張(解凍)した結果が入っているということなのかどちらでしょうか?
瀬戸っぷ様、有り難うございます。
> メモリに展開するならばc:は不要だったりしませんか?
c:を取り除いても結果は同じで、アクセス違反が生じます。
> プレフィクスにg_とかついていますが、グローバル変数とかそういったことは?
その通りです。
参考にしたサンプルが WinAPI で、これらはグローバル変数となっています。
自分のプログラムはMFCで、これらの変数は一つの関数の中だけで使っていて、記号
をそのままにしているだけです。
> 寿命や他で書き換えているとかそういうコトはない…ですよね?
はい。
> UnlhaFindFirst()で失敗していて、g_iiに不正な値が入っていた…とかいうことはあ
りませんか?
UnlhaFindFirst()の戻り値は確認していて失敗はしていません。
g_ii は、次のファイルサイズ g_len を確認していて正しいです。
しま様
> そもそも UnlhaXXXX() という関数があなたの自作なのか、
> どこかからダウンロードした DLL の関数なのかも分りません。
LHA形式の圧縮/解凍を行うライブラリ UNLHA32.DLL の中の関数です。
提供元: http://www.csdinc.co.jp/archiver/lib/unlha32.html
> 1-1)hArc にはどんな値が返ってきましたか?
正常時:指定の書庫ファイルに対応したハンドルが返される。
エラー時:NULL が返される。
となっていますが、正しくハンドルが返っています。
> 1-2)UnlhaFindFirst() の戻り値は何でしょうか?
正常終了:0
検索終了:-1
エラー時:0、-1 以外の値
自分の場合、0 が返っています。
> 1-3)g_buf にはどんな値が入りましたか?
対象としている書庫ファイル NOTE.lzh の中身は、テキストファイル NOTE.txt で
す。g_buf には NOTE.txt の内容が正しく入っています。
> 2-1)正しい内容とは、圧縮した結果が入っているということなのか、
> 伸張(解凍)した結果が入っているということなのかどちらでしょうか?
後者です。
> UnlhaExtractMem() で落ちるのに、その後のコードで中身が確認できるとは意味が
> よく分りません。
UnlhaExtractMem() の戻り値は、正常終了時:0、エラー時:0以外ですが、0 が返っ
ています。落ちてはいないでしょう。
> UnlhaExtractMem() の中で 0 番地にアクセスしていることが確かなら
> UnlhaExtractMem() の中に入ってデバッガーで追いかけてみるといいかもしれませ
ん。
初心者のため、ライブラリの中の関数に入ってデバッガーで追いかけるなんてことはで
きそうにありません。
>UnlhaExtractMem() の戻り値は、正常終了時:0、エラー時:0以外ですが、0 が
>返っています。落ちてはいないでしょう。
>>Debug で実行すると、「0x75327ee4 で初回の例外が発生しました: 0xC0000005:
>>場所 0x00000000 を読み込み中にアクセス違反が発生しました。」
>>というメッセージが出ます
>>UnlhaExtractMem() の前の行まではOKです。
>>g_buf に原因がありそうですが何故か解りません。
という文章から UnlhaExractMem() で初回例外が... のメッセージが
UnlhaExtractMem() 実行中に出たのだと判断しましたが、そうではないのですね?
ではこのメッセージはどの行(関数)を実行中に出るのでしょうか?
違ってたらすいません。
UnlhaExtractMem というのは、関数ポインタのtypedefだったりしませんか?
で、GetProcAddress()した値を入れる処理を忘れてて、初期化時に代入した
NULL値のままアクセスしてるとか?
きになるところ
1.
>TCHAR szBuf[256];
ファイル名のみではいざ知れず、パス名の場合256バイトで足りなくなる
可能性大です。512バイト以上にしたほうがいいです。
2.
> DWORD g_len = g_ii.dwOriginalSize;
いつも問題になるけれども
>BYTE* g_buf = new BYTE[g_len];
は、
BYTE* g_buf = new BYTE[g_len + 1];
じゃないですか?
できれば、+100ぐらいしてもいいと思います。
あと、newを使うなら変数でなく数値で決めて設定した方がいいと思います。
ですね。
bun様
> UnlhaExtractMem というのは、関数ポインタのtypedefだったりしませんか?
typedef ではありません。
> GetProcAddress()した値を入れる処理を忘れてて・・・
DLLの呼び出しは UNLHA32.LIB ファイルをリンクして行っています。
#pragma comment(lib, UNLHA32.LIB)
GetProcAddress()はしていません。
ITO様、いつも有り難うございます。
1.
はい、そう思ってその後 1024 にしていました。
2.
これは元々 BYTE* g_buf = new BYTE[g_len + 1]; にしていました。
というのは、このあとのコードで g_buf の最後に '\0' を追記しています。
g_buf[g_len] = '\0';
質問するときに整理の意味で new BYTE[g_len]; と書きました。
UNLHA32.DLL の最新バージョン Ver 2.67a を使っていたのですが、これを1つ前のバー
ジョン Ver 2.02e に置き換えたら、アクセス違反は生じなくなりました。
解決済みですが、
バージョンに関わることは、作者に問い合わせた方がいいです。
DLLのバグならいいのですが、初期化の手順等で状態が変化するとややこしくなりますよ
ね。
UNLHA32.DLL を旧バージョンにしたらアクセス違反がなくなったというのは間違いでし
た。やはり発生します。
しかし、色々やっているときにアクセス違反が出なかったときがあったのも事実です。
> 初期化の手順等で状態が変化するとややこしくなりますよね。
このあたりにも注目して更に調べます。