Управляйте «XXX» не имеют родительского окна

StackOverflow https://stackoverflow.com/questions/3776028

  •  04-10-2019
  •  | 
  •  

Вопрос

Я пытался написать библиотеку DLL в Delphi с функцией, которая создает экземпляр потомка Tfraame и возвращает его. Но когда я импортировал эту функцию в приложение, каждый раз, когда я назвал это, я бы получил исключение, например, «XXX», не имеет родительского окна ». Я уверен, что я не на 100%, но исключение появилось в конструкторе этого класса, когда все элементы управления графическим интерфейсом доступны.

Не могли бы вы рассказать мне, какова причина этого поведения? Должен ли я просто использовать потомки TForm вместо или есть лучшее решение?

Спасибо!

Это было полезно?

Решение

О ошибке

Это сообщение об ошибке поднимается из элемента управления PAS, из TWinControl.CreateWnd метод. По сути, этот код используется для создания ручки окна для вашего потомка Twincontrol (tframe, tbutton, tedit ... если он может иметь клавиатуру фокусировки, это потомка Twincontrol), и это на самом деле очень разумное сообщение об ошибке: вы не можете иметь Окно без WindowParent, а поскольку мы говорим о VCL здесь, это имеет большой смысл попробовать и получить ручку родительского окна от Twincontrol.Parent; И это не назначено.

Вот почему сообщение об ошибке появляется. Вы можете увидеть это сообщение об ошибке, потому что некоторые из кода, которые вы используете для настройки кадра, требует обработки окна для некоторой операции. Это может быть что-нибудь, как и настроить заголовок некоторого компонента (что внутренне требует ручки окна, выполняющую для некоторых расчетов). Я лично действительно ненавижу это, когда это произойдет. Когда я создаю GUI из Code, я стараюсь максимально задержать назначение родительского назначения, пытаясь задержать создание окна, поэтому я укусил это много раз.

Специфично для вашего использования DLL, возможное исправление

Я собираюсь поставить мою шляпу читателя психо-разума. Поскольку вам нужно вернуть кадр из вашей DLL, и вы не можете вернуть фактический кадр, потому что это Delphi-специфичный объект, и вам не разрешено возвращать объекты, специфичные Delphi на границы DLL, мое предположение - вы возвращаетесь Ручка окна, как делают все хорошие API, используя определение функции, как это:

function GiveMeTheNiceFrame:HWND;

Беда в том, что рутина требует создания фактической обработки окна, по вызову TWinControl.CreateWnd, и, в свою очередь, этот вызов требует, чтобы регламентировать родительскую ручку, чтобы настроить вызов Windows.CreateWindowEx, И рутина не может получить ручку родительского окна, поэтому он ошибся.

Попробуйте заменить свою функцию чем-то allong строки:

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

... то есть: используйте CreateParented(AParentWindow:HWND) Конструктор, не обычный Create(AOwner:TComponent) И пропустите владельца HWND к вашей DLL.

Другие советы

Есть несколько важных вещей, которые нужно помнить:

  1. При использовании DLLS и ваша DLL и ваша EXE у каждого есть экземпляр приложения, который борются для управления. Управления в вашей DLL увидят экземпляр приложения, который принадлежит DLL; Управления в вашем EXE увидят экземпляр приложения, который принадлежит EXE. Эта борьба не там при использовании пакетов, как тогда будет только один экземпляр приложений.
  2. Рамы являются элементами управления, но они не являются формы.
  3. При использовании элементов управления в приложении они не могут визуально существовать без родительского управления (обычно форма или контейнера, которая имеет родительскую иерархию к форме).
  4. Некоторые элементы управления не могут раскрыть свою полную функциональность, если они не существуют визуально и имеют действительный родитель.

Попробуйте воспроизвести вашу проблему внутри EXE; Если вы не можете воспроизводить, это, наверное, первое в списке выше.

- jereen.

Похоже, вам просто нужно назначить компонент (форма или часть формы, как панель), которая содержит кадр к ANFRAME.parent.

Вы не можете делать работу GUI, прежде чем она назначена. Рамки - это части форм для повторного использования, и обычно нужно назначить им немного родителей.

Переместите код графического интерфейса в Onshow или процедуру, которую вы вызовите явно, чтобы вызова код может назначить родителя.

Или сделать родительский параметр в функции.

Я нашел это (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;

Вы можете избежать этого сообщения, назначив NIL на родительское событие Onclose, иногда это работает:

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

Я думаю, что это очень крутое решение. Я думаю, что это не пробовать раньше :) Я использую фиктивную родитель (что является формой).

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top