Announcement

Collapse
No announcement yet.

Question on Global variables in a DLL

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

  • Mike Doty
    replied
    Read, write arrays to disk or call DLLLoadGlobal to load string array into gs() in the DLL
    Array can be local, threaded or global.
    Code:
    #DIM ALL      'ReadWriteArray.bas
    '%MakeEXE = 1 'remark to create DLL then unremark to test
    
    #IF %DEF(%MakeEXE)
     #COMPILE EXE
     DECLARE FUNCTION WriteArray    LIB "MyDLL.DLL" (sFileName AS STRING,temparr() AS STRING,ecode AS LONG) AS LONG
     DECLARE SUB      DllLoadGlobal LIB "MyDLL.DLL" (sFileName AS STRING)
     DECLARE FUNCTION ReadArray     LIB "MyDLL.DLL" (sFileName AS STRING,temparr() AS STRING,ecode AS LONG) AS LONG
    
     FUNCTION PBMAIN AS LONG
      LOCAL ecode AS LONG
      REDIM s(1) AS STRING
      s(0) =        "Saved to disk and"
      s(1) =        "loaded into DLL global array"
      WriteArray    "temp.txt",s(),ecode&
      DllLoadGlobal "temp.txt"  'calls ReadArray and fills gs() array in DLL
     END FUNCTION
    '====================================================================================================================
    
    #ELSE 'DLL
     #COMPILE DLL "MyDll.Dll"
     GLOBAL gs() AS STRING
    
     FUNCTION WriteArray(sFileName AS STRING,temparr() AS STRING,ecode AS LONG) EXPORT AS LONG
      LOCAL hFile AS LONG
      hfile = FREEFILE
      OPEN sFileName FOR OUTPUT AS #hfile
      IF ERR THEN ecode = ERR:FUNCTION = ecode:BEEP:EXIT FUNCTION
      PRINT #hFile, temparr()
      IF ERR THEN ecode = ERR:BEEP:FUNCTION = ERR
      CLOSE #hfile
     END FUNCTION
    
     FUNCTION ReadArray(sFileName AS STRING,temparr() AS STRING,ecode AS LONG) EXPORT AS LONG
      LOCAL hFile    AS LONG
      LOCAL elements AS LONG
      ERASE temparr
      IF ISFILE(sFilename) THEN
       hfile = FREEFILE
       OPEN sFileName FOR INPUT AS #hfile
       IF ERR THEN ecode = ERR:FUNCTION = ecode:BEEP:EXIT FUNCTION
       FILESCAN #hfile, RECORDS TO elements
       IF elements < 1 THEN ECODE = -1:FUNCTION = ecode:BEEP:CLOSE #hfile:BEEP:EXIT FUNCTION
       REDIM temparr(1 TO elements)
       LINE INPUT #hfile, temparr() TO elements
       IF ERR THEN ecode = ERR:FUNCTION = ecode:BEEP
       CLOSE #hfile
      ELSE
       ecode = 53:FUNCTION = ecode
      END IF
     END FUNCTION
    
     SUB DllLoadGlobal(sFileName AS STRING) EXPORT
      LOCAL ecode AS LONG
      ReadArray sFileName,gs(),ecode
      ? JOIN$(gs(),$CRLF),,"DLL Load Global"
     END SUB
    #ENDIF

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Christopher Becker View Post
    Situation: Inside PBMAIN(), I've DIMed and populated a large LOCAL array. Now, I want to refer to elements of that array in SUBs and FUNCTIONs. Ideally (!), it would be great to pass a pointer to the array to SUBs and FUNCTIONs ...
    That's what BYREF does.
    '
    Code:
    #COMPILE EXE
    #DIM ALL
    FUNCTION PBMAIN() AS LONG
        LOCAL lDebug AS LONG: TXT.WINDOW EXE.FULL$, 10,10,45,85 TO lDebug
        DIM StrMyArray(10 TO 20) AS STRING
        StrMyArray(15) = "Fifteen"
        AccessStrArray(strMyArray())
        TXT.PRINT "Back from Function, strMyArray(20) = ", strMyArray(20)
    'Finalise
        TXT.COLOR = %RGB_BLUE
        TXT.PRINT
        TXT.PRINT "  ....Press any key to exit": TXT.WAITKEY$: TXT.END
    END FUNCTION
    
    FUNCTION AccessStrArray(BYREF strA() AS STRING) AS LONG
        TXT.PRINT "In Function - Lbound=", LBOUND(strA())
        TXT.PRINT "In Function - Ubound=", UBOUND(strA())
        TXT.PRINT "In Function  strMyArray(15) = ",strA(15)
        strA(20) = "Twenty"
    END FUNCTION
    '

    Click image for larger version  Name:	PassArray.jpg Views:	0 Size:	35.8 KB ID:	823522

    Leave a comment:


  • Michael Mattias
    replied
    Situation: Inside PBMAIN(), I've DIMed and populated a large LOCAL array. Now, I want to refer to elements of that array in SUBs and FUNCTIONs. Ideally (!), it would be great to pass a pointer to the array to SUBs and FUNCTIONs, just as if it were a very large string. Of course, if I pass enough information to the SUB, it's possible to re-create the array. But now we're working with a copy, and not the original. Using GLOBAL is the obvious answer; I was just looking for a pointer solution.
    You can do that... or you can just just pass a reference to the array or the the array and and a subscript.

    That is, instead of

    Code:
       CALL SupportingFunction  (array_element)  or "Pointer to array element" or "big block of data"
    .. you could simply ...
    Code:
       CALL SupportingFunction  (arrayName() , subscript)
    or
    Code:
       CALL SupportingFunction  (arrayName() )

    Cases two and three are in essence just passing a reference to the original LOCAL array.

    Isn't that cleaner if you want to work directly with the Array you created?

    Leave a comment:


  • Christopher Becker
    replied
    Mike, I appreciate the reply. I really do. That code will come in handy someday for sure.

    Background: My style of coding is to minimize the use of GLOBALs. In fact, I use them as a last resort.

    Situation: Inside PBMAIN(), I've DIMed and populated a large LOCAL array. Now, I want to refer to elements of that array in SUBs and FUNCTIONs. Ideally (!), it would be great to pass a pointer to the array to SUBs and FUNCTIONs, just as if it were a very large string. Of course, if I pass enough information to the SUB, it's possible to re-create the array. But now we're working with a copy, and not the original. Using GLOBAL is the obvious answer; I was just looking for a pointer solution.

    Yes, off-topic; apologies. It was the idea of visibility into an array from a function that reminded me of my previous problem.

    Leave a comment:


  • Mike Doty
    replied
    Christopher,

    What is wrong with this macro that works with multi-dimensional numeric and string data?
    It is also one-line.
    Kinda off subject of global array in a DLL.

    Code:
    MACRO CopyArray(A1, A2) = PARSE JOIN$ (a1,BINARY), a2, BINARY
    
    FUNCTION PBMAIN AS LONG
    
     'dimension numeric arrays
     REDIM x1(0,0,0) AS LONG
     REDIM x2(0,0,0) AS LONG
     x1(0,0,0) = 99
     CopyArray (x1(),x2())  'copy multi-dimensional numeric
    
     'dimension string arrays
     REDIM s1(0,0,0) AS STRING
     REDIM s2(0,0,0) AS STRING
     s1(0,0,0) = "99"
     CopyArray (s1(),s2())  'copy multi-dimensional string
    
     ? USING$("(#)(&)",x2(0,0,0),s2(0,0,0)) ' (99) (99)
    
    END FUNCTION



    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Christopher Becker View Post
    However, Borje's comment was quite useful: MAT b() = a().
    Aas long as you are working with a numeric array. MAT doesn't work with string arrays.


    Leave a comment:


  • Christopher Becker
    replied
    Mike, Stuart, Dale,
    I started this thread a couple of years ago...
    Suppose I have two arrays of the same size and same type. The Good Old Fashioned way to copy an array would be a FOR/NEXT loop, copying each element one-by-one. It works fine. But I'm using multi-dimensional arrays, and the result is a bunch of nested loops that are slow and ugly. I was disappointed to see that ARRAY COPY does


    Lots of suggestions and work-arounds, but I had hoped for one-line simplicity; e.g.: Array2 = @PointerToArray1

    However, Borje's comment was quite useful: MAT b() = a()

    Pointers are funny. First you hate 'em, then you get used to 'em. Enough time passes, you get so you depend on them. That's institutionalized. I'm an institutional man now. Just like Brooks was.

    Leave a comment:


  • Michael Mattias
    replied
    Follow-on question, what about pointers? Could a pointer inside the MAIN be passed to a DLL and the reference remain faithful?
    Since you do not pass anything to a DLL, I assume you mean a "Function which is loaded from a DLL."

    Has maybe been answered indirectly but:

    Yes. A pointer value obtained in any process is valid anywhere within that process; but only in that process. However, you may use it in another process using the ReadProcessMemory() WinAPI function, https://learn.microsoft.com/en-us/wi...dprocessmemory

    Also, an easy way to think about this "GLOBAL" thing is, the PB scope words LOCAL, STATIC, GLOBAL and THREADED* create variables with that scope only valid within the module being compiled. That is, those scope statements are used only at compile time.

    * automatically GLOBAL in scope

    Leave a comment:


  • Dale Yarker
    replied
    Mannish,

    Thank you. You may have gotten your answer early, but it still sparked a good discussion.

    Leave a comment:


  • Mike Doty
    replied
    > isn't that passing the contents of an array into an identical but totally separate array? Any changes in one will not "appear" in the other.
    Dale,
    True

    Post number 1
    In a DLL, is it true that its global variables are only valid while inside that DLL and not shareable to the Main prog which calls that DLL ?

    I would like to ensure that all the Global variables in a DLL can only work inside that DLL, and not seen by the Main calling prog.​

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Mike Doty View Post
    Pass array to a DLL function that copies array to a global array[code]
    Alternatively, see Variant Data Types


    Leave a comment:


  • Dale Yarker
    replied
    isn't that passing the contents of an array into an identical but totally separate array? Any changes in one will not "appear" in the other.

    Leave a comment:


  • Mike Doty
    replied
    PassArray JOIN$(sArray(), BINARY), LBOUND(sArray), UBOUND(sArray)

    Code:
    #COMPILE EXE
    DECLARE SUB PassArray LIB "MyDll.Dll"(s AS STRING,low AS LONG,high AS LONG)
    GLOBAL gs() AS STRING   'does not have to be global
    
    FUNCTION PBMAIN
     REDIM gs(1)
     ARRAY ASSIGN gs()="Cool","beans"
     PassArray JOIN$(gs(),BINARY),LBOUND(gs),UBOUND(gs)
    END FUNCTION
    Code:
    #COMPILE DLL
    GLOBAL gs() AS STRING
    DECLARE SUB PassArray LIB "MyDll.Dll"(s AS STRING,low AS LONG, high AS LONG)
    
    SUB PassArray (s AS STRING,low AS LONG,high AS LONG) EXPORT
     REDIM gs(low,high)  'redim to correct number of elements
     PARSE s,gs(),BINARY 'parse into global array
    END SUB

    Leave a comment:


  • Mike Doty
    replied
    A passed array can be copied into a global array and the original array can be shared with with PbMain.
    Next post passes an array from PbMain using join binary into a global array in a DLL function.

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Christopher Becker View Post
    E But if it works, and you needed global variables in a DLL, I suppose a work-around would be to make them available via pointers.
    or, as Bob wrote in Help:

    GLOBAL variables are not shared between programs and DLLs or between multiple instances of the same DLL. That is, a GLOBAL variable is only global within its own module. The simplest way to expose a variable to a DLL is to pass the variable (by reference) to the target DLL

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Christopher Becker View Post
    I still wish there was a way to refer to an array with a pointer in PB.
    WHat do you mean by "refer to an array" ?

    Have you read Help on "Pointers To Arrays"?
    Also Help on "Varptr" and "Passing Arrays"

    Leave a comment:


  • Dale Yarker
    replied
    See post 4.
    Will also work with GLOBAL in dot exe and pointer in DLL.
    Use a "helper" function in DLL to exchange pointer. (as in post 4)
    Will remain "faithful" (valid) unless DLL is unloaded. (re-exchange pointer if DLL reloaded)
    I still wish there was a way to refer to an array with a pointer in PB.
    How about pointer to first array element, pass pointer, then DIM AT in other module? ("Helper" function would also pass/receive LBOUND and UBOUND.)

    Cheers,

    Leave a comment:


  • Christopher Becker
    replied
    Eric, I'm not OP, but it's an interesting question and I hadn't ever considered the answer. Thanks for answering. Follow-on question, what about pointers? Could a pointer inside the MAIN be passed to a DLL and the reference remain faithful?

    I guess I could code it myself to test. But I'm lazy at the moment. But if it works, and you needed global variables in a DLL, I suppose a work-around would be to make them available via pointers. I still wish there was a way to refer to an array with a pointer in PB.

    Leave a comment:


  • Dale Yarker
    replied
    (Note the word "flashlight" used to avoid disturbing people in the US. I would normally have said torch" )​
    Can I make that:
    "(Note the word "flashlight" used to avoid disturbing certain people in the US. I would normally have said torch" ) ?

    ((and some how I suspect that won't happen again for a while [end ] ))​

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Mannish Bhandari View Post
    What is OP?
    Depending on context: "Original Post" or "Original Poster" i.e. normally post #1 in the thread but also maybe something subsequently posted by the original poster.

    Leave a comment:

Working...
X
😀
🥰
🤢
😎
😡
👍
👎