alank2 5 Posted Friday at 05:01 PM The DLL has: #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { if (reason==DLL_PROCESS_ATTACH) { Application->Initialize(); Form1=new TForm1(NULL); } else if (reason==DLL_PROCESS_DETACH) { if (Form1!=NULL) { delete Form1; Form1=NULL; } } return 1; } The attach section works fine. The Form1 is created and works great. If I omit the cleanup in the detach section, no error, but if I include the above I get the 0x0eedfae exception when closing the application that uses the DLL. Any ideas on why? Could the Form1 have already been deleted/cleaned up before the DllEntryPoint is called with DLL_PROCESS_DETACH? Share this post Link to post
Remy Lebeau 1534 Posted Friday at 06:20 PM (edited) 1 hour ago, alank2 said: The attach section works fine. The Form1 is created and works great. Actually, no. Creating and destroying windows is highly discouraged in DllEntryPoint(), see: Dynamic-Link Library Best Practices: Quote You should never perform the following tasks from within DllMain: ... Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized. ... Guess where the CreateWindow/Ex() and DestroyWindow() functions reside - in user32.dll ! 1 hour ago, alank2 said: If I omit the cleanup in the detach section, no error, but if I include the above I get the 0x0eedfae exception when closing the application that uses the DLL. Any ideas on why? 0x0EEDFADE is the exception code when a Delphi exception escapes into the C++ runtime. So, what exception type exactly is the TForm destructor actually throwing? My guess is EOSError if DestroyWindow() fails. But a TForm destruction does a lot of things, so there could be any number of reasons why it would fail while the DLL is in the process of being unloaded from memory. 1 hour ago, alank2 said: Could the Form1 have already been deleted/cleaned up before the DllEntryPoint is called with DLL_PROCESS_DETACH? Perhaps, if your DLL's TApplication object were already destroyed (or in the process of being destroyed). You should run your code in the debugger and verify that. Your global Form1 variable would not be updated in that situation, so you would have a dangling pointer. One way to handle that would be to assign NULL to your variable in your Form's destructor. But really, this is not the kind of stuff that you should be doing in your DllEntryPoint() to begin with. It would be better to export a couple of functions from your DLL that the loading app can then call after loading the DLL and before unloading it. Edited Friday at 06:30 PM by Remy Lebeau 1 Share this post Link to post
Kas Ob. 128 Posted Saturday at 09:24 AM One small addition to Remy detailed answer, There is zero guarantee that DllMain will be called from the the Main Thread or even the the same thread that called LoadLibrary ! So all bets are off using VCL, while RTL should be OK if thread safety used with it (locking/synchro..) Share this post Link to post
Remy Lebeau 1534 Posted Saturday at 04:40 PM (edited) 7 hours ago, Kas Ob. said: There is zero guarantee that DllMain will be called from the the Main Thread or even the the same thread that called LoadLibrary ! DLL_PROCESS_ATTACH should be in the same thread that calls LoadLibrary(), but DLL_PROCESS_DETACH is not guaranteed to be in that same thread. Raymond Chen even blogged about this issue back in 2009 (emphasis added by me): The thread that gets the DLL_PROCESS_DETACH notification is not necessarily the one that got the DLL_PROCESS_ATTACH notification Quote The thread that gets the DLL_PROCESS_DETACH notification is not necessarily the one that got the DLL_PROCESS_ATTACH notification. This is obvious if you think about it, because the thread that got the DLL_PROCESS_ATTACH notification might not even exist any longer when the DLL is unloaded. How can something that doesn’t exist send a notification? Even so, many people fail to realize this. You can’t do anything with thread affinity in your DLL_PROCESS_ATTACH or DLL_PROCESS_DETACH handler since you have no guarantee about which thread will be called upon to handle these process notifications. Of course, you’re not supposed to be doing anything particularly interesting in your DLL_PROCESS_ATTACH handler anyway, but things with thread affinity are doubly bad. The classic example of this, which I’m told the Developer Support team run into with alarming frequency, is a DLL that creates a window in its DLL_PROCESS_ATTACH handler and destroys it in its DLL_PROCESS_DETACH handler. Now, creating a window in DllMain is already a horrifically bad idea since arbitrary code can run during the creation of a window (for example, there may be a global hook), but the lack of a thread guarantee makes it downright insane. The DLL calls DestroyWindow in its DLL_PROCESS_DETACH handler, but since that notification comes in on a thread different from the one that received the DLL_PROCESS_ATTACH notification, the attempt to destroy the window fails since you must call DestroyWindow from the same thread that created it. Result: The DLL’s attempt to destroy its window fails, a message comes in, and the process crashes since the window procedure no longer exists. Edited Saturday at 05:00 PM by Remy Lebeau 1 Share this post Link to post
alank2 5 Posted Monday at 06:45 PM Thank you everyone; I'll dig into this some more with your ideas. Share this post Link to post