Domanda

Sto stava cercando di scrivere una libreria DLL in Delphi wih una funzione che crea un'istanza di un discendente TFrame e lo restituisce. Ma quando ho importato questa funzione in un'applicazione, ogni volta che ho chiamato mi sarebbe ottenere una deroga come "l' 'xxx' di controllo non ha alcuna finestra padre". Io non sono sicuro al 100%, ma l'eccezione è apparso nel costruttore di quella classe, quando uno qualsiasi dei controlli GUI ha avuto accesso.

La prego di dirmi quale sia la ragione di questo comportamento è? Devo solo usare discendenti TForm invece o c'è una soluzione migliore?

Grazie!

È stato utile?

Soluzione

sull'errore

Questo messaggio di errore viene generato dall'unità Controls.pas, dal metodo TWinControl.CreateWnd. In sostanza, che il codice viene utilizzato per creare l'handle della finestra per il vostro discendente TWinControl (TFrame, TButton, TEdit ... se può avere fuoco della tastiera è un discendente TWinControl), ed è in realtà un messaggio di errore molto sensibile: non si può avere un finestra senza WindowParent, e dal momento che stiamo parlando della VCL qui, fa un sacco di senso per cercare di ottenere l'handle della finestra principale dal TWinControl.Parent; E non è assegnato.

Non è per questo il messaggio di errore è popping up. Si arriva a vedere che il messaggio di errore, perché parte del codice che si sta utilizzando per impostare il telaio richiede un handle di finestra per alcune operazioni. Potrebbe essere qualsiasi cosa, come l'impostazione della didascalia di qualche componente (che richiede internamente un handle di finestra fare per un po 'di calcolo). Io personalmente odio quando succede. Quando creo GUI dal codice cerco di ritardare l'assegnazione di Parent, per quanto possibile, nel tentativo di ritardare la creazione della finestra, così mi sono morso da questo molte volte.

specifico per l'utilizzo DLL, possibile correzione

ho intenzione di mettere il mio cappello psico lettore di mente su. Dal momento che è necessario restituire un fotogramma di DLL, e non è possibile restituire il telaio vero e proprio perché è un oggetto Delphi-specifico e non ti è permesso di restituire gli oggetti Delphi-specifici su confini DLL, la mia ipotesi è che stai tornando una finestra Maniglia, come tutte le belle di API fanno, usando una definizione di funzione come questa:

function GiveMeTheNiceFrame:HWND;

Il problema è che di routine richiede la creazione di l'handle di finestra reale, da una chiamata a TWinControl.CreateWnd, ea sua volta questa chiamata richiede un handle di finestra genitore di impostare la chiamata a Windows.CreateWindowEx, e la routine non può ottenere un genitore finestra maniglia, in modo che gli errori di fuori.

Provare a sostituire la vostra funzione con qualcosa allong le linee di:

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

... vale a dire:. Utilizzare il costruttore CreateParented(AParentWindow:HWND), non il solito Create(AOwner:TComponent) e superare un HWND proprietario per la DLL

Altri suggerimenti

Ci sono alcune cose importanti da ricordare:

  1. Quando si utilizzano le DLL, sia la DLL e il vostro EXE hanno ciascuno un'istanza di applicazione che stanno lottando per il controllo. I controlli nella DLL vedrà l'istanza di applicazione che appartiene alla DLL; i controlli nella tua EXE vedranno l'istanza di applicazione che appartiene alla EXE. Quella lotta non c'è quando si utilizzano pacchetti, come allora ci sarà una sola istanza di applicazione.
  2. Le cornici sono controlli, ma non sono le forme.
  3. Quando si utilizza i controlli in un'applicazione, non possono esistere visivamente senza un genitore di controllo (di solito una maschera o un contenitore che ha una gerarchia padre verso una forma).
  4. Alcuni controlli non possono esporre la loro piena funzionalità a meno che non esistano visivamente e avere un genitore valido.

Provare a riprodurre il problema all'interno del file EXE; se non è possibile riprodurre, è probabilmente la prima cosa nella lista di cui sopra.

- Jeroen

Suoni come è sufficiente assegnare il componente (una forma o una parte di una forma, come un pannello) che contiene la cornice theframe.parent.

Non si può fare il lavoro GUI prima che venga assegnato. Cornici sono parti dei moduli per il riutilizzo, e normalmente devono assegnare qualche genitore a loro.

Spostare il codice della GUI di procedura onshow o si chiama esplicitamente, in modo che il codice chiamante può assegnare genitore.

O fare il genitore di un parametro nella funzione.

Ho trovato questo (CreateParams si chiama come parte di CreateWnd):

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

E Application.Handle = 0 in modo che getta sempre l'errore più avanti in CreateWnd.
Dopo aver letto questo Delphi:? Come chiamare ereditato antenato ereditaria su un metodo virtuale

ho risolto ridefinendo CreateParams nel mio telaio perdere la versione 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;

Ora si tratta solo di gettare gli errori quando si cerca di impostare la messa a fuoco subcontrols, che penso di risolvere intercettando WM_FOCUS ma faremo come va da qui.

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;

È possibile evitare questo messaggio assegnando nil al genitore OnClose evento, a volte funziona:

SomeControl.Parent := nil;//Before free your TControl
SomeControl.Free;

Credo che questo sia una soluzione molto cool. Penso che non è provato prima :) Sto usando un genitore Dummy (che è una forma).

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top