11

TFrameの子孫のインスタンスを作成して返す関数を使用してDelphiでdllライブラリを作成しようとしていました。しかし、この関数をアプリケーションにインポートすると、呼び出すたびに「「xxx」コントロールには親ウィンドウがありません」などの例外が発生します。100%確信はありませんが、GUIコントロールのいずれかにアクセスすると、そのクラスのコンストラクターに例外が発生しました。

その行動の理由を教えてください。代わりにTFormの子孫を使用する必要がありますか、それともより良い解決策がありますか?

ありがとうございました!

4

6 に答える 6

8

エラーについて

TWinControl.CreateWndこのエラーメッセージは、Controls.pasユニットのメソッドから発生します。基本的に、そのコードはTWinControlの子孫(TFrame、TButton、TEdit ...キーボードフォーカスが可能な場合はTWinControlの子孫)のウィンドウハンドルを作成するために使用され、実際には非常に賢明なエラーメッセージです。 WindowParentのないウィンドウ。ここではVCLについて説明しているので、TWinControl.Parentから親ウィンドウハンドルを取得することは非常に理にかなっています。そして、それは割り当てられていません。

エラーメッセージが表示されるのはそのためではありません。フレームの設定に使用しているコードの一部は、操作のためにウィンドウハンドルを必要とするため、このエラーメッセージが表示されます。これは、コンポーネントのキャプションを設定するなど、何でもかまいません(内部的には、ウィンドウハンドルで計算を行う必要があります)。それが起こったとき、私は個人的にそれを本当に嫌います。コードからGUIを作成するときは、ウィンドウの作成を遅らせるために、親の割り当てをできるだけ遅らせようとしているので、これに何度も噛まれました。

DLLの使用法に固有、可能な修正

サイコマインドリーダーの帽子をかぶるつもりです。DLLからFRAMEを返す必要があり、実際のフレームを返すことはできません。これはDelphi固有のオブジェクトであり、DLLの境界を越えてDelphi固有のオブジェクトを返すことは許可されていないためです。すべての優れたAPIと同様に、次のような関数定義を使用するウィンドウハンドル。

function GiveMeTheNiceFrame:HWND;

問題は、そのルーチンがへの呼び出しによって実際のウィンドウハンドルを作成する必要があり、TWinControl.CreateWndその呼び出しがへの呼び出しを設定するために親ウィンドウハンドルを必要Windows.CreateWindowExとし、ルーチンが親ウィンドウハンドルを取得できないことです。エラーが発生します。

関数を次の行に沿ったものに置き換えてみてください。

function GiveMeTheNiceFrame(OwnerWindow:HWND):HWND;
begin
  Result := TMyNiceFrame.CreateParanted(OwnerWindow).Handle;
end;

...すなわち:CreateParented(AParentWindow:HWND)通常ではなくコンストラクターを使用しCreate(AOwner:TComponent)、所有者HWNDをDLLに渡します。

于 2010-09-23T08:08:05.820 に答える
1

覚えておくべき重要なことがいくつかあります。

  1. DLLを使用する場合、DLLとEXEの両方に、制御に苦労しているアプリケーションインスタンスがあります。DLLのコントロールには、DLLに属するアプリケーションインスタンスが表示されます。EXEのコントロールには、EXEに属するアプリケーションインスタンスが表示されます。パッケージを使用する場合、アプリケーションインスタンスは1つしかないため、この問題は発生しません。
  2. フレームはコントロールですが、フォームではありません。
  3. アプリケーションでコントロールを使用する場合、親コントロール(通常はフォームまたはフォームに対する親階層を持つコンテナー)がないと視覚的に存在できません。
  4. 一部のコントロールは、視覚的に存在し、有効な親がない限り、すべての機能を公開できません。

EXE内で問題を再現してみてください。再現できない場合は、おそらく上記のリストの最初のものです。

--jeroen

于 2010-09-23T07:46:08.187 に答える
0

