FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Problem: DFL doesn't clean up after itself

 
Post new topic   Reply to topic     Forum Index -> DFL
View previous topic :: View next topic  
Author Message
CyberShadow
Site Admin


Joined: 29 Dec 2006
Posts: 21
Location: Moldova, Eastern Europe

PostPosted: Wed Sep 19, 2007 6:25 pm    Post subject: Problem: DFL doesn't clean up after itself Reply with quote

For a typical Windows application, this is not a problem at all. However, if I try to use DFL in a DLL, which is unloaded and then reloaded, DFL fails to initialize. It fails to register window classes (because these classes already exist and DFL never unregisters them). I tried to work around that by making DFL ignore class creation errors, however this causes a "abnormal program termination" error messagebox followed by the whole program terminating. I believe that that error is generated by libc, but I don't know what are the conditions for that happening.

I might investigate the exact cause of that error later. Meanwhile, please consider implementing some clean-up code - or, at least, some graceful handling of resources that have been already initialized Smile
Back to top
View user's profile Send private message
CyberShadow
Site Admin


Joined: 29 Dec 2006
Posts: 21
Location: Moldova, Eastern Europe

PostPosted: Thu Sep 20, 2007 3:04 pm    Post subject: Reply with quote

The "abnormal program termination" was due to CreateWindowEx failing, because the classes were registered by another module. Duh.

DFL really needs clean-up code. I may start writing some, but it'll probably be a hack to get it working for my project.
Back to top
View user's profile Send private message
CyberShadow
Site Admin


Joined: 29 Dec 2006
Posts: 21
Location: Moldova, Eastern Europe

PostPosted: Fri Sep 21, 2007 9:14 am    Post subject: Reply with quote

Remembering registered classes and unregistering them on exit seems to have fixed it.

My changes:
Code:

diff -u -r C:\Downloads\dfl-20070811\import\dfl/application.d C:\Soft\dmd\import\dfl/application.d
--- C:\Downloads\dfl-20070811\import\dfl/application.d   2007-06-15 13:23:08.000000000 +0300
+++ C:\Soft\dmd\import\dfl/application.d   2007-09-21 17:35:04.062500000 +0300
@@ -501,6 +501,8 @@
             UnhookWindowsHookEx(msghook);
          
          tctx.threadExit.removeHandler(&threadJustExited);
+
+         unregisterClasses(getInstance());
       }
    }
    
diff -u -r C:\Downloads\dfl-20070811\import\dfl/internal/utf.d C:\Soft\dmd\import\dfl/internal/utf.d
--- C:\Downloads\dfl-20070811\import\dfl/internal/utf.d   2007-05-13 19:35:16.000000000 +0300
+++ C:\Soft\dmd\import\dfl/internal/utf.d   2007-09-21 17:58:58.062500000 +0300
@@ -349,6 +349,7 @@
    alias LONG function(HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcbValueName,
       LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) RegEnumValueWProc;
    alias ATOM function(WNDCLASSW* lpWndClass) RegisterClassWProc;
+   alias BOOL function(LPCWSTR lpClassName, HINSTANCE hInstance) UnregisterClassWProc;
    alias BOOL function(HDC hdc, LPCWSTR lpString, int cbString, LPSIZE lpSize) GetTextExtentPoint32WProc;
    alias HANDLE function(HINSTANCE hinst, LPCWSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad)
       LoadImageWProc;
@@ -1323,9 +1324,11 @@
    char[] className;
 }
 
+ATOM[] registeredClasses;
 
 ATOM registerClass(inout WndClass wc)
 {
+   ATOM result;
    if(useUnicode)
    {
       version(STATIC_UNICODE)
@@ -1346,15 +1349,47 @@
       }
       
       wc.wcw.lpszClassName = toUnicodez(wc.className);
-      return proc(&wc.wcw);
+      
+      result = proc(&wc.wcw);
    }
    else
    {
       wc.wca.lpszClassName = unsafeAnsiz(wc.className);
-      return RegisterClassA(&wc.wca);
+      result = RegisterClassA(&wc.wca);
    }
+   registeredClasses ~= [result];
+   return result;
 }
 
