Announcement

Collapse
No announcement yet.

can we use mutex for DLL files ?

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

  • Michael Mattias
    replied
    Naming an entry point into either an executable file OR a DLL is a matter of convention.
    Actually, it's a matter of your compiler. When a compiler writes the executable file header, it specifies the entry point (by offset from start of file).

    The PB compiler recognizes specific procedure ("function") names as the programmer's desired entry point for the module... eg PBMAIN or WINMAIN when compiling to an EXE or DLLMAIN or LIBMAIN when compiling to a DLL.


    A DLL is a different animal, it requires a specific format that is defined by the operating system
    Actually, the specifications for an EXE file's entry-point function are O/S defined as well. But the PB compiler makes that transparent when you use the abbreviated procedure header supported by the reserved name PBMAIN when compiling to an EXE. And the compiler makes it REALLY simple when compiling to a DLL, as it handles the format transparently even if the programmer does not explicitly specify an entry point function.

    While pretty much all you say is true when using POwerBASIC compilers, I'd caution you against expanding those statement as you have to state them as universal truths.

    (I have a great story about that, but I'll save that for another day.)

    Leave a comment:


  • Tim Lakinir
    replied
    Thank you Dale and Steve,

    Leave a comment:


  • Dale Yarker
    replied
    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?

    Leave a comment:


  • Steve Hutchesson
    replied
    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.

    Leave a comment:


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

    Leave a comment:


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

    Leave a comment:


  • Michael Mattias
    replied
    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.


    Leave a comment:


  • Tim Lakinir
    replied
    Thank you Jose

    Leave a comment:


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

    Leave a comment:


  • José Roca
    replied
    > 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

    Leave a comment:


  • Stuart McLachlan
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    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.

    Leave a comment:


  • Tim Lakinir
    replied
    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

    Leave a comment:


  • Dale Yarker
    replied
    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

    Leave a comment:


  • Stuart McLachlan
    replied
    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..

    Leave a comment:


  • Tim Lakinir
    replied
    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 ?

    Leave a comment:


  • Stuart McLachlan
    replied
    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.

    Leave a comment:


  • Tim Lakinir
    replied
    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

    Leave a comment:


  • Tim Lakinir
    replied
    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

    Leave a comment:


  • Stuart McLachlan
    replied
    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?

    Leave a comment:

Working...
X