Delphi在创建TFrame组件时忽略CS_OWNDC标志,wglMakeCurrent随后失败

时间:2011-01-31 16:17:17

标签: delphi opengl components

我正在尝试将一些组件放在一起,以便在RAD Studio 2009中使用OpenGL。我希望有多个渲染上下文。

我的想法是拥有一个名为GLMaster的“主要OpenGL组件”。它是一个TFrame后代,所以它应该为我提供一个DC。还有一个GLMonitor的组件,充当摄像头。

我在覆盖的GLMaster.Loaded中创建了一个OpenGL RC,如果没有(在ComponentState中的csDesigning),那么“-clause”。我不保留DC,在RAD Studio的帮助中说明你不应该: “TWinControl.Handle 在组件创建或流式传输期间不要引用Handle属性。在第一次引用Handle属性之前,底层窗口不存在。发生这种情况时,会自动调用HandleNeeded方法。“ 我使用GLMaster指向GLMaster.GetCurrentDC(返回HDC)的组件中的函数指针来处理它。

在销毁过程中,GLMonitor希望清理一些渲染到纹理和其他OpenGL资源。检索DC以调用wglMakeActive时,将跟随函数指针并执行跳转到GLMaster.GetCurrentDC。指针(Self)告诉我,在组件流式传输过程中,我们创建了“主RC”,这与GLMaster相同。属性[GLMaster。] Handle现在无效!但是,如果我在应用程序表单的OnClose中释放GLMonitor(仅使用GLMonitor_1.Free;)GLMaster.GetCurrentDC内的句柄是有效的,那么一切正常。

我设法看到GLMaster.Loaded中使用的句柄与完成初始化并向用户显示应用程序表单后的(!?!?)不一样。当我发现这个时,我搜索了我的问题并添加了一个重写的CreateParams来将CS_OWNDC添加到GLMaster组件。那里的一个断点告诉我它正在被执行。

为什么VCL / Delphi会静默地为新创建的组件提供其他句柄,从而间接提供其他DC,即使我提供OWNDC标志?有没有办法得到一个“现在加载所有组件并从.dfm文件读取它们的属性和”-message所以我可以在组件内运行GLMaster.InitEverything?

现在我认为最快的方法是将这个InitEverything放在主窗体的OnShow处理程序中。然后在主窗体的OnClose中调用GLMatser.CleanAll。但我不希望表单中有任何代码,这就是我首先创建组件的原因!

P.S。 并不是说我觉得这个特殊问题很重要,但我使用的是OpenGL 3.2 Core Profile。

3 个答案:

答案 0 :(得分:3)

我正在回答“为什么VCL / Delphi默默地为新创建的组件提供其他句柄”。

为什么控件的窗口句柄可能在运行时更改

您的TFrameTWinControl后代)被放置在另一个TWinControl上,让我们说TForm。父容器围绕许多设置提供属性包装器,允许我们轻松地进行更改;如果不重新创建windhow句柄,则无法实现其中一些更改。您可以通过在RecreateWndForms.pas等中搜索Controls.pas来获取导致这种情况发生的一长串属性。

调用RecreateWnd以在运行时实现更改的属性示例:

  • TScollBox.BorderStyle
  • TForm.BorderIcons(适用于MDI孩子)

当您的TFrame父母需要更改窗口句柄时,您的TFrame也必须更改窗口句柄。您的Delphi控件,无论是哪个,都需要处理这个,而其他控件最糟糕的是:围绕Windows控件实现包装的控件需要保存状态和重载状态(TEdit,TComboBox,...)

我的想法

在流式传输(加载表单)时,某些控件会在加载完成之前执行需要窗口句柄的操作。这很可能是你自己的代码!一切都完成加载后,Form可能需要重新创建它的Handle,这反过来会导致你的Frame的句柄被更改。

您可能想要覆盖的内容

鉴于VCL的工作方式,您需要为Window Handle做好准备。您应该在Controls.pas中搜索单词句柄 HDC 。如果您的控件与它的Window Handle和HDC密切相关,那么阅读这些内容符合您的最佳利益。

看看那些例行公事。也许你可以找一个更好的地方来挂钩:

  • CreateHandle
  • CreateWnd方法
  • DestroyHandle
  • DestroyWnd
  • GetDeviceContext

答案 1 :(得分:1)

如果标题是问题,那么不,Delphi在创建框架时不会忽略CS_OWNDC。刚刚使用以下程序在表单上使用框架进行测试。如果未指定该标志,则会一次又一次地绘制该行,从而产生一条从(0,0)到(10,10)的行。当拥有DC时,该行从(0,0)延伸到(50,50),无需告知,但检索到的DC始终相同。

procedure TFrame2.WmPaint(var Msg: TWMPaint);
var
  i: Integer;
  DC: HDC;
  Pt: TPoint;
begin
  inherited;
  for i := 1 to 5 do begin
    DC := GetDC(Handle);
    GetCurrentPositionEx(DC, @Pt);
    LineTo(DC, Pt.X + 10, Pt.Y + 10);
    ReleaseDC(Handle, DC);
  end;
end;

答案 2 :(得分:0)

如果你的问题是:

现在加载所有组件,并从.dfm文件和

中读取其属性

答案是:

,只需覆盖组件的Loaded方法即可。当所有引用都有效时(dfm读取完成后)调用它。