比如在工程文件中:有如下两句:
//...
Application.CreateForm (TForm1, Form1);
Application.CreateForm (TForm2, Form2);
//....
如果一开始就把Form1, Form2的Visible属性设为true
不必等到Application.Run;两个窗口都会显示出来:
Form1我可以理解:毕竟它是主窗体,我觉得其建立(指WinApi:CreateWindow)是在
HandleNeeded中。
但是Form2怎么会建立,我不明白,因为Form2是执行不到HandleNeeded这个方法的。小弟才学Delphi,希望各位大哥不吝赐教。

解决方案 »

  1.   

    这些属性是在Project-Option中指定的,从那里你可以指定,哪个窗体是自动创建,还是需要时收工创建。打开看看就知道了
      

  2.   

    project->options->forms中把auto-create forms中的窗体移到available forms中即可。
      

  3.   

    不是啊,我的意思是我怎么也找不到对应Form2的windowAPI函数:CreateWindowEx,所以我认为TForm2不会被建立(我正在看VCL的源代码),哪位给我一个解释,
    先谢过了
      

  4.   

    哦?呵呵,是啊,这个问题俺到是从来没有注意过!!!!在创建了窗体1后,在进入CreateForm后,对FMainForm=Nil的判断为False,所以,那个if语句中的代码不执行,那看来Form2的创建只能是在if的前面了,让俺在看看,共同学习,呵呵!
      

  5.   

    不对,楼主,你的理解可能有错误。窗体实例的创建不应该是在HandleNeeded里面进行的,那样的话,按照我们的推断,窗口2是肯定不会被创建的。另外,我查了查资料,发现一个资料上有这样的一段,你看看:。
    procedure TApplication.CreateForm(InstanceClass:TComponentClass;var Reference);
    var
      Instance:TComponent;
    begin
      Instance:=TComponent(InstanceClass.NewInstance);
      ......//创建窗体实例的代码省略
      
      //第一个创建的窗体实例就是MainForm
      if (FMainForm=Nil) and (Instance is TForm) then
      begin
        TForm(Instance).HandleNeeded;
        FMainForm:=TForm(Instance);
      end;
    end;

    看看上面的注释,说明窗体实例的创建不是在HandleNeeded中完成的!!!!不过具体HandleNeeded做了什么,我也说不清楚,还是等其他高人来解答吧......呵呵,俺现在给你找高人去,呵呵...闪!
      

  6.   

    Instance:=TComponent(InstanceClass.NewInstance);我认为这句才是创建对象的地方!在堆上为对象分配InstanceSize大小的堆内存!
      

  7.   

    procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
    var
      Instance: TComponent;
    begin
      Instance := TComponent(InstanceClass.NewInstance);
      TComponent(Reference) := Instance;
      try
        Instance.Create(Self);
      except
        TComponent(Reference) := nil;
        raise;
      end;
      if (FMainForm = nil) and (Instance is TForm) then
      begin
        TForm(Instance).HandleNeeded;
        FMainForm := TForm(Instance);
      end;
    end;实际上窗体的创建在Instance.Create(Self);这一步完成的HandleNeeded是当取
    Form的Handle是调用的
        property Handle: HWnd read GetHandle;function TWinControl.GetHandle: HWnd;
    begin
      HandleNeeded;
      Result := FHandle;
    end;而取Handle的这些在Instance.Create(Self);
    就会去做
      

  8.   

    详情请见
    http://expert.csdn.net/Expert/topic/1604/1604705.xml?temp=.3986933
      

  9.   

    To Xzgybconstructor TComponent.Create(AOwner: TComponent);
    begin
      FComponentStyle := [csInheritable];
      if AOwner <> nil then AOwner.InsertComponent(Self);
    end;
    你认为是在这里创建的!?可是我看到上面这个过程中没有具体的创建动作啊?只是设置属性和添加列表啊!
      

  10.   

    FrameSniper:你看错了
    应该是TCustomForm.Createconstructor TCustomForm.Create(AOwner: TComponent);
    begin
      GlobalNameSpace.BeginWrite;
      try
        CreateNew(AOwner);
        if (ClassType <> TForm) and not (csDesigning in ComponentState) then
        begin
          Include(FFormState, fsCreating);
          try
            if not InitInheritedComponent(Self, TForm) then
              raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
          finally
            Exclude(FFormState, fsCreating);
          end;
          if OldCreateOrder then DoCreate;
        end;
      finally
        GlobalNameSpace.EndWrite;
      end;
    end;
      

  11.   

    同意老达摩!Application.Run与窗体Form1和Form2的创建没有关系,它的作用是负责维护工程的消息队列。
      

  12.   

    先谢谢大家,但是我觉得大家并没有解决这个问题:
    1。Instance:=TComponent(InstanceClass.NewInstance);
    是为这个对象分配内存,和窗口的建立根本没有关系,而且这个Instance是TForm类型(具体怎么回事我不清楚)。
    2。因为Instance是TForm类型,所以Create是调用的TCustomForm的,但是我找遍构造函数,找不到CreateWndEx,事实上我猜测也不可能是在构造函数。
    3。HandleNeeded中我可以间接找到CreateWndEx,大家自己跟到VCL源代码去看好了,很容易。
    4。Application.Run跟窗口的显示是有关系的,因为主窗体最初是设为不可见的,就是在这个函数中设为可见。
    Form2的CreateWndEx肯定在什么地方,我只是找不到,希望有高人能找到。
    我只是一个计算机系的学生,谢谢大家的关怀。
      

  13.   

    呵呵,没有什么关怀不关怀的,大家讨论讨论,有问题不讨论莫非还要留着吗,呵呵!!!!刚开始学Delphi能研究这么透彻已经很难得了,俺刚开始学Delphi的时候连VCL的Source Code在哪里都不知道啊,俺还要再研究研究你的问题......
      

  14.   

    Xcercs看来你没看那个贴子阿
    我重新贴上来吧
    希望对你有所帮助我从
      Application.Initialize;
      Application.CreateForm(TMainForm, MainForm);
      Application.Run;
    一开始调试
    记录一下主要的过程
    当Application.CreateForm时
    执行到
    constructor TCustomForm.Create(AOwner: TComponent);
    begin
      GlobalNameSpace.BeginWrite;
      try
        CreateNew(AOwner);
        if (ClassType <> TForm) and not (csDesigning in ComponentState) then
        begin
          Include(FFormState, fsCreating);
          try
            if not InitInheritedComponent(Self, TForm) then
              raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
          finally
            Exclude(FFormState, fsCreating);
          end;
          if OldCreateOrder then DoCreate;
        end;
      finally
        GlobalNameSpace.EndWrite;
      end;
    end;关键一处
    InitInheritedComponent
    由调试看出的调用顺序,关键的部分InitInheritedComponent
    InternalReadComponentRes  //读取窗体资源,也就是准备根据DFM描述建立窗体控件
    TResourceStream.ReadComponent
    TReader.ReadRootComponent
    TCustomForm.ReadState  
    TComponent.ReadState
    TReader.ReadData
    TReader.ReadDataInner
       这个比较让人感兴趣的
       procedure TReader.ReadDataInner(Instance: TComponent);
    var
      OldParent, OldOwner: TComponent;
    begin
      while not EndOfList do ReadProperty(Instance);
      ReadListEnd;
      OldParent := Parent;
      OldOwner := Owner;
      Parent := Instance.GetChildParent;
      try
        Owner := Instance.GetChildOwner;
        if not Assigned(Owner) then Owner := Root;
        while not EndOfList do ReadComponent(nil);
        ReadListEnd;
      finally
        Parent := OldParent;
        Owner := OldOwner;
      end;
    end;
    这句ReadProperty(Instance);就是读取MainForm上的属性并设置属性值
    ReadComponent就是读取MainForm上的控件描述并建立之并设置相应的控件属性值
    这些操作做完之后,回到
    procedure TCustomForm.ReadState(Reader: TReader);
    var
      NewTextHeight: Integer;
      Scaled: Boolean;
    begin
      DisableAlign;
      try
        FClientWidth := 0;
        FClientHeight := 0;
        FTextHeight := 0;
        Scaled := False;
        FOldCreateOrder := not ModuleIsCpp;
        inherited ReadState(Reader);  //回到这    if (FPixelsPerInch <> 0) and (FTextHeight > 0) then
        begin
          if (sfFont in ScalingFlags) and (FPixelsPerInch <> Screen.PixelsPerInch) then
            Font.Height := MulDiv(Font.Height, Screen.PixelsPerInch, FPixelsPerInch);
          FPixelsPerInch := Screen.PixelsPerInch;
          NewTextHeight := GetTextHeight;
          if FTextHeight <> NewTextHeight then
          begin
            Scaled := True;
            ScaleScrollBars(NewTextHeight, FTextHeight);
            ScaleControls(NewTextHeight, FTextHeight);
            if sfWidth in ScalingFlags then
              FClientWidth := MulDiv(FClientWidth, NewTextHeight, FTextHeight);
            if sfHeight in ScalingFlags then
              FClientHeight := MulDiv(FClientHeight, NewTextHeight, FTextHeight);
            if sfDesignSize in ScalingFlags then
            begin
              FDesignSize.X := MulDiv(FDesignSize.X, NewTextHeight, FTextHeight);
              FDesignSize.Y := MulDiv(FDesignSize.Y, NewTextHeight, FTextHeight);
            end;
          end;
        end;
        if FClientWidth > 0 then inherited ClientWidth := FClientWidth;
        if FClientHeight > 0 then inherited ClientHeight := FClientHeight;
        ScalingFlags := [];
        if not Scaled then
        begin
          { Forces all ScalingFlags to [] }
          ScaleScrollBars(1, 1);
          ScaleControls(1, 1);
        end;
        Perform(CM_PARENTBIDIMODECHANGED, 0, 0);
      finally
        EnableAlign;
      end;
    end;注意:我这边调试了好几遍窗体的创建就在这个属性设置
     NewTextHeight := GetTextHeight;调用GetTextHeight,跟踪
    function TCustomForm.GetTextHeight: Integer;
    begin
      Result := Canvas.TextHeight('0');
    end;
    到达
    function TCanvas.TextHeight(const Text: string): Integer;
    begin
      Result := TextExtent(Text).cY;
    end;function TCanvas.TextExtent(const Text: string): TSize;
    begin
      RequiredState([csHandleValid, csFontValid]);
      Result.cX := 0;
      Result.cY := 0;
      Windows.GetTextExtentPoint32(FHandle, PChar(Text), Length(Text), Result);
    end;procedure TCanvas.RequiredState(ReqState: TCanvasState);
    var
      NeededState: TCanvasState;
    begin
      NeededState := ReqState - State;
      if NeededState <> [] then
      begin
        if csHandleValid in NeededState then
        begin
          CreateHandle;
          if FHandle = 0 then
            raise EInvalidOperation.CreateRes(@SNoCanvasHandle);
        end;
        if csFontValid in NeededState then CreateFont;
        if csPenValid in NeededState then CreatePen;
        if csBrushValid in NeededState then CreateBrush;
        State := State + NeededState;
      end;
    end;好了,主角慢慢快出来了
    由于NeededState包含csHandleValid一句所以
    procedure TControlCanvas.CreateHandle;
    begin
      if FControl = nil then inherited CreateHandle else
      begin
        if FDeviceContext = 0 then
        begin
          with CanvasList.LockList do
          try
            if Count >= CanvasListCacheSize then FreeDeviceContext;
            FDeviceContext := FControl.GetDeviceContext(FWindowHandle);
            Add(Self);
          finally
            CanvasList.UnlockList;
          end;
        end;
        Handle := FDeviceContext;
        UpdateTextFlags;
      end;
    end;
    继续执行到了
    function TWinControl.GetDeviceContext(var WindowHandle: HWnd): HDC;
    begin
      if csDesigning in ComponentState then
        Result := GetDCEx(Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS)
      else
        Result := GetDC(Handle);
      if Result = 0 then raise EOutOfResources.CreateRes(@SWindowDCError);
      WindowHandle := FHandle;
    end;执行到了
      Result := GetDC(Handle);
    Handle为TWinControl的属性
    这样定义的
    property Handle: HWnd read GetHandle;
    所以
    function TWinControl.GetHandle: HWnd;
    begin
      HandleNeeded;
      Result := FHandle;
    end;procedure TWinControl.HandleNeeded;
    begin
      if FHandle = 0 then
      begin
        if Parent <> nil then Parent.HandleNeeded;
        CreateHandle;
      end;
    end;而这时窗体没有创建FHandle = 0;
    执行到CreateHandleprocedure TWinControl.CreateHandle;
    var
      I: Integer;
    begin
      if FHandle = 0 then
      begin
        CreateWnd;
        SetProp(FHandle, MakeIntAtom(ControlAtom), THandle(Self));
        SetProp(FHandle, MakeIntAtom(WindowAtom), THandle(Self));
        if Parent <> nil then
          SetWindowPos(FHandle, Parent.PrecedingWindow(Self), 0, 0, 0, 0,
            SWP_NOMOVE + SWP_NOSIZE + SWP_NOACTIVATE);
        for I := 0 to ControlCount - 1 do
          Controls[I].UpdateAnchorRules;
      end;
    end;