Announcement

Collapse
No announcement yet.

can we use mutex for DLL files ?

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

  • can we use mutex for DLL files ?

    Hi All, I have a main program that call several PB DLL files, I'm wondering if I can place different MUTEXes in each of these DLLs

    so that when the main program can call or load only one instance of each DLL at any one time.

  • #2
    Originally posted by Tim Lakinir View Post
    Hi All, I have a main program that call several PB DLL files, I'm wondering if I can place different MUTEXes in each of these DLLs

    so that when the main program can call or load only one instance of each DLL at any one time.
    How do you see your main program loading more that one instance of a DLL?

    Comment


    • #3
      Thanks Stuart, yes sometimes the main may call up the SAME dll several times which may need to be control in some situation

      I'm trying to ensure that the same dll is not called more than once as it is sometimes in certain situations we need to be able to control as we do
      engineering computations programming

      Comment


      • #4
        I have also found out that MUTEX do work for DLL , I tested run the below codes with the Main prog.exe calling 2 separate DLLs

        1. if the DLL prog1.dll and DLL prog2.dll have the same mutex then DLL prog2.dll won't work

        2. if the DLL prog1.dll and DLL prog2.dll have the DIFFERENT mutex then DLL prog2.dll would work

        the Main Prog.bas
        Code:
        ' Main Prog.bas
        ' modified from
        ' http://www.garybeene.com/power/tutorial/pb-tutor-dll.htm
        
        #COMPILE EXE
         #DIM ALL
         #INCLUDE "WIN32API.INC"
        
            DECLARE FUNCTION RandomAdd  LIB "DLL prog1.dll" ALIAS "RandomAdd" (BYVAL x&) AS LONG
            DECLARE FUNCTION RandomAdd2 LIB "DLL prog2.dll" ALIAS "RandomAdd2" (BYVAL x&) AS LONG
        
        
            FUNCTION PBMAIN () AS LONG
                DIM a AS LONG,b AS LONG
                a = RandomAdd(b)
                MSGBOX " a  " + STR$(a)
        
              ' this won't work which results in u2 = 0
              ' if the mutex of DLL prog2.dll
              ' is the same as DLL prog1.dll
                DIM u2 AS LONG, ub AS LONG
                u2 = RandomAdd2(ub)
                MSGBOX " u2  " + STR$(u2)
        
              '  hence mutex does work for dll
        
        
            END FUNCTION

        the DLL prog1.bas
        Code:
         ' Dll prog1.bas
         #COMPILE DLL   'directs compiler to create DLL
         #DIM ALL
         #INCLUDE "WIN32API.INC"
        
            FUNCTION RandomAdd ALIAS "RandomAdd" (BYVAL x AS LONG) EXPORT AS LONG
        
               ' check mutex for ProgDlg2.exe
                LOCAL chkInst AS LONG
                chkinst = chkanotherInstance2()
                IF chkinst = -1 THEN
          '        another instance exist -- exit this program
                   EXIT FUNCTION
                END IF
        
        
               RANDOMIZE TIMER
               RandomAdd = x + RND * 100    'adds random amount to x
            END FUNCTION
        
        
          '=============================================
         ' this function prevents loading another
        ' instance of ProgDlg2.exe
        'https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/817778-does-the-use-of-atom-slows-down-the-loading-of-a-program?p=817780#post817780
        ' Great Thanks to Peter
        FUNCTION chkanotherInstance2() AS LONG
          ' Mutex for ProgDlg2
            LOCAL  atmtxt AS ASCIIZ * 33
            LOCAL  myatom AS STRING
        
           myatom = "m56ertmHJK-#[email protected]#"
           LOCAL hmutex AS DWORD
           LOCAL Numutex AS LONG
           Numutex = 1553902
           atmtxt =  myatom + STR$(Numutex)
           hMutex = CreateMutex (BYVAL %Null, 0 ,atmtxt)
           IF hMutex AND (GetLastError = %ERROR_ALREADY_EXISTS) THEN
          '   an instance of the program already running
             ' we must exit this program
             FUNCTION = -1
           ELSE
             FUNCTION = 0
           END IF
        
        END FUNCTION


        the DLL prog2.bas
        Code:
         ' Dll prog2.bas
         #COMPILE DLL   'directs compiler to create DLL
         #DIM ALL
         #INCLUDE "WIN32API.INC"
        
            FUNCTION RandomAdd2 ALIAS "RandomAdd2" (BYVAL x AS LONG) EXPORT AS LONG
        
               ' check mutex for ProgDlg2.exe
                LOCAL chkInst AS LONG
                chkinst = chkanotherInstance3()
                IF chkinst = -1 THEN
          '        another instance exist -- exit this program
                   EXIT FUNCTION
                END IF
        
        
               RANDOMIZE TIMER
               RandomAdd2 = x + RND * 100 + 3000   'adds random amount to x
            END FUNCTION
        
        
          '=============================================
         ' this function prevents loading another
        ' instance of ProgDlg2.exe
        'https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/817778-does-the-use-of-atom-slows-down-the-loading-of-a-program?p=817780#post817780
        ' Great Thanks to Peter
        FUNCTION chkanotherInstance3() AS LONG
          ' Mutex for ProgDlg2
            LOCAL  atmtxt AS ASCIIZ * 33
            LOCAL  myatom AS STRING
        
         '  same myatom as DLL prog1.DLL
         '  myatom = "m56ertmHJK-#[email protected]#"
         '  different myatom from DLL prog1.DLL
           myatom  = "pakerghergh-#[email protected]#"
           LOCAL hmutex AS DWORD
           LOCAL Numutex AS LONG
           Numutex = 1553902
           atmtxt =  myatom + STR$(Numutex)
           hMutex = CreateMutex (BYVAL %Null, 0 ,atmtxt)
           IF hMutex AND (GetLastError = %ERROR_ALREADY_EXISTS) THEN
          '   an instance of the program already running
             ' we must exit this program
             FUNCTION = -1
           ELSE
             FUNCTION = 0
           END IF
        
        END FUNCTION

        Comment


        • #5
          Your logic is confused.
          Using a mutex to control the program flow in a function does not ensure that "the main program can call or load only one instance of each DLL at any one time."

          Both DLLs are loaded by the applicaion when it starts and the functions in both are then available.in the application.
          All your code does is prevent a function in the DLL from returning a valid value if that function or a function in another DLL (or even one in your main application) has set a specific mutex and the mutex still exists.
          The DLLs are still loaded and any other function in the DLL can still be called.

          It doesn't matter which DLL' s function you call first. Once you have done so, calling either of them subsequentlly will return "0" for the life of your application (until your appplication specifically releases the mutex or the application closes and the mutex becomes "abandoned".)
          What you have done is essentially create a "use-once" function.
          It is exactly the same as if you had put the functions in your main application instead of a DLL.
          You would still only be able to call one of the functions once and subsequent call to either function would fail.

          Comment


          • #6
            Thank you Stuart, it is true any subsequent call to DLL prog1.dll will also fail !

            Is there a statement or command to delete or release a mutex after its use ? for atoms we can use Globaldeleteatom()
            is there an equivalent command for mutex ?

            Comment


            • #7
              Originally posted by Tim Lakinir View Post
              Thank you Stuart, it is true any subsequent call to DLL prog1.dll will also fail !
              Please, get this clear: You dont "call a DLL", you "load a DLL" and then "call a function in a DLL". If you want something to happen when you "load a DLL", you need to put code in the LIBMAIIN() function (look it up in Help)
              Any call to the functions RandomAdd1 or RandomAdd2 will fail. If there were any other functions in the DLLs, you would be able to call them with no problem.

              Is there a statement or command to delete or release a mutex after its use ? for atoms we can use Globaldeleteatom()
              is there an equivalent command for mutex ?
              ReleaseMutex. will delete it IF it is called by the process (application in this case) that created the mutex (has ownership) AND there is no thread or other application trying to get ownership of the mutex with a "WaitForSingleObject" or similar.

              Note that it doesn't matter whether the mutex is created in functions in the DLLs or functions in your main application. The mutex is owned by your application's main thread ( process) so you can release it from any function in the main application (including PBMain() ) or a DLL..

              Comment


              • #8
                is there an equivalent command for mutex ?
                First item on search for MSDN mutex is
                Using Mutex Objects - Win32 apps | Microsoft Docs
                MSDN is help doc for Windows
                Dale

                Comment


                • #9
                  Thank you Dale and Stuart, I have given up on Mutex as it is a hard beast to handle, so I check for the existence of a loaded DLL using FindWindow() which
                  is more efficient, the below program illustrate this method.

                  I have tried using LIBMAIN() and Mutex and it doesn't work out, even if we exit the DLL and do a ReleaseMutex()
                  it doesn't work

                  MyMain.exe program
                  Code:
                  ' MyMain.bas
                  ' https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/766076-subclass-dialog-from-dll?p=766170#post766170
                  
                  #COMPILE EXE
                  #DIM ALL
                  
                  #INCLUDE "WIN32API.INC"
                  
                  %IDD_DIALOG1 =  101
                  %IDC_BUTTON1 = 1001
                  
                  'GLOBAL FlagRan AS long
                  
                  DECLARE FUNCTION startdll LIB "WinDisp-dll.dll" ALIAS "initdll" (BYVAL xx AS LONG) AS LONG
                  
                  FUNCTION PBMAIN()  '   ** Main Application Entry Point **
                      ShowDIALOG1 %HWND_DESKTOP
                  END FUNCTION
                  
                  '------------------------------------------------------------------------------
                  CALLBACK FUNCTION ShowDIALOG1Proc() '   ** CallBacks **
                      LOCAL lblTEXT AS ASCIIZ * 20
                      LOCAL lRes AS DWORD
                      LOCAL hDLL AS DWORD
                  
                      SELECT CASE AS LONG CBMSG
                  
                          CASE %WM_COMMAND
                              SELECT CASE AS LONG CBCTL
                                  CASE %IDC_BUTTON1
                                    DIALOG SET TEXT CB.HNDL, HEX$(GetActiveWindow)        ' test
                                   ' IF hMutex THEN
                                      ' ReleaseMutex(hMutex)
                                  '  END IF
                                   hDLL = FindWindow("","WinDisp-dll" )
                                   IF hDLL = 0 THEN
                                  ' if FlagRan = 0 then
                                      lRes = startdll( GetActiveWindow() )  ' Send active hWnd      ' should be Dialog1..
                                    '  if lRes then
                                      '   FlagRan = 1
                                     ' end if
                                    END IF
                   '                  If lRes Then Control Disable Cb.Hndl, %IDC_BUTTON1
                              END SELECT
                      END SELECT
                  END FUNCTION
                  
                  
                  '------------------------------------------------------------------------------
                  FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG   '   ** Dialogs **
                      LOCAL lRslt AS LONG
                      LOCAL hDlg  AS DWORD
                      DIALOG NEW PIXELS, hParent, "Dialog1", 70, 70, 301, 221, _
                            %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                            %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX TO hDlg
                      CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Start WinDisp-dll", 85, 30, 100, 20
                      DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                      FUNCTION = lRslt
                  END FUNCTION

                  WinDisp-dll.DLL program .
                  Code:
                  ' WinDisp-dll.bas
                  
                  #COMPILE DLL
                  #DIM ALL
                  #INCLUDE "Win32API.inc"
                  
                  %IDC_Button = 500
                  %IDC_Button1= 501
                  
                  GLOBAL hWndMain   AS DWORD
                  GLOBAL ghWndInst  AS DWORD
                  GLOBAL gOldProc   AS DWORD
                  
                  ' GLOBAL hmutex AS DWORD
                  
                  
                  '-------------------------------------------------------------------------------
                  ' Main DLL entry point called by Windows...
                  '
                  FUNCTION LIBMAIN (BYVAL hInstance   AS LONG, _
                                    BYVAL fwdReason   AS LONG, _
                                    BYVAL lpvReserved AS LONG) AS LONG
                  
                      SELECT CASE fwdReason
                          CASE %DLL_PROCESS_ATTACH
                              'Indicates that the DLL is being loaded by another process (a DLL
                              'or EXE is loading the DLL).  DLLs can use this opportunity to
                              'initialize any instance or global data, such as arrays.
                  
                              FUNCTION = 1   'success!
                              'FUNCTION = 0   'failure!  This will prevent the EXE from running.
                  
                          CASE %DLL_PROCESS_DETACH
                              'Indicates that the DLL is being unloaded or detached from the
                              'calling application.  DLLs can take this opportunity to clean
                              'up all resources for all threads attached and known to the DLL.
                            '  if hMutex then
                                ' ReleaseMutex(hMutex)
                             ' end if
                              FUNCTION = 1   'success!
                              'FUNCTION = 0   'failure!
                  
                          CASE %DLL_THREAD_ATTACH
                              'Indicates that the DLL is being loaded by a new thread in the
                              'calling application.  DLLs can use this opportunity to
                              'initialize any thread local storage (TLS).
                  
                              FUNCTION = 1   'success!
                              'FUNCTION = 0   'failure!
                  
                          CASE %DLL_THREAD_DETACH
                              'Indicates that the thread is exiting cleanly.  If the DLL has
                              'allocated any thread local storage, it should be released.
                             ' IF hMutex THEN
                              '   ReleaseMutex(hMutex)
                            '  END IF
                              FUNCTION = 1   'success!
                              'FUNCTION = 0   'failure!
                      END SELECT
                  END FUNCTION
                  
                  
                  
                  FUNCTION initdll ALIAS "initdll"(BYVAL hInst AS LONG ) EXPORT AS LONG
                      LOCAL hwnd  AS DWORD
                      LOCAL lpCmdLine AS ASCIIZ PTR
                  
                         ' check mutex for WinDisp-dll.dll
                        '  LOCAL chkInst AS LONG
                        '  chkinst = chkanotherInstance2()
                        '  IF chkinst = -1 THEN
                    '        another instance exist -- exit this dll
                          '   EXIT FUNCTION
                        '  END IF
                  
                  
                  
                      ghWndInst = hInst                           ' Global handle to Dialog1 (Target?)
                      hwnd = GetParent(hwnd)                      ' ??
                      WINMAIN hwnd, 0, lpCmdLine, %SW_SHOW
                     FUNCTION = ghWndInst
                  END FUNCTION
                  
                  
                  
                   '=============================================
                   ' this function prevents loading another
                  ' instance of ProgDlg2.exe
                  'https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/817778-does-the-use-of-atom-slows-down-the-loading-of-a-program?p=817780#post817780
                  ' Great Thanks to Peter
                  FUNCTION chkanotherInstance2() AS LONG
                    ' Mutex for ProgDlg2
                      LOCAL  atmtxt AS ASCIIZ * 33
                      LOCAL  myatom AS STRING
                      LOCAL  hmutex AS DWORD
                     myatom = "m56ertmHJK-#[email protected]#"
                  
                     LOCAL Numutex AS LONG
                     Numutex = 1553902
                     atmtxt =  myatom + STR$(Numutex)
                     hMutex = CreateMutex (BYVAL %Null, 0 ,atmtxt)
                     IF hMutex AND (GetLastError = %ERROR_ALREADY_EXISTS) THEN
                    '   an instance of the program already running
                       ' we must exit this program
                       FUNCTION = -1
                     ELSE
                       FUNCTION = 0
                     END IF
                  
                  END FUNCTION
                  
                  
                  
                  
                  
                  FUNCTION WINMAIN (BYVAL hInst AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS LONG
                     'arguments to WinMain are provided by Windows - not defined by the programmer
                     'hInst             current instance of the application
                     'hPrevInstance    previous instance (not used - returns %Null in Win32)
                     'lpCmdLine        pointer to command line (whatever the user types in after MyApp.EXE). A null terminated string.
                     'iCmdShow         used the first time ShowWindow is called to display the application main window
                     LOCAL Msg         AS tagMsg
                     LOCAL W           AS WndClassEx
                     LOCAL szAppName  AS ASCIIZ * 80
                     LOCAL hWndButton AS DWORD
                     LOCAL hAccel     AS DWORD
                     LOCAL WndStyle   AS LONG
                     LOCAL WndStyleX  AS LONG
                     LOCAL hWnd,hInstance AS DWORD
                  
                     'register window class
                     szAppName = "SDK"
                     W.cbSize        = SIZEOF(W)
                     W.Style         = %CS_HREDRAW OR %CS_VREDRAW   '%WS_OverlappedWindow Or %WS_HScroll Or %WS_VScroll  '
                     W.lpfnWndProc   = CODEPTR(WndProc)
                     W.cbClsExtra    = 0
                     W.cbWndExtra    = 0
                     W.hInstance     = hInst
                     W.hIcon         = %null 'LoadIcon(hInst, "logo")
                     W.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                     W.hbrBackground = %Color_BtnFace+1
                     W.lpszMenuName  = %NULL
                     W.lpszClassName = VARPTR(szAppName)
                     W.hIconSm       = LoadIcon(hInst, BYVAL %IDI_APPLICATION)   'why not %NULL
                     RegisterClassEx W
                  
                     'create window of that class
                     WndStyle  = %WS_OVERLAPPEDWINDOW
                     WndStyleX = %WS_EX_LEFT
                     hWndMain  = CreateWindowEX( _
                        WndStyleX,  _    'dwStyle        extended style of window
                        szAppName,  _    'lpClassName    pointer to a null-terminated string (any registered name, including predefined system class names).
                        "Child dialog",      _    'lpWindowName   pointer to a null-terminated String (placed in title bar, text of the control, icon name or #identifier)
                        WndStyle,   _    'dwStyle        style of window
                        500,        _    'x              initial horizontal position (upper left screen, except for child is relative to parent window's client area)
                        200,        _    'y              initial vertical position  (upper left screen, except for child is relative to parent window's client area)
                        300,        _    'nWidth         width in device units
                        300,        _    'nHeight        height in device units
                        %Null,      _    'hWndParent     handle to parent window (optional for a pop-up window)
                        %Null,      _    'hMenu          handle to a menu
                        hInst,      _    'handle to instance of the module to be associated with the window
                        BYVAL %Null _    'pointer to CREATESTRUCT structure pointed to by the lParam param of the WM_CREATE message.
                        )
                  
                     'create window of existing class "Button"
                     WndStyle  = %WS_TABSTOP OR %WS_VISIBLE OR %WS_CHILD OR %BS_DEFPUSHBUTTON
                     hInstance = GetWindowLong(hWndMain, %GWL_HINSTANCE)
                      hWnd= CreateWindow( "Button", "Send to Parent",  WndStyle, 10, 10, 110, 25, hWndMain, %IDC_Button , hInstance, BYVAL %Null )
                      hWnd= CreateWindow( "Button", "Get Parent size", WndStyle, 10, 60, 160, 25, hWndMain, %IDC_Button1, hInstance, BYVAL %Null )
                  
                  
                     ShowWindow hWndMain, iCmdShow   'controls how window is to be shown. 1st must use iCmdShow
                     UpdateWindow hWndMain           'sends the window it's first WM_Create to display the window on the screen
                  
                     'message pump - calls WndProc whenever an application-specific message is received
                     'WndProc can process the message, or pass it on to a the default window procedure that is built into Windows.
                     WHILE GetMessage(Msg, %NULL, 0, 0) > 0
                        IF ISFALSE TranslateAccelerator (hWndMain, hAccel, Msg) THEN
                           IF ISFALSE ISDialogMessage (hWndMain, Msg) THEN
                              TranslateMessage Msg
                              DispatchMessage  Msg
                           END IF
                        END IF
                     WEND
                  END FUNCTION
                  
                  FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
                     LOCAL hDC AS DWORD, pPaint AS PAINTSTRUCT, tRect  AS RECT
                     LOCAL pnmhdr AS NMHDR PTR
                     LOCAL oldProc AS DWORD
                     LOCAL lblTEXT AS ASCIIZ * 20
                     LOCAL DialogID AS LONG
                  
                  
                     SELECT CASE wMsg
                  
                         CASE %WM_CREATE
                             ' Subclass
                   '           DialogID = getdlgctrlid ( ghWndInst )
                   '           oldProc = SetWindowLong( DialogID, %GWL_WNDPROC, CODEPTR(SubClassProc))
                             goldProc = SetWindowLong( ghWndInst, %GWL_WNDPROC, CODEPTR(SubClassProc))   ' SubClass Dialog1 ??
                  
                             'SetTimer hWnd, 1001, 500, 0
                             'SendMessage hwnd,%WM_TIMER, 1001, 0
                  
                         CASE %WM_DESTROY
                   '        SetWindowLong DialogID, %GWL_WNDPROC, oldProc
                          '  ReleaseMutex(hMutex)
                            SetWindowLong ghWndInst, %GWL_WNDPROC, goldProc
                            PostQuitMessage 0
                            EXIT FUNCTION
                  
                  
                         CASE %WM_COMMAND
                             'control notifications
                  
                               SELECT CASE LO(WORD,wParam)
                  
                                  CASE %IDC_Button
                                     SELECT CASE HI(WORD,wParam)
                                        CASE %BN_CLICKED
                                           lblTEXT = "From child " & TIME$  ' Send message to Parent
                                           setWindowText( ghWndInst, lblTEXT )
                                        END SELECT
                  
                                  CASE %IDC_Button1
                                      ' Get size from Parent
                                     SELECT CASE HI(WORD,wParam)
                                        CASE %BN_CLICKED
                                            GetClientRect ghWndInst, tRect ' get size from parent client
                                            lblTEXT= STR$(trect.left) & "|" & STR$(trect.top) & "|" & _
                                            STR$(trect.right-trect.left) & "|" & STR$(trect.bottom-trect.top)
                                            setWindowText( ghWndInst, lblTEXT )
                                      END SELECT
                               END SELECT
                  
                         CASE %WM_SIZE
                              'after its size has changed on local dialog
                             ' lblTEXT= "local size "& STR$(Lo(WORD,lParam)) & "|" & STR$(Hi(WORD,lParam))   'STR$(wParam)
                              lblTEXT= "WinDisp-dll"
                              setWindowText( hWnd, lblTEXT )
                  
                         CASE %WM_ERASEBKGND
                            hDC = wParam
                            DrawGradient hDC
                            FUNCTION = 1
                            EXIT FUNCTION
                  
                         CASE %WM_PAINT
                           'set when request is made to paint a portion of an application's window.
                            hDC = BeginPaint(hWnd, pPaint)
                            GetClientRect hWnd, tRect
                            SetBkMode hDC, %TRANSPARENT
                            SetTextColor hDC,%RGB_BLUE '%WHITE
                            DrawText hDC, "Child", -1, tRect, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
                            EndPaint hWnd, pPaint
                            FUNCTION = 1
                            EXIT FUNCTION
                  
                      CASE %WM_TIMER
                       ' SELECT CASE WPARAM
                       '   CASE 1001
                              lblTEXT= "Timer " & TIME$   & STR$(LO(WORD,lParam)) & "|" & STR$(HI(WORD,lParam))   'STR$(wParam)
                              setWindowText( hWnd, lblTEXT )
                          '  IF ghWndInst > 0 THEN
                            '   GetClientRect ghWndInst, tRect
                               'SendMessage(hWnd, %WM_SIZE, wparam, lParam)
                             '   movewindow( hwnd, trect.left, trect.top, trect.right-trect.left, trect.bottom-trect.top, -1 )
                  
                           ' end if
                       '   end select
                  
                     END SELECT
                     FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)   'if not handled above, pass to Windows default message handler.
                  END FUNCTION
                  
                  
                  '======================== SUBCLASS ============================================
                  FUNCTION SubClassProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _
                                        BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
                    LOCAL lRes, oldProc AS DWORD
                    LOCAL lblTEXT AS ASCIIZ * 20
                  
                    SELECT CASE AS LONG wMsg
                  
                      CASE %WM_COMMAND
                   '       SELECT CASE LO(WORD,wParam)
                  
                                lblTEXT= TIME$ + STR$(wParam)
                                setWindowText( hWnd, lblTEXT )
                                FUNCTION = 0 : EXIT FUNCTION
                         ' end select
                  
                     CASE %WM_SIZE   'after its size has changed.
                           lblTEXT= "SIZE of PARENT " 'STR$(wParam)
                           setWindowText( hWnd, lblTEXT )
                  
                    END SELECT
                  
                    FUNCTION = CallWindowProc(goldProc, hWnd, wMsg, wParam, lParam)
                  END FUNCTION
                  '------------------------------------------------------------------
                  
                  SUB DrawGradient (BYVAL hDC AS DWORD)
                     LOCAL rectFill AS RECT, rectClient AS RECT, fStep AS SINGLE, hBrush AS DWORD, lOnBand AS LONG
                     GetClientRect WindowFromDC(hDC), rectClient
                    ' fStep = rectClient.nbottom / 200
                    ' the more steps the finer is the color gradient
                     fStep = rectClient.nbottom / 156
                     FOR lOnBand = 0 TO 155
                        SetRect rectFill, 0, lOnBand * fStep, rectClient.nright + 1, (lOnBand + 1) * fStep
                       ' creates a yellowish greenish background
                        hBrush = CreateSolidBrush(RGB(221, 250, 180 - lOnBand))
                        Fillrect hDC, rectFill, hBrush
                        DeleteObject hBrush
                     NEXT
                  END SUB

                  Comment


                  • #10
                    so that when the main program can call or load only one instance of each DLL at any one time.
                    Windows will control any physical loading to your address space. If the DLL is already present it returns a handle. If not, Windows will load it and return a handle. Either way, you get a handle. The libray itself is loaded in Windows' space and all that ever goes in your user space is a handle.

                    As per above, this is not really what you are talking about but you need to know this.

                    Even if you have multiple programs loading the library the library itself will be only be resident once and each process gets its own handle.

                    Pray what are you trying to do? This description:
                    I'm trying to ensure that the same dll is not called more than once as it is sometimes in certain situations we need to be able to control as we do
                    engineering computations programming
                    ... really does not make sense, as DLLs are not called... procedures are called. Are you worried about data integrity? Possible re-entrancy? You should not be worried about either.
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      WTF? Calling a WInMain function in a DLL function? Read Help on WInMain!!!
                      "The WINMAIN function is called by Windows when an executable application first loads and begins to run."

                      That whole heap of garbage indicates that you may be able to copy and paste, but have no idea what you are doing.
                      There is no point in trying to help you further.

                      Comment


                      • #12
                        > so I check for the existence of a loaded DLL using FindWindow

                        The correct way to check if a library is already loaded in the address space is to use GetModuleHandle or GetModuleHandleEx API functions.

                        GetModuleHandleA function (libloaderapi.h) - Win32 apps | Microsoft Docs
                        Forum: http://www.jose.it-berater.org/smfforum/index.php

                        Comment


                        • #13
                          Note that the original program calling Winmain comes from
                          https://forum.powerbasic.com/forum/u...170#post766170
                          and that it is working well

                          Comment


                          • #14
                            Thank you Jose

                            Comment


                            • #15
                              Note that the original program calling Winmain comes from
                              https://forum.powerbasic.com/forum/u...170#post766170
                              In that linked post, the WINMAIN function is a user-written (and named) function in a code module specified as compile DLL.

                              'WINMAIN' here is, in my opinion, the worst possible name for a user-written function in the history of functions. All it can do is confuse PB users. (I'd say it worked pretty well!)

                              Regardless, I really suggest you brush up on "entry point functions" when compiling for either EXE or DLL.


                              Michael Mattias
                              Tal Systems (retired)
                              Port Washington WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                Thank you Michael, I have renamed the WinMain() to DLLMain() and now it works well too

                                Comment


                                • #17
                                  Originally posted by tim lakinir View Post
                                  thank you michael, i have renamed the winmain() to dllmain() and now it works well too
                                  Aaaaaaahhhhhhhhhhhh!

                                  Comment


                                  • #18
                                    Hi Tim,

                                    Naming an entry point into either an executable file OR a DLL is a matter of convention. For an executable file, the normal PBMAIN is where the executable code begins. You hunt up the instance handle with an API if you need it and then write your UI code after that. A DLL is a different animal, it requires a specific format that is defined by the operating system and in the case of PowerBASIC, its a PB specific wrapper to ensure that PB is supported properly. A DLLMAIN style of entry point is more powerful than the simpler version in that it allows you to control a number of factors in the DLL.

                                    A DLL is more complicated than an executable as it can be loaded at different addresses in a calling applications address space.
                                    hutch at movsd dot com
                                    The MASM Forum - SLL Modules and PB Libraries

                                    http://www.masm32.com/board/index.php?board=69.0

                                    Comment


                                    • #19
                                      You hunt up the instance handle with an API if you need it and then write your UI code after that.
                                      Or use WINMAIN and get the instance handle without hunting.

                                      I have renamed the WinMain() to DLLMain() and now it works well too
                                      DO NOT RENAME IT TO DLLMAIN, your DLL already has LIBMAIN.

                                      Exe files get one main; either PBMain or WinMain.
                                      DLLs files get one main; PBLibMain, LibMain or DLLMain.
                                      Help describes the differences, but you're just copying and pasting in-the-blind aren't you?
                                      Dale

                                      Comment


                                      • #20
                                        Thank you Dale and Steve,

                                        Comment

                                        Working...
                                        X