+void unregisterClasses(HINSTANCE hInstance)
+{
+   if(useUnicode)
+   {
+      version(STATIC_UNICODE)
+      {
+         alias UnregisterClassW proc;
+      }
+      else
+      {
+         const char[] NAME = "UnregisterClassW";
+         static UnregisterClassWProc proc = null;
+         
+         if(!proc)
+         {
+            proc = cast(UnregisterClassWProc)GetProcAddress(user32, NAME.ptr);
+            if(!proc)
+               getProcErr(NAME);
+         }
+      }
+      foreach(atom;registeredClasses)
+         proc(cast(LPCWSTR)atom, hInstance);
+   }
+   else
+   {
+      foreach(atom;registeredClasses)
+         UnregisterClassA(cast(LPCSTR)atom, hInstance);
+   }
+}
 
 BOOL getClassInfo(HINSTANCE hinst, char[] className, inout WndClass wc)
 {
diff -u -r C:\Downloads\dfl-20070811\import\dfl/internal/winapi.d C:\Soft\dmd\import\dfl/internal/winapi.d
--- C:\Downloads\dfl-20070811\import\dfl/internal/winapi.d   2007-07-14 13:18:54.000000000 +0300
+++ C:\Soft\dmd\import\dfl/internal/winapi.d   2007-09-21 17:57:43.609375000 +0300
@@ -2538,6 +2538,8 @@
    BOOL DestroyWindow(HWND hwnd);
    ATOM RegisterClassExA(WNDCLASSEXA* lpwcx);
    ATOM RegisterClassW(WNDCLASSW* lpWndClass);
+   BOOL UnregisterClassA(LPCSTR lpClassName, HINSTANCE hInstance);
+   BOOL UnregisterClassW(LPCWSTR lpClassName, HINSTANCE hInstance);
    HWND GetActiveWindow();
    LRESULT DefDlgProcA(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
    LRESULT DefDlgProcW(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);


It needs a setInstance call from user code to work properly. It's pretty hard to do it because HINSTANCE is a private type (HANDLE alias, which is a typedef and thus incompatible with base types) declared in dfl.internal._stdwindows - so I had to write Application.setInstance(cast(dfl.internal._stdcwindows.HINSTANCE)hInstance).
Back to top
View user's profile Send private message
Chris Miller



Joined: 27 Mar 2004
Posts: 514
Location: The Internet

PostPosted: Sat Sep 22, 2007 1:36 pm    Post subject: Reply with quote

Thanks, I will try to incorporate it soon.

- Chris
Back to top
View user's profile Send private message
CyberShadow
Site Admin


Joined: 29 Dec 2006
Posts: 21
Location: Moldova, Eastern Europe

PostPosted: Sat Sep 22, 2007 1:39 pm    Post subject: Reply with quote

I'd like to add that this isn't a complete solution. If I understand Windows GUI correctly, each module must register its own window classes separately, and there may not be class name conflicts between modules. This means that, in order for DFL to be used by more than one module in the same application, DFL must create the classes with unique names (e.g. appending the module instance number to each class name).
Back to top
View user's profile Send private message
Chris Miller



Joined: 27 Mar 2004
Posts: 514
Location: The Internet

PostPosted: Fri Sep 28, 2007 10:30 pm    Post subject: Re: Problem: DFL doesn't clean up after itself Reply with quote

The current snapshot improves this situation. I also put up a new DLL example on the ExampleCode page.

It requires each EXE and DLL to have its own copy of DFL, I think you've been trying to share one. The window classes unregister when the EXE or DLL is unloaded.

Note that for having separate copies of DFL, it might be better for them to have their own threads so they can have their own Application.run(). The example doesn't do this. Sorry this use of DFL isn't well tested or supported, you'll probably have to hack your way through it, as you've been; I'll help along the way.
Back to top
View user's profile Send private message
CyberShadow
Site Admin


Joined: 29 Dec 2006
Posts: 21
Location: Moldova, Eastern Europe

PostPosted: Fri Dec 07, 2007 11:38 am    Post subject: Reply with quote

Sorry, the changes in that snapshot did not solve my problem. The second time the DLL loads, it crashes with the following call stack:

__d_throw@4
_D3dfl11application13_initInstanceFT3dfl8internal12_stdcwindows6HANDLEZv
_D3dfl11application11Application11setInstanceFT3dfl8internal12_stdcwindows6HANDLEZv
...

To make it clear: I have a non-DFL EXE (which does have a message loop) and a DFL DLL. The EXE needs to load and unload the DFL DLL arbitrarily. DFL still does not unregister window classes, which causes it to fail initializing a second time.

Note: I re-applied my patch (specified above) and everything is working fine for me again. Either I'm not understanding something impotant about atoms/registered classes, or that's the only way to solve my problem. The patch makes note of which classes were registered, and unregisters them when DFL deinitializes.

Also, the DLL examples are missing calls to module destructors (_moduleDtor). The first DLL example on DigitalMars omits this as well, but it's a documentation bug on their side.
Back to top
View user's profile Send private message
Chris Miller



Joined: 27 Mar 2004
Posts: 514
Location: The Internet

PostPosted: Sat Dec 08, 2007 4:13 pm    Post subject: Reply with quote

It's not clear if you're calling Application.setInstance() in DllMain, but in this case it is required. See the example for when it needs to be called. If you don't, the window classes are registered in the exe and not the dll. If registered in the dll (by properly using Application.setInstance) they should be unloaded when the dll is unloaded, and they should be kept separate from other dlls, as the example works.
Back to top
View user's profile Send private message
CyberShadow
Site Admin


Joined: 29 Dec 2006
Posts: 21
Location: Moldova, Eastern Europe

PostPosted: Sat Dec 08, 2007 4:16 pm    Post subject: Reply with quote

Like the DLL example, I do call Application.setInstance before calling the module static constructors. I don't know why would DFL register the classes with the EXE's instance.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> DFL All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group