Quote
Vincent Schmid wrote:
>My application dynamically loads TUTIL32.DLL with
>the LoadLibrary API. It works then fine, and every
>call to the DLL function succeed. When the program
>terminates it provoques an access violation. This
>problem does not occur if I do not call FreeLibrary.
You didn't indicate where in your app the DLL is loaded
and freed, but almost certainly you're freeing too early.
To stab in the dark I'd guess you're
(i) doing LoadLibrary in a form initialization section
(ii) using the library in either its FormCreate,
FormShow or in one of its children
(iii) closing the function handles in either its
FormDestroy, the OnDestroy of one of its
components, controls or child forms,
or the FormClose of an MDI child, and
(iv) then calling FreeLibrary in form finalization.
The above is a recipe for access violation because
- unless you explicitly free a form within your code
(via Free method or MDI child caFree) its
FormDestroy handler isn't called until *after*
its unit's finalization - when the Forms unit
finalization calls Application.DestroyComponents
- MDI children don't get FormClose until *after*
their finalization if the application quit due to
clicking system menu or calling MainForm.Close,
Application.Terminate or PostQuitMessage.
That's my best guess. The fix would be to load/free
the DLL in your main form's OnCreate & OnDestroy
methods and ensure that the DLL is not used in either
the DPR or any of the initialization/finalization sections
of your forms or their components. Similarly be sure to
avoid use of AddExitProc in your forms or components
(it's obsolete anyway because it's not package-safe) .
The other nice way to use a DLL is to encapsulate it
in an object or component, loading/freeing in that
object's constructor/destructor. Provided that access
is only via properties (ie handles aren't recklessly
passed out) this ensures that functions aren't called
beyond module lifetime. As an example see the
TIBEventAlerter component in samples\ibctrls.pas
which encapsulates GDS32.DLL.
It's not always possible to encapsulate things nicely, but
too often people just LoadLibrary/GetProcAddress and
shove the pointers into global variables with little thought
for limiting their scope. IME the majority of shutdown AVs
can be traced back to global variables. Inevitably you
end up with flags all over the place to disable shutdown-
time activity everywhere that the variables might be used.
Several of the uglier VCL units bear that curse. (Other
problems with global variables of course are threadsafety
and data segment limits.)
By the way, don't even think about loading/freeing the
DLL in your DPR before/after Application.Run: if you
get a runtime error your DLL won't get freed.
HTH
Grant Walker
sydney australia