Announcement

Collapse
No announcement yet.

Calls to DLLMain

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Calls to DLLMain

    I’m trying to get my head around when and why DllMain() is called. Here’s what I’ve learned so far:

    DllMain( DLL_PROCESS_ATTACH ) is called when any application using the dll starts;

    DllMain( DLL_PROCESS_DETACH ) gets called when the application using the dll terminates;

    Both DllMain( DLL_THREAD_ATTACH ) and DllMain( DLL_THREAD_DETACH ) are only called if the calling application starts/ends a new thread; and

    That if more than one application uses the same dll then DllMain( DLL_PROCESS_ATTACH ) will be called each time any of these applications starts. And each time one of these applications terminates then a corresponding call to DllMain( DLL_PROCESS_DETACH ) will be made.

    Sound right?


    Pat

  • #2
    > more than one application

    One detail... DLL_PROCESS_ATTACH is triggered when an instance of an application is launched. For example, if 10 copies of the same application are started, DLL_PROCESS_ATTACH will be seen 10 times. Same for _DETACH, as the instances close.

    -- Eric
    "Not my circus, not my monkeys."

    Comment


    • #3
      Good place to register window classes for custom controls (hint > grid).
      Fred
      "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

      Comment


      • #4
        >Good place to register window classes for custom controls (hint > grid).

        You need to check the specific Windows' functions which are called to do so, both explicit and implicit:

        Warning The entry-point function should perform only simple initialization tasks. It must not call the LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, the entry-point function must not call the FreeLibrary function (or a function that calls FreeLibrary), because this can result in a DLL being used after the system has executed its termination code.

        It is safe to call other functions in Kernel32.dll, because this DLL is guaranteed to be loaded in the process address space when the entry-point function is called. It is common for the entry-point function to create synchronization objects such as critical sections and mutexes, and use TLS. Do not call the registry functions, because they are located in Advapi32.dll. If you are dynamically linking with the C run-time library, do not call malloc; instead, call HeapAlloc.

        Calling imported functions other than those located in Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions in their DLLs call LoadLibrary to load other system components.
        MCM
        Michael Mattias
        Tal Systems Inc. (retired)
        Racine WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Fred,

          Good place to register window classes for custom controls (hint > grid).
          Yep, good guess - it is a Custom Control and I'm using DllMain( DLL_PROCESS_ATTACH ) to call RegisterClassEx().

          It's the Grid control that I started working on last year - with other real work commitments I may one day actually finish it

          Pat

          Comment


          • #6
            Tip: Do NOT register window classes, use GUI code (for example, MessageBox), or otherwise load other DLLs in LIBMAIN. What it says in the MSDN doc is true, you will get hard-to-find crashes.

            The most recent one for me only occurred on Vista, moving the GUI initialization code to an individual function cured the crash. If you need to make sure that the caller has called your init function, use a global flag (such as gnInitialized) that can be checked to to ensure the init function has been called.
            kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

            Comment


            • #7
              And don't forget, if your initialization function uses any PB syntax other than 'pure' calls to functions in KERNEL32.DLL, you are implicitly calling functions NOT in KERNEL32.DLL

              e.g, any operation which creates an OLE string calls functions in OLEAUT32.DLL

              No, there is no documentation on which functions are called by what PB verbs.. nor will there ever likely be. "How" the compiler implements your source code is the very 'guts' of the "proprietariness" (is that a word?) of the compiler product.
              Michael Mattias
              Tal Systems Inc. (retired)
              Racine WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                My standard way of registering window classes for my grid controls has always been to use DLL_PROCESS_ATTACH and I've never had any problems with it. However, I've never used Vista either. Specifically, I've used every other Microsoft 32 bit OS from 95 onward but as just mentioned - no Vista. I seem to recall having this discussion before.

                I also use the SIGrid control some. If I recall, that grid control has an InitGrid() function that must be called before a CreateWindowEx() call is used to instantiate an instance of the grid. I take it that is what Kev and Michael are alluding to. I suppose I could do it that way too. It just seems cleaner somehow to just register the class in DLL_PROCESS_ATTACH. I certainly am not privy to Microsoft's implementation of RegisterClassEx() , but that call certainly does not produce any GUI output. What it more than likely does is add the new class name to an internal atom table and create and fill out some internal data structures.

                Was the problem you had Kev specifically a RegisterClassEx() call in DLL/LIBMain?
                Fred
                "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                Comment


                • #9
                  RegisterClass and associated window functions are in USER32.DLL. Your first call to this library will trigger a load of that library, potentially a big problem if your code is in LIBMAIN.

                  I had two DLLs doing this at once, which triggered the crash. I ended up spending hours stripping down the crashing program (which, as I found out crashed on startup) to just a simple PBMAIN function which called one function in each of the DLLs, which then exhibited the problem. Moving the code from LIBMAIN into an init-function and calling that from the main program code solved the crash.

                  This is by no means Vista specific - I remember I was having trouble with it in Windows 2000 years ago. Do yourself a favour and follow the doc - don't call non-kernel32 functions from LIBMAIN (or from function(s) called by LIBMAIN), it will avoid any future problems
                  Last edited by Kev Peel; 29 Apr 2008, 11:30 AM.
                  kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

                  Comment


                  • #10
                    > Moving the code from LIBMAIN into an init-function and
                    > calling that from the main program code solved the crash.

                    One of the hardest bugs I've ever had to kill involved calling a DLL other than KERNEL32 in DLL_PROCESS_ATTACH.

                    Another good technique is to use an auto-check-for-init function in critical places.
                    Code:
                    FUNCTION CreateMyCustomControl(whatever) AS LONG
                     
                       IF InitMyCustomClass = 1 THEN
                           'create the custom control using the class
                       ELSE
                           'display error message   
                       END IF
                     
                    END FUNCTION
                    The Init function would contain something like this...
                    Code:
                        DIM lInitDone AS STATIC LONG
                    
                        IF lInitDone THEN
                            'The class has already been registered; do nothing
                        ELSE
                            'register the class
                            lInitDone = 1 '(or =0 if the registration fails)
                        END IF
                        
                        FUNCTION = lInitDone
                    It involves writing some extra code, but the calling program(mer) can't possibly forget to call the init-function, because it's automatic.

                    -- Eric
                    Last edited by Eric Pearson; 29 Apr 2008, 12:08 PM.
                    "Not my circus, not my monkeys."

                    Comment


                    • #11
                      I fear I'm going to come across as overly intransigent on this point (and I do appreciate enlightenment I'm receiving), but if a host app of a custom control is itself a GUI application in which a window class has already been registered and instantiated for the host app's main program window, then is it not true that user32.dll (among others) will already have been loaded into the process's address space - which is the same address space into which the dll will be loaded?

                      While I've never had a problem with it, as I've said, I will say I always call LoadLibrary() on the dll first. I'm not entirely sure where or how that figures into it. Its of course as a response to LoadLibrary() that DLL_PROCESS_ATTACH occurs in the dll. But long before that point the host app (the caller) would have had access to user32.dll, gdi32.dll, etc?
                      Fred
                      "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                      Comment


                      • #12
                        If YOUR library is ALWAYS loaded with an explicit "LoadLibrary" call (no DECLAREs: any callsto any function in that library is made via getProcAddress/CALL DWORD), and you know the using program has always loaded USER32.DLL, you can get away with 'doing forbidden stuff' on DllMain/DLL_PROCESS_ATTACH.

                        If you use DECLAREs for the library function, you no longer have any control over the ORDER in which DLLs are loaded to the process' address space.

                        Short version: New shooter, coming out.
                        Michael Mattias
                        Tal Systems Inc. (retired)
                        Racine WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          Its of course as a response to LoadLibrary() that DLL_PROCESS_ATTACH occurs in the dll.
                          But long before that point the host app (the caller) would have had access to user32.dll, gdi32.dll, etc?
                          The assumption in the second sentence is not correct. An app(the caller) can load DLLs long before
                          it accesses the USER or GDI. You seem to be assuming that the caller will only load your DLL after
                          it creates a host window.
                          Dominic Mitchell
                          Phoenix Visual Designer
                          http://www.phnxthunder.com

                          Comment


                          • #14
                            In the heat of the moment I may have gone too far with regard to Gdi32.dll, but if its a gui custom control in a dll being instantiated during a WM_CREATE message in the host app (the caller), as a necessary prerequisite to that WM_CREATE message a window class would have to have been registered in WinMain(), and it is highly likely several calls would have already been made to such User32 functions as LoadIcon(), LoadCursor(), GetStockObject(); the latter of which would have in fact caused Gdi32 to load.
                            Fred
                            "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                            Comment


                            • #15
                              but if its a gui custom control in a dll being instantiated during a WM_CREATE message
                              in the host app (the caller), as a necessary prerequisite to that WM_CREATE message a
                              window class would have to have been registered in WinMain(),
                              This just verifies what I thought you were assuming. You seem to be forgetting that an
                              app can call LoadLibrary on your DLL without the intention of creating a windowed instance
                              of the control. For example, it could be checking whether the control exists, version info,
                              or for predefined exported functions. This can be done long before the main application
                              window is created, or the verification routines might be located in a DLL which means that
                              the load order of the DLLs cannot be guaranteed.
                              A Visual Designer is one type of application that might do this.
                              Dominic Mitchell
                              Phoenix Visual Designer
                              http://www.phnxthunder.com

                              Comment


                              • #16
                                Why don't we just cut to the chase here, shall we, Fred?
                                Good place to register window classes for custom controls (hint > grid)?
                                Answer: No.
                                Michael Mattias
                                Tal Systems Inc. (retired)
                                Racine WI USA
                                [email protected]
                                http://www.talsystems.com

                                Comment


                                • #17
                                  Fred --

                                  All I know for an absolute fact is that Microsoft (the publisher of the API) says "don't do it". So I no longer do.

                                  -- Eric
                                  "Not my circus, not my monkeys."

                                  Comment


                                  • #18
                                    The executable image of the most basic Hello, World! Sdk Windows program possible contains 52 imports as determined by Torsten Rienow's (further modified by Michael C. Mattias) Import/Export utility at...

                                    http://www.powerbasic.com/support/fo...ML/001212.html

                                    One of the sixteen functions imported from USER32.DLL is RegisterClassEx(), and that function returns an atom as I had previously stated. The atom and Windows memory allocation functions are all in Kernel32.dll, to the best of my knowledge. Perhaps that explains why I and others have never encountered any difficulties using the DLL_PROCESS_ATTACH message to register Window Classes for custom controls. In terms of visual designer creators for PowerBASIC products, I'm pretty sure Chris Boss uses this technique for the custom controls he includes in his product.

                                    However, considering the grief bugs can cause, it makes all kinds of sense to avoid any practice that has the potential for causing trouble, especially when easy work arounds such as those suggested by Kev and Eric are so easily implementable.
                                    Fred
                                    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                                    Comment


                                    • #19
                                      [ scholarly stuff] ......
                                      .....The atom and Windows memory allocation functions are all in Kernel32.dll, to the best of my knowledge. Perhaps that explains why I and others have never encountered any difficulties ...
                                      Then again, it may have been just plain old dumb luck.
                                      Michael Mattias
                                      Tal Systems Inc. (retired)
                                      Racine WI USA
                                      [email protected]
                                      http://www.talsystems.com

                                      Comment


                                      • #20
                                        Pure Dumb luck...its like vegas...you may have a system, it may work for a while but then WHAM out of the blue for some reason your "System does not work anymore"

                                        I am just now learning...."Lil by lil" but from experiencing troublesome ideas that only Kernel32 functions are "Semi-Guaranteed" to be there (if not, then forget it, the computer is hosed ), Functions in User32 are "Pretty Much Guaranteed"(but don't do it, and in most cases no User32, then the computer is hosed anyways)

                                        and it gets detrimental from there. (Whether you coded it yourself, or even knew the compiler uses a lower API call to allow you to use it)

                                        New Shooter coming out....but I think I got a system....
                                        Although it calls for 2 extra functions (load and unload), that seem to "Auto-Magically") call Libmain on first "Touch"

                                        The way I take it is the process is:
                                        1. The 1st process (Parent EXE or whatever) to access a DLL not only loads the DLL into its memory, but into the computer memory (either by "Declares" or Loadlibrary) and makes it like you originally coded it into your program (like adding a INC file)
                                        2. Every Process after this gets their own copy (each separate) from the other Parent Process (so no cross contamination)
                                        3. (Pretty sure...but not 100%) Dll remains in memory UNTIL all processes release...(including if the 1st process releases, but the 3rd and 12th are still using it, so it remains locked until ALL are done)
                                        4. If the above are true, then that is why the docs say only the Kernel should be called, because it IS the operating system...and each (semi) guaranteed step away from it, brings you that much closer to "Ooops sorrry...too bad...sooo sad")

                                        Or at leas thats my take on it....I may be way off and not know it
                                        Engineer's Motto: If it aint broke take it apart and fix it

                                        "If at 1st you don't succeed... call it version 1.0"

                                        "Half of Programming is coding"....."The other 90% is DEBUGGING"

                                        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                                        Comment

                                        Working...
                                        X