[vtkusers] Access violation in destructor of vtkBorlandRenderWindow

dean.inglis at camris.ca dean.inglis at camris.ca
Thu Feb 23 15:51:56 EST 2006


Hi Michael, Mattias

I don't encounter these destructor problems and have been running BCB 4,5,6
and now Borland Developer Studio which contains the latest incarnation
of BCB: BCB 2006 (so, it's NOT being abandoned by Borland contrary to
comments below).  In a TForm that has a vtkBorlandRenderWindow
component built from a static VTK build, all one has to do
is delete the object in the Tform's OnClose event and
set the TCloseAction passed by reference to caFree.  If compiling
against a shared VTK build (which I haven't done in a while)
you should not need to to this but may have to have props assigned
to the component's renderer call ReleaseGraphicsResources in the
TForm's OnDestroy event. I would not recommend messing about with 
TApplication in the manner suggested.  Of course, the render window
component is not built as part of VTK so you can inherit from it/
alter it / whatever to suit your purposes.
Below is a simple app to test for static builds and the other
test for shared builds is in the VTK source tree.

regards,
Dean

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#include <vcl\SysUtils.hpp>
#pragma hdrstop

#include "MyUnit.h"

#include "vtkActor.h"
#include "vtkFileOutputWindow.h"
#include "vtkOutputWindow.h"
#include "vtkPolyDataMapper.h"
#include "vtkSphereSource.h"
#include "vtkRenderer.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "vtkBorlandRenderWindow"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  vtkOutputWindow* ow = vtkOutputWindow::GetInstance();
  vtkFileOutputWindow* fow = vtkFileOutputWindow::New();
  String s = GetCurrentDir() + "\\BDS_VTK_test_debug.txt";
  fow->SetFileName(s.c_str());
  if (ow)
	{
	ow->SetInstance(fow);
	}
  fow->Delete();

  m_actor = vtkActor::New();

  vtkSphereSource* sphere = vtkSphereSource::New();
  sphere->SetRadius(1);
  sphere->SetThetaResolution(10);
  sphere->SetPhiResolution(10);
  sphere->Update();

  vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
  mapper->SetInput( sphere->GetOutput() );
  m_actor->SetMapper( mapper );
  mapper->Delete();
  sphere->Delete();

  RenderWindow1->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
  RenderWindow1->Enabled = true;
  vtkRenderer* ren = RenderWindow1->GetRenderer();
  if ( ren )
	{
	ren->AddViewProp( m_actor );
	m_actor->VisibilityOn();
	}
 RenderWindow1->Repaint();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  Action = caFree;
  m_actor->Delete();
  delete RenderWindow1;
}

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------



Matthias,
you'r right these "workaround" don't solve any problems. The only
solution that I found was in the following mail ( but in VTK 5.0
this doesn't work anymore if you use more than one RenderWindow),
good luck
Michael

--------------------

Hi all,

Again, thanks for your feedback.

I have been ping-pong'ing with a borland newsgroup to find a better workaround. I found a workaround, wether it's better or worse, decide for yourselves, but it seems to do the trick for me :-)

Instead of doing all these specialized things in every project in which I use VTK, I have found a solution that can be included into the vtkBorlandRenderWindow source, without requiring any changes to the normal way of using VCL. That is: the users of the VCL-wrapped VTK components does not have to make any special magic to get it to work.
The fix is rather dirty, but again, it seems to work.


vtkBorlandRenderWindow.cpp:
--- Original ---
namespace Vtkborlandrenderwindow
{
  void __fastcall PACKAGE Register()
    {
    TComponentClass classes[1] = {__classid(TvtkBorlandRenderWindow)};
    RegisterComponents("Samples", classes, 0);
    }
}

--- New ---

+ static bool InDesigner = false;
+
+ void vtkWorkAround(void)
+ {
+     if (!InDesigner) {
+         ShowMessage("Workaround");
+         delete Application;
+         Application = new TApplication(NULL);
+     }
+ }
+
+
+ void InstallvtkWorkAround(void)
+ {
+     atexit(vtkWorkAround);
+ }
+ #pragma startup InstallvtkWorkAround
+
+
namespace Vtkborlandrenderwindow
{
  void __fastcall PACKAGE Register()
    {
    TComponentClass classes[1] = {__classid(TvtkBorlandRenderWindow)};
    RegisterComponents("Samples", classes, 0);
+     InDesigner = true;
    }
}
------
Remember to add the define "STRICT" to the ... defines. To get VTK to compile.


A more thorough explanation on the workings of this workaround can be found at the borland newsgroup: news:borland.public.cppbuilder.vcl.components.writing in the thread with subject: "Designtime or runtime" in my third (and so far last) post.

The relevant quote from that post:
---
The problem relates to a nonlocal object, on which the dynamically
allocated VTK objects depend during destruction. Unfortunately this nonlocal object is destroyed BEFORE the VCL, and thereby the dynamic VTK objects => Access violation.

To workaround this problem, I found out that I could destroy the Application variable myself in the project source, just before the return from WinMain().
To keep the BCB runtime from crashing when it tries to destroy the
Application variable, it is recreated (without forms).
In that way I ensure that the VCL-objects are destroyed before nonlocal objects are, keeping the nonlocal object valid during VCL/VTK destruction.

To wrap things nicely to the users of these components, I thought I would make this Application destroy/recreate trick from within the library.
Unfortunately the #pragma exit functions are executed AFTER the destruction of nonlocal objects. Luckily functions registered with the standard C function atexit() are called BEFORE the destruction of nonlocal objects.
The solution then were to install an atexit-function, in the librarys startup code, which simply made the Application destroy/recreate trick.

However, while within the designer, things works as (I think) they should.
The nonlocal object are destroyed after the VCL/VTK objects. In addition the Application destroy/recreate trick made havoc.

So what I have tried now is to install this atexit() handler, to make the Application destroy/recreate trick IF not within the designer (or in context of BCB).

I have now implemented the workaround, and everything seems to work
perfectly.
---

Hope you guys find some of this useful.


> it's the original Borland demo, which has never been attended 
> to. Please fix it if you have time. Mind you, now that Borland 
> are dumping BCB, it's worth discouraging people from adopting it.

Even if they had continued BCB, I would still discourage people from using it ;-)


Best regards
Per





More information about the vtkusers mailing list