Ticket T406371
Visible to All Users

The Access Violation is raised when the form with Grid inside a DLL is closed

created 9 years ago

I have a loader application that dynamically loads a form residing inside a dll.
Everything works fine until I put a TcxGrid or a TcxTreeList  on the form.
Then the application crashes on close with an access violation.
With a TcxGrid the stack trace tells 'TdxLayoutTextMetrics.GetCount'.
It will not crash when I delete the only view inside the grid.

With a TcxTreeList it is 'TcxLookAndFeelPaintersManager.Unregister'.
But it will only crash with a TcxTreeList when it contains at least one volumn.

I'm quite sure that all went fine with my complex application until yesterday, but now I can reproduce the crash even with a simple demo.
Any ideas how to fix it?

I've attached a little demo application.

Answers

created 9 years ago

As a workaround, I added a condition to 'TdxLayoutTextMetrics.Get':

Delphi
begin if not IsLibrary then begin AIndex := GetSameFontIndex(AFont); if AIndex = -1 then AIndex := CreateItem; ATextMetric := Items[AIndex].TextMetric; end; end;
    Show previous comments (1)

      Each of my Dll's is providing a single form that is created by the host immediately after loading the dll.
      So i had dxInitialize in the constructor and dxFinalize in the destructor of the dll's form base class.

      On your advice I moved it to the initialization and finalization parts of the forms unit … no success.

      When should dxInitialize and dxFinalize be called?
      Once for the host and once for each dll I'm loading?
      Or only once by the host as all the loaded dll's are loaded into the host's address space?

      My own solution is working quite good so far ;-)

      DevExpress Support Team 9 years ago

        Thank you for letting us know that you have found the workaround.

        I've examined your code further and wish to give you some comments:

        1. I need to note that the following approach is incorrect:
        Delphi
        constructor TClientForm.Create(AOwner: TForm); begin dxInitialize; inherited CreateParented(AOwner.Handle); Self.MainForm := AOwner as IMainForm; end; destructor TClientForm.Destroy; begin dxFinalize; inherited Destroy; end;

        You need to call the initialization before creating any controls.
        Also, you need to export our dxInitialize and dxFinalize procedures like the CreateForm one:

        Delphi
        library Module3; ... Exports dxInitialize, dxFinalize, CreateForm;
        1. I see that you never use the FreeLibrary method, so it is unclear where you unload your library.

        2. The "Access Violation" exception is raised because of your TModuleFactory.CreateModule function:

        Delphi
        class function TModuleFactory.CreateModule(ParentForm: TForm; ClientForm: TClientFormClass; App: TApplication): TClientForm; begin Application := App; /// HERE ... end;

        Here you replace the Application variable with your own one that comes from the other form. As a result, after closing the project, your application is destroyed twice and the second time the AV exception is raised.

        To avoid the issue, I recommend you enable runtime packages (at least  "vcl"  and "rtl" ) and comment out the following code string:

        Delphi
        Application := App;

        I've attached your test project containing my modifications to illustrate the issue.

          Hello Mikhail,
          once a module (dll) is loaded, there's no way for explicitly unloading it (by now, maybe it will be necessary later).
          All loaded lbraries are unloaded when the host will be terminated.
          I changed my host's form class so that at first all loaded libraries will be unloaded with FreeLibrary() and I can call the exported dxFinalize inside each library.

          Maybe it's a quite strange construction, but replacing the Application variable is necessary to use the forms inside a library as a MDI-Child for the main form.

          And by the way … using runtime packages is not an option ;-)

          All is working quite well by now, so thank you very much for your efforts.

          Kind regards
          Bernd

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.