XE5のVCLプログラムを10Seattleにコンバートしています。
メイン側のStyleをDll側TFormにも適用する処理で、XE5では問題ないのですが
10SeattleではDll側のTStyleManager.SetStyleコール後、メイン側のTMainMenuを
DropDownしてClickすると「access violation」エラーが発生してしまいます。
(メインとDll両方が10Seattleでビルドされている時のみの様です)
どなたか対処法が解る方いらっしゃいますか?
環境は Win10+Delphi10 Seattle(Update 1とUpdate 1 Hotfixまでは適用済)です。
よろしくお願いします。
[Unit1.pasの一部]
object MainMenu1: TMainMenu
Left = 40
Top = 32
object N0: TMenuItem
Caption = #12501#12449#12452#12523
object N1: TMenuItem
Caption = #32066#20102
OnClick = N1Click
end
end
end
[Unit1.pas]
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.StdCtrls;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
N0: TMenuItem;
N1: TMenuItem;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure N1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
procedure DllSetStyle(AFileName: string); external 'DllForm.dll';
implementation
uses
Vcl.Themes, Vcl.Styles;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
FileName: string;
begin
FileName := ExtractFilePath(Application.ExeName) + 'Auric.vsf';
TStyleManager.SetStyle(TStyleManager.LoadFromFile(FileName));
DllSetStyle(FileName);
end;
procedure TForm1.N1Click(Sender: TObject);
begin
Self.Close;
end;
end.
[DllForm.dpr]
library DllForm;
uses
System.SysUtils, System.Classes, Vcl.Themes, Vcl.Styles;
{$R *.res}
procedure DllSetStyle(AFileName: string);
begin
TStyleManager.SetStyle(TStyleManager.LoadFromFile(AFileName));
end;
exports
DllSetStyle;
begin
end.
まずはDLLを新規作成するとdprojに自動的に書き込まれる
{ DLL のメモリ管理に関する重要なメモ: パラメータまたは関数結果として文字列を渡す
手続きまたは関数を DLL がエクスポートする場合は、ShareMem をライブラリの
uses 句およびプロジェクトの uses 句 ([プロジェクト|ソースの表示] を選択) の
最初に記載する必要があります。これは、
DLL との間で渡されるすべての文字列に当てはまります。レコードやクラスに
ネストされているものも同様です。ShareMem は共有メモリ マネージャ BORLNDMM.DLL に対するインターフェイス
ユニットです。この DLL は作成対象の DLL と一緒に配置する必要が
あります。BORLNDMM.DLL を使用しないようにするには、PChar 型または ShortString 型の
パラメータを使って文字列情報を渡します。}
というコメントの内容はクリアできていますか?
通りすがりさん、ご回答ありがとうございます。
何やら面倒そうなので、テスト的にdllのDllSetStyle関数は引数なしに変更してみました。
しかし、結果は全く同じでした。
[Unit1.pas]
procedure DllSetStyle; external 'DllForm.dll'; //<--ここ
procedure TForm1.Button1Click(Sender: TObject);
var
FileName: string;
begin
FileName := ExtractFilePath(Application.ExeName) + 'Auric.vsf';
TStyleManager.SetStyle(TStyleManager.LoadFromFile(FileName));
DllSetStyle; //<--ここ
end;
[DllForm.dpr]
procedure DllSetStyle; //<--ここ
var
FileName: string;
begin
FileName := ExtractFilePath(Application.ExeName) + 'Auric.vsf';
TStyleManager.SetStyle(TStyleManager.LoadFromFile(FileName));
end;
うーん、違いましたか。ところでAVが起きるのはDLL内ですか?それとも呼び出し元に戻ってきたときですか?
はたまた呼び出し元に戻った後の処理ですか?(疑っているのは呼び出し規約がEXEとDLLで一致していない状況です)
通りすがりさん、ご回答ありがとうございます。
[メイン側の.dfm]
object MainMenu1: TMainMenu
object N0: TMenuItem
Caption = 'ファイル'
object N1: TMenuItem
Caption = '終了'
OnClick = N1Click
end
end
end
その後もう少し検証してみたところ、Dll側のTStyleManager.SetStyleコール後、
メイン側のMainMenu1のN0(ファイル)をDropDown後フォーム内のどこかClickして、
MainMenu1のDropDownリストをクローズする時に「access violation」エラーが
発生いているようです。
MainMenu1のDropDownリストのクローズ以外は、メイン側フォームもdll側フォームも
正常にStyleが適用されていて動作も問題ありません。
(メインとDll両方が10Seattleでビルドされている時のみの様です)
exe, dll
XE5, XE5 => OK
XE5, D10 => OK
D10, XE5 => OK
D10, D10 => NG <--この組み合わせだけエラーになる!
よろしくお願いします。
呼び出し規約を明示的に指定したらどうなります?
[Unit1.pas]
procedure DllSetStyle; stdcall; external 'DllForm.dll';
[DllForm.dpr]
procedure DllSetStyle; stdcall;
var
...
通りすがりさん、ご回答ありがとうございます。
ご指摘の通り stdcall; を追加してみましたが、
結果は全く同じでした。
うーん、呼び出し規約はとりあえず無罪ですか。DLL側のDllSetStyleの内容を無難なもの
(ラベルのCaptionを変更するだけとか)に変えたらどうでしょう?
# EXE側で呼び出し前後のスタックの状況とかCPUウィンドウ上で確認してみると何か判るかも…
# あとは公式フォーラムあたりで最低限の再現プロジェクトをつけて質問してみるとか。
詳しい状況が分からないのですが,
一般的に,VCL スタイルの適用は,アプリケーションの初期化の時,あるいは,DLL の生成時が基本です.
そうしないと,access violation (アクセス違反) が発生ことがあります.
Delphi XE5 で何故アクセス違反が発生しないかは,分かりません.
以下に,関係記事を追加してみました.参考になれば.
MDI のサンプル以外は,Delphi 10 Seattle (Subscription UP1) 試用版で動作確認しています.
[889_VCL スタイルをリソースとして埋め込んで使用]
http://mrxray.on.coocan.jp/Delphi/plSamples/889_VCLStyleResource.htm
その他,「delphi VCLスタイル」でググるといろいろ情報があるようです.
ただし,利用する時の注意等は,ひっそりと書かれている場合があります.
>以下に,関係記事を追加してみました.参考になれば.
>MDI のサンプル以外は,Delphi 10 Seattle (Subscription UP1) 試用版で動作確認しています.
TMainMenu のアイテムで,Close した時にアクセス違反が発生する現象については,全く分かりません.
>TMainMenu のアイテムで,Close した時にアクセス違反が発生する現象については,全>>く分かりません.
引き続きやってみました.
以下の条件で発生するようです.
(1) フォームを実装した DLL を作成
(2) その DLL を使用するプロジェクトを作成
(3) そのプロジェクトに VCL スタイルを設定
(3) そのプロジェクトに TMainMenu を配置
その TMainMenu にアイテムを追加
イベント等の設定は必要ない
プロジェクトをコンパイルして実行.
DLL の生成時または,EXE を実行して DLL に VCL スタイルを適用する.
TMainMenu をクリックしてメニューを表示して,メニューをクリック
これで,アクセス違反,あるいは,「Project1.exe は動作を停止しました」のダイアログが現れます.
プロジェクトと DLL の両方に VCL スタイルを適用した場合に発生するようです.
どちらか一方だけに VCL スタイルを適用した場合は発生しません.
Delphi XE7, Delphi 10 Seattle で発生します.Delphi XE6, XE8 は未確認です (手元にないので).
バグっぽいですが,もう少し確認する必要がありそうです.
DLL でフォームを使用なければ問題ないと思うのですが.
Mr.XRAYさん、色々検証ありがとうございます。
http://mrxray.on.coocan.jp/Delphi/plSamples/889_VCLStyleResource.htm
上記URLを参考に、procedure DLLEntry(Reason: Integer); でやってみましたが
ダメでした。
Windows10で超シンプルなプロジェクトを作成し検証しました。
1.SetStyleするDllForm.DLLを作成
2.SetStyleするDllStyle.exeアプリを作成(TFormにTEditを配置)
[DX10での現象]
1.アプリのみSetStyleした時は問題ない
2.DLLのみSetStyleした時は、アプリ側のTEditを右クリックしてメニューアイテムを開くと
すでにDLLでセットしたStyleが適用済みになっている(アプリ側でSetStyleしてないのに..)
3.アプリとDLLでSetStyleすると、TEditを右クリックしてメニューアイテムをColseすると
access violation例外は発生する
4.XE5では、2,3の現象は発生しない。
※DX10のTMenuItem系に問題がありそうです。
>DLL でフォームを使用なければ問題ないと思うのですが.
それは、重々承知のうえで....
以下が検証の全ソースです。
[DllForm.dpr]
library DllForm;
uses
Winapi.Windows, System.SysUtils, System.Classes, Vcl.Themes, Vcl.Styles;
{$R *.res}
procedure DllDummy; stdcall;
begin
end;
exports
DllDummy;
begin
TStyleManager.SetStyle(TStyleManager.LoadFromFile('Auric.vsf'));
end.
[DllStyle.dpr]
program DllStyle;
uses
System.SysUtils, System.Classes, Vcl.Themes, Vcl.Styles, Vcl.Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
TStyleManager.SetStyle(TStyleManager.LoadFromFile('Auric.vsf'));
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
[Unit1.pas]
unit Unit1;
interface
uses
System.Classes, System.SysUtils, Vcl.Forms, Vcl.StdCtrls, Vcl.Controls;
type
TForm1 = class(TForm)
Edit1: TEdit;
end;
var
Form1: TForm1;
procedure DllDummy; stdcall; external 'DllForm.dll';
implementation
uses
Vcl.Themes, Vcl.Styles;
{$R *.dfm}
initialization
DllDummy;
end.
えーと、
> library DllForm;
> ...
> begin
> TStyleManager.SetStyle(TStyleManager.LoadFromFile('Auric.vsf'));
> end.
これは多分駄目です(本筋には関係ないかもしれませんが)。
DLLMainに相当するこの部分では最低限の処理しか行うべきではありません。
なぜ、XE5でTMenuItemのaccess violation例外が発生しないか判りました!
そもそも、XE5ではSetStyleしてもTMenuItemはStyleが適用されていない事に
今さら気が付きました。(DX10は適用されています)
※XE5以降のバージョンで、この問題を解決しようとした事によるエンバグ?...
通りすがり 、ご回答ありがとうございます。
>DLLMainに相当するこの部分では最低限の処理しか行うべきではありません。
無理矢理ですが、本筋とは関係なさそうなので。
>そもそも、XE5ではSetStyleしてもTMenuItemはStyleが適用されていない事に
>今さら気が付きました。(DX10は適用されています)
>
>※XE5以降のバージョンで、この問題を解決しようとした事によるエンバグ?...
おおっ,よく見つけましたね.
私も,調べていたのですが「壁」です.
ということは...
バグ,バグと言っていても仕方ないので,できないものはできないですね.
私自身は,これ以上の追及はしないことにしました.
貴重な情報を頂きましたので,今後の参考にしたいと思います.
>DLLMainに相当するこの部分では最低限の処理しか行うべきではありません。
分かっていてやっていることとは思いますが,
そのためにメッセージ処理がありますんで (^^)
>そもそも、XE5ではSetStyleしてもTMenuItemはStyleが適用されていない事に
>今さら気が付きました。(DX10は適用されています)
>
>※XE5以降のバージョンで、この問題を解決しようとした事によるエンバグ?...
ということですので.TMenuItem に VCL スタイルを適用しなければ使えることになります.
[delphi - VCL Style from DLL is affecting TMenuItem in Application - Stack Overflow]
http://stackoverflow.com/questions/25933252/vcl-style-from-dll-is-affecting-tmenuitem-in-application
↑には,私より厳しい意見があるようです (^^;
私のサイトにも記事にしておきました.
[06_呼出し側と DLL の両方に VCL スタイルを適用する場合]
http://mrxray.on.coocan.jp/Delphi/plSamples/889_VCLStyleResource.htm#06
一応,DLL のプロセス生成時に,TMenuItem の VCL スタイルを無効にすることで,Delphi XE5 と同じように動作することを確認しました.
これで,DLL 側のフォームの TMenuItem は,VCL スタイルは無効になりました.
Windows 7 U64(SP1) + Delphi XE7, Delphi 10 Seattle で確認しました.
ごめんなさい.間違えました.
> VCL スタイルを無効にすることで
「VCL スタイルフックを無効」です.
Mr.XRAYさん、色々調べている頂きありがとうございます。
Mr.XRAYさんのサイトを参考に、Dll側だけに
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
を追加して、うまくいきました。
>[delphi - VCL Style from DLL is affecting TMenuItem in Application - Stack Overflow]
>http://stackoverflow.com/questions/25933252/vcl-style-from-dll-is-affecting-tmenuitem-in-application
↑私自身では、このサイトにはたどり着けなっただろうと思います。
丁寧な対応に大変感謝して居ります。
DLLでのTFormの使用は嫌な予感はしていたのですが、マルコ カントウの本にも使用例なんかも載ってるし...
プロジェクトが大きくなり過ぎて、今さら戻るのも大変でした。
せっかくの苦労を無にする結論ですが、
次のプロジェクトでは、使わないのが無難ですかね(^^)
>↑私自身では、このサイトにはたどり着けなっただろうと思います。
検索は結構シビアですよね.ノウハウの 1 つかも知れません.
>丁寧な対応に大変感謝して居ります。
いえいえ,私のサイトにも関連記事があるので,その対応策の意味がありますで.
よっしーさんの質問のおかげで,十分な予防対策となったと思っています.
>プロジェクトが大きくなり過ぎて、今さら戻るのも大変でした。
最初の質問の文章と,コードの提示の仕方で,これは,テスト用のプログラムを新規に
作っているわけではないな,と思いました.
で,失礼ですが,他になんか変なことやっているんじゃないの,と思っていました.
スレッドが進むにつれ,あれっ ?
まずい,私のサイトにも関連サンプルがあるし,というわけです.
>せっかくの苦労を無にする結論ですが、
>次のプロジェクトでは、使わないのが無難ですかね(^^)
いえ,そんなことはないと思います.自分の信念を貫いてください (笑)
私のサイトの記事は,警告的な意味があるんです.
コミュニティの場で,DLL にフォームを実装したり,それに VCL スタイルを適用する際に,
トラブッていて,苦労している方がいました.
そんなに悩むなら,そういうのはやめたら ? という意味も含んでいるんです.
ちなみに,自分が開発した業務アプリでは,DLL にフォームを実装したことはありません.・
ツイート | ![]() |