親のOnCloseイベントにnilを割り当てることで、このメッセージを回避できます。場合によっては、次のように機能します。

SomeControl.Parent := nil;//Before free your TControl
SomeControl.Free;
于 2011-11-17T22:09:35.287 に答える
0

フレームを保持するコンポーネント(フォームまたはフォームの一部(パネルなど))をframe.parentに割り当てるだけでよいように思えます。

割り当てられる前にGUI作業を行うことはできません。フレームは再利用するためのフォームの一部であり、通常はフレームに親を割り当てる必要があります。

GUIコードをonshowまたは明示的に呼び出すプロシージャに移動して、呼び出し元のコードが親を割り当てることができるようにします。

または、親を関数のパラメーターにします。

于 2010-09-23T07:37:45.820 に答える
0

私はこれを見つけました(CreateParamsはCreateWndの一部として呼び出されます):

procedure TCustomFrame.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if Parent = nil then
    Params.WndParent := Application.Handle;
end;

また、Application.Handle = 0であるため、後でCreateWndで常にエラーがスローされます。
このDelphiを読んだ後 :仮想メソッドで継承された継承された祖先を呼び出す方法は?

フレーム内のCreateParamsをオーバーライドして、tCustomFrameバージョンを見逃すことで解決しました。

type
  tCreateParamsMethod = procedure(var Params: TCreateParams) of object;

type
  tMyScrollingWinControl = class(TScrollingWinControl);

procedure TDelphiFrame.CreateParams(var Params: TCreateParams);
var
  Proc: tCreateParamsMethod;
begin
  TMethod(Proc).Code := @TMyScrollingWinControl.CreateParams;
  TMethod(Proc).Data := Self;

  Proc(Params);
end;

サブコントロールにフォーカスを設定しようとすると、エラーがスローされるだけです。これは、WM_FOCUSをインターセプトすることで修正できると思いますが、ここから説明します。

function CreateFrame(hwndParent: HWnd): HWnd; stdcall;
var
  frame: tFrame;
begin
  Result := 0;
  try
    frame := TDelphiFrame.CreateParented(hwndParent);
    Result := frame.Handle;
  except on e: Exception do
    ShowMessage(e.Message);
  end;
end;
于 2011-03-18T18:44:18.597 に答える
0

これは非常にクールな解決策だと思います。以前は試していなかったと思います:)ダミーの親(フォーム)を使用しています。

function MyFrame_Create(hApplication, hwndParent:THandle; X, Y, W, H:Integer):Pointer; stdcall;
var Fr: TMyFrame;
    F:  TForm;
    CurAppHandle: THandle;
begin
  CurAppHandle:=Application.Handle;
  Application.Handle:=hApplication;
  //---
  F:=TForm. Create(Application);//Create a dummy form
  F.Position:=poDesigned;
  F.Width:=0; F.Top:=0; F.Left:=-400; F.Top:=-400;//Hide Form
  F.Visible:=True;
  //---
  Fr:=TMyFrame.Create(Application);
  Fr.Parent:=F;//Set Frame's parent
  //Fr.ParentWindow:=hwndParent;
  Windows.SetParent(Fr.Handle, hwndParent);//Set Frame's parent window
  if CurAppHandle>0 then Application.Handle:=CurAppHandle;
  //---
  Fr.Left:=X;
  Fr.Top:=Y;
  Fr.Width:=W;
  Fr.Height:=H;
  Result:=Fr;
end;//MyFrame_Create

procedure MyFrame_Destroy(_Fr:Pointer); stdcall;
var Fr: TMyFrame;
    F: TObject;
begin
 Fr:=_Fr;
 F:=Fr.Parent;
 Fr.Parent:=Nil;
 if (F is TForm) then F.Free;
 //SetParent(Fr.Handle, 0);
 //Fr.ParentWindow:=0;
 Fr.Free;
end;//MyFrame_Destroy
于 2014-12-30T05:09:46.110 に答える