[delphi-users:4607] 「access violation」エラーの対処方法

2,430 views
Skip to first unread message

遊歩人

unread,
Jan 18, 2017, 1:29:58 AM1/18/17
to delphi...@freeml.com
みなさん、こんにちは。

度々の質問で恐縮です。

前回投稿した続きですが、質問の内容が異なるため別スレッドとしました。

メインフォームに配置されているTEditのEnterイベントで、DLLを呼び出していま
す。
DLL側のフォームには、TMemoだけが配置されています。

キャレットが表示されない件は、細川さんのアドバイスで解消したのですが、メイン
フォームのクローズ時(アプリ終了時)に次の様な「アクセス・バイオレーション」
のエラーが表示されます。

「プロジェクト Project2.exe は例外クラス $C0000005 (メッセージ 'access
violation at 0x01d69c78: read of address 0x01133754')を送出しました。」

DLL呼出しで、メインフォームのTEditの内容を、DLL側のTMemoに渡し表示させていま
す。
初回のTEditに何も入力されていない場合は、DLL側で入力しアプリを終了させても正
常に終了します。

しかし、TEditに値が入っていて、DLL呼び出しが行われた後で、アプリを終了させた
ときのみ、上記エラーが表示されます。

何かヒントや、エラーの原因究明等をご存じの方はアドバイスをお願いします。

遊歩人


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
今までダイエットに失敗してきたあなた
必見です!!やせる事に特化した専門店
ミスパリダイエットセンター☆彡☆彡
今なら、5,000円で体験実施中♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=pBezz
------------------------------------------------------[freeml byGMO]--

7of9

unread,
Jan 18, 2017, 2:24:27 AM1/18/17
to delphi...@freeml.com
7of9です。


access violationですが、TShellExecuteInfoの変数に対して
::ZeroMemory()を実行していない場合に起きた経験はあります。

http://qiita.com/7of9/items/7b8e8e5ec4111df6dcf5
http://qiita.com/7of9/items/66dd24cf60273a2f5260

ただ、今回のケースでは、上記とは無関係のような気もします。

DLL側のTMemo書換えをしている、とのことで、以下のコメントが気にはなります。
http://stackoverflow.com/questions/22693514/access-violation-when-adding-multiple-lines-in-a-tmemo

> All access of UI controls must be executed on the UI thread. You'll need to queue or synchronize UI access code onto that main UI thread.

Synchronize()などは使われているのでしょうね。


7of9



> みなさん、こんにちは。
>
> 度々の質問で恐縮です。
>
> 前回投稿した続きですが、質問の内容が異なるため別スレッドとしました。
>
> メインフォームに配置されているTEditのEnterイベントで、DLLを呼び出していま
> す。
> DLL側のフォームには、TMemoだけが配置されています。
>
> キャレットが表示されない件は、細川さんのアドバイスで解消したのですが、メイン
> フォームのクローズ時(アプリ終了時)に次の様な「アクセス・バイオレーション」
> のエラーが表示されます。
>
> 「プロジェクト Project2.exe は例外クラス $C0000005 (メッセージ access
> violation at 0x01d69c78: read of address 0x01133754)を送出しました。」
>
> DLL呼出しで、メインフォームのTEditの内容を、DLL側のTMemoに渡し表示させていま
> す。
> 初回のTEditに何も入力されていない場合は、DLL側で入力しアプリを終了させても正
> 常に終了します。
>
> しかし、TEditに値が入っていて、DLL呼び出しが行われた後で、アプリを終了させた
> ときのみ、上記エラーが表示されます。
>
> 何かヒントや、エラーの原因究明等をご存じの方はアドバイスをお願いします。
>
> 遊歩人


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
■即戦力人材と企業をつなぐ転職サイト■
ビズリーチに【無料登録】すると・・・
・一流企業の求人情報を閲覧できます
・ヘッドハンターからスカウトが届きます
ビズリーチ【無料登録】ページはこちら
http://ad.freeml.com/cgi-bin/sa.cgi?id=pBeZb
------------------------------------------------------[freeml byGMO]--

Quest

unread,
Jan 18, 2017, 2:28:27 AM1/18/17
to delphi...@freeml.com
遊歩人さん、こんにちは。

プロジェクトオプションでデバッグ情報をオンにして
マップファイルを作成するとエラーが発生したアドレスから
ソースの位置が特定できますので参考になるかもしれません。

今回の場合はDLLに文字列を渡すとエラーが発生するようなので
string型の変数を格納するメモリ領域の確保方法に関する制約事項に
引っかかっているのかもしれません。
具体的にどういった制限があるのかは、私も調べないと分からないのですが
DLLと文字列を受け渡しする場合に気を付けなければいけない事があったと
記憶しています。

釈迦に説法かもしれませんが、ヒントになれば幸いです。

Quest
MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
あなたの息は大丈夫?
自分の息に自信のないあなたに!!
http://ad.freeml.com/cgi-bin/sa.cgi?id=pBfbP
------------------------------------------------------[freeml byGMO]--

hosokawa

unread,
Jan 18, 2017, 2:54:37 AM1/18/17
to delphi...@freeml.com
こんにちは。
細川です。

String 型をそのまま渡そうとしていませんか?
Exe - DLL 間で String を渡すには BorlandMM.dll が必要です。

http://docwiki.embarcadero.com/RADStudio/Berlin/ja/%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%92%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B

この場合は、String 型を使わずに PChar を使うと良いです。

例えば↓のように変更します

■元:
// DLL
procedure ShowMemo(Text: String);
begin
// 何か処理
end;

// Exe
begin
ShowMemo('あいうえお'); // Exe - DLL 間で String を単純に渡せない
end.

■変更:
// DLL
procedure ShowMemo(Text: PChar; TextLen: Integer);
var
S: String;
begin
S := String(Text);
// 何か処理
end;

// Exe
begin
ShowMemo(PChar('あいうえお'));
end.
Regards,
HOSOKAWA Jun / embarcadero MVP for Delphi
[S/G] SERIALGAMES Inc.
TEL: 03-5812-4368
FAX: 03-5812-0970

---------------------------------------------------------------
このメールには、本来の宛先の方のみに限定された機密情報が含まれて
いる場合がございます。お心あたりのない場合は、送信者にご連絡のうえ、
このメールを削除してくださいますようお願い申し上げます。
PLEASE READ:This e-mail is confidential and intended for
the named recipient only. If you are not an intended recipient,
please notify the sender and delete this e-mail.
---------------------------------------------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
☆世界初☆17種類以上のお茶がワンタッチで楽しめる
ネスレのカプセル式お茶マシン「スペシャル.T」を今なら無料でお試し!
あなたの想像を超えるお茶の世界を♪♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=pBftX
------------------------------------------------------[freeml byGMO]--

遊歩人

unread,
Feb 1, 2017, 8:34:28 AM2/1/17
to delphi...@freeml.com
細川さん、Questさん、 7of9さん こんにちは。

返信を頂いておりながら、お礼が遅くなり誠に申し訳ありません。
継続してプログラムを修正しておりますが、うまくいっておりません。

前回と変わらず、プログラム終了時に 「access violation」エラーが発生します。

今回実現しようとしている仕様は、次の通りです。
1.自前のカスタムコントロール(TCustomEditから継承)から[F4]キー押下でDLLが呼
ばれます。
2.DLL側では、TMemoに値を入力します。
3.入力された内容は、呼んだカスタムコンポーネントに都度渡される。
4.入力は、[Alt]+[End]キー押下で終了します。

尚、DLL側のコード抜粋は次の通りです。

---------------- DLL側
var
EditForm: TEditForm;

hHandle: HWnd;
hText : String;

// フォームを表示
procedure ShowEditForm(Handle: HWnd; Text: PChar; ・・・); stdcall;
// フォームを閉じる
procedure CloseEditForm; stdcall;
// テキストを返す
function GetRetText: PChar; stdcall;

procedure ShowEditForm(Handle: HWnd; Text: PChar; ・・・);
begin
hHandle := Handle;
hText := String(Text);

EditForm := TEditForm.Create(Application);
:
EditForm.Show;
end;

procedure CloseEditForm;
begin
EditForm.Close;
end;

function GetRetText: PChar;
begin
Result := PChar(EditForm.Memo.Lines.Text);
end;

遊歩人
MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
あなたの息は大丈夫?
自分の息に自信のないあなたに!!
http://ad.freeml.com/cgi-bin/sa.cgi?id=pDKf0
------------------------------------------------------[freeml byGMO]--

hosokawa

unread,
Feb 1, 2017, 8:30:25 PM2/1/17
to delphi...@freeml.com
細川です。

stdcall にしている理由は何かありますか?

Delphi - Delphi 同士であれば fastcall 以外にする理由が無さそうですが…
Regards,
HOSOKAWA Jun / embarcadero MVP for Delphi
[S/G] SERIALGAMES Inc.
TEL: 03-5812-4368
FAX: 03-5812-0970

---------------------------------------------------------------
このメールには、本来の宛先の方のみに限定された機密情報が含まれて
いる場合がございます。お心あたりのない場合は、送信者にご連絡のうえ、
このメールを削除してくださいますようお願い申し上げます。
PLEASE READ:This e-mail is confidential and intended for
the named recipient only. If you are not an intended recipient,
please notify the sender and delete this e-mail.
---------------------------------------------------------------


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
☆世界初☆17種類以上のお茶がワンタッチで楽しめる
ネスレのカプセル式お茶マシン「スペシャル.T」を今なら無料でお試し!
あなたの想像を超えるお茶の世界を♪♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=pDNTf
------------------------------------------------------[freeml byGMO]--

中村拓男(自宅)

unread,
Feb 1, 2017, 8:59:35 PM2/1/17
to delphi-users

>function GetRetText: PChar;
>begin
>  Result := PChar(EditForm.Memo.Lines.Text);
>end;

これ大丈夫でしたっけ?

EditForm.Memo.Lines.Text が生成した String型
の寿命は end; で終わると考えた方が良いと思う。

PCharのキャストの返すのは stringの内部への
ポインタだからやばそう。

-- Takuo Nakamura, Hino City Tokyo Japan

Fukushi

unread,
Feb 2, 2017, 4:55:05 AM2/2/17
to delphi...@freeml.com
遊歩人さん、こんにちは。福士です。

> 前回と変わらず、プログラム終了時に 「access violation」エラーが発生します。
> (略)

中村さんからも指摘されてますが、

> function GetRetText: PChar;
> begin
> Result := PChar(EditForm.Memo.Lines.Text);
> end;

これはまずそうです。呼び出し元に渡されるポインタはDLL内の内部的な
メモリのアドレスで、しかもプロパティのアクセスメソッドで確保された
右辺値的な領域ですので、いつまで有効にアクセスできるかの保証が
ありません(文字列なので参照カウントが0になったらいつでも破棄できる)。

DLLから文字列を返すAPIを作る場合、Win32APIのアプローチが参考に
なります。一般的には、文字列を格納して返すための領域のアドレスと
領域のサイズを渡し、戻値として実際の文字列の長さ(アドレスがNULLの
ときは必要な領域のサイズ)を返すようなやり方でしょうか。例えば
DLL側は

function GetRetText(Buf: PChar; Len: DWORD): DWORD;
begin
Result := Length(EditForm.Memo.Lines.Text);
if Buf <> nil then
begin
StrPLCopy(Buf,EditForm.Memo.Lines.Text,Len);
if Result > Len then
begin
Result := Len;
end;
end;
end;

こんな感じにして、呼び出し側では

var
S: String;
Len: DWORD;
begin
Len := GetRetText(nil,0);
SetLength(S,Len);
Len := GetRetText(PChar(S),Len);
SetLength(S,Len);

こんなふうに使います。参考にしてください。

---
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fuk...@tts-inc.co.jp


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
今までダイエットに失敗してきたあなた
必見です!!やせる事に特化した専門店
ミスパリダイエットセンター☆彡☆彡
今なら、5,000円で体験実施中♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=pDUmX
------------------------------------------------------[freeml byGMO]--

遊歩人

unread,
Feb 2, 2017, 7:45:36 PM2/2/17
to delphi...@freeml.com
細川さん、中村さん、 福士さん こんにちは。

アドバイスありがとうございます。

今回のDLLは、すでに色々な機能が組み込まれており、他言語からの利用も想定して
おります。

現在の状況をお知らせします。
皆さんのアドバイスは、文字列渡しに原因があるのでは?と言うことでしたので、DLL
とのインターフェースからすべて文字列定義を省いて実行してみました。

この状態で実行した結果ですが、やはり「access violation」エラーが発生してしま
います。

文字列渡しの部分は、後ほど皆さんのアドバイスを参考に修正したいと思いますが、
何か他に根本的に問題があるような気がしております。

例えば・・
メインのVCLのスレッドから、動的リンクされたDLL側でキーボード入力可能なTMemo
は使えないとか・・
この様な場合、マルチスレッドにする必要があるとか・・

基本的なところが分かっていないのかも知れませんが、引き続きアドバイスをお願い
します。

尚、デバッグモードで「access violation」エラーが発生する以外は、当初の仕様を
すべて実現できております。

お手数をお掛けしますが、宜しくお願いいたします。

遊歩人


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
■即戦力人材と企業をつなぐ転職サイト■
ビズリーチに【無料登録】すると・・・
・一流企業の求人情報を閲覧できます
・ヘッドハンターからスカウトが届きます
ビズリーチ【無料登録】ページはこちら
http://ad.freeml.com/cgi-bin/sa.cgi?id=pDZEG
------------------------------------------------------[freeml byGMO]--

高木太郎

unread,
Feb 4, 2017, 7:57:51 AM2/4/17
to delphi...@freeml.com
 こんにちは、イマジオムの高木です。 いつもお世話に
なっております。

遊歩人さん:
> 尚、DLL側のコード抜粋は次の通りです。
>
> ---------------- DLL側
> var
> EditForm: TEditForm;
>
> hHandle: HWnd;
> hText : String;
>
> // フォームを表示
> procedure ShowEditForm(Handle: HWnd; Text: PChar; ・・・); stdcall;
> // フォームを閉じる
> procedure CloseEditForm; stdcall;
> // テキストを返す
> function GetRetText: PChar; stdcall;
>
> procedure ShowEditForm(Handle: HWnd; Text: PChar; ・・・);
> begin
> hHandle := Handle;
> hText := String(Text);
>
> EditForm := TEditForm.Create(Application);
> :
> EditForm.Show;
> end;
>
> procedure CloseEditForm;
> begin
> EditForm.Close;
> end;
>
> function GetRetText: PChar;
> begin
> Result := PChar(EditForm.Memo.Lines.Text);
> end;

> 現在の状況をお知らせします。皆さんのアドバイスは、
> 文字列渡しに原因があるのでは?と言うことでしたので、
> DLLとのインターフェースからすべて文字列定義を省いて
> 実行してみました。
>
> この状態で実行した結果ですが、やはり「access
> violation」エラーが発生してしまいます。
>
> 文字列渡しの部分は、後ほど皆さんのアドバイスを参考に
> 修正したいと思いますが、何か他に根本的に問題がある
> ような気がしております。

 TEditForm.Create() の AOwner 引数に Application を
渡されていますが、これを nil にするとどうなりますか?
私の記憶が間違っているかもしれませんが、DLL内での
Application は呼び出し元と同じである保証はなかった
ように思います。

 また作成したフォームはどのように破棄されていますか?
たとえばフォームで発生したイベントでフォーム自体を
破棄するようなことをすると、フォーム側ではイベントを
呼び出した後の戻り場所がなくなっていてアクセス違反が
発生することがあります。


> 例えば・・
> メインのVCLのスレッドから、動的リンクされたDLL側で
> キーボード入力可能なTMemoは使えないとか・・
> この様な場合、マルチスレッドにする必要があるとか・・

 それは大丈夫です。 DLLの中でも、呼び出し元での
機能は一とおり使えると考えてかまいません。 たいていの
ことはできます。 上記の二つを疑ってみてください。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/


MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
あなたの息は大丈夫?
自分の息に自信のないあなたに!!
http://ad.freeml.com/cgi-bin/sa.cgi?id=pErF7
------------------------------------------------------[freeml byGMO]--

7of9

unread,
Feb 5, 2017, 7:56:21 PM2/5/17
to delphi...@freeml.com
遊歩人さん
cc: 皆様


7of9です。

色々お疲れさまです。

問題の解消が難しいようですね。

一つ提案させていただきます。

問題が再現する最低限のコードにしてみて、対策方法を検討されてはいかがでしょうか?

方法として、以下のいずれかが考えられます。

1. 既存のDLLをコピーして、機能を省いていく
- ある機能を省いた時点で問題が発生しなくなるかどうか
- 最後まで問題が発生する場合、その「残り」に問題がはらんでいる
2. 新規DLLを作成して、問題の再現しそうな部分だけを実装する

コードが最低限になれば、回答者の方でも同じ再現を試みることができ、より良い回答が来る可能性があります。

すでにそういうことをしていて現状の状況でしたら、提案自体が間違いですみません。




MLホームページ: http://www.freeml.com/delphi-users

----------------------------------------------------------------------
☆世界初☆17種類以上のお茶がワンタッチで楽しめる
ネスレのカプセル式お茶マシン「スペシャル.T」を今なら無料でお試し!
あなたの想像を超えるお茶の世界を♪♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=pE2Zy
------------------------------------------------------[freeml byGMO]--

Reply all
Reply to author
Forward
0 new messages