Announcement

Collapse

New Sub-Forum

In an effort to help make sure there are appropriate categories for topics of discussion that are happening, there is now a sub-forum for databases and database programming under Special Interest groups. Please direct questions, etc., about this topic to that sub-forum moving forward. Thank you.
See more
See less

Loading and using a Resource within a DLL

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

  • Loading and using a Resource within a DLL

    I read some older posts about this but they were many years old and prior to RESOURCE$() so here goes...

    I don't have any control of a particular EXE but I do have control of a DLL that contains functions called by code within the EXE. When one of the functions in the DLL is called, I want it to be able to use a particular resource that I have compiled into the DLL, but I am not having any success. I have tested the code compiled in a sample EXE and it works, so I am at a loss at this point. Any advice would be most appreciated.

    Here is the sample EXE code I used to test my loading and retrieving of the resource. It yields the correct length when displayed by MSGBOX():
    Code:
    #COMPILE EXE
    #RESOURCE RCDATA, 937 , "My.BMP"
    ' ---------------------------------
    FUNCTION PBMAIN () AS LONG
    
        LOCAL ResourceString AS STRING
        ResourceString = RESOURCE$( RCDATA, 937 )
        MSGBOX "Length: " + TRIM$(LEN(ResourceString))
    
    END FUNCTION
    ' ---------------------------------
    Here is the same code in my DLL code that yields 0 for the length displayed by MSGBOX() when MyProc is called by some calling code in an EXE
    Code:
    $COMPILE DLL
    
    #RESOURCE RCDATA, 937 , "My.BMP"
    DECLARE SUB MyProc LIB "My.dll"  ALIAS "MyProc" ( ) 
    ' --------------------------------
    SUB MyProc EXPORT
    
    LOCAL ResourceString AS STRING
    ResourceString = RESOURCE$( RCDATA, 937 )
    MSGBOX "Length: " + TRIM$(LEN(ResourceString))
    
    END SUB
    ' --------------------------------

    Sample EXE for the above DLL would be:
    Code:
    #COMPILE EXE
    DECLARE SUB MyProc LIB "My.dll" ALIAS "MyProc" ( )
    ' --------------------------------
    FUNCTION PBMAIN () AS LONG
    
    MyProc()
    
    END FUNCTION
    ' --------------------------------

  • #2
    create the string in EXE and pass to SUB in DLL. In DLL string is populated from resource, and STRPTR is put at location passed (the byref which is the VARPTR for the string) ((the zero length in DLL might be fixed with # and two DQs))

    Code:
     
    $COMPILE DLL #RESOURCE RCDATA, 937 , "My.BMP" ' -------------------------------- SUB MyProc ALIAS "MyProc" (BYREF ResourceString AS STRING) EXPORT 'can skip DECLARE in 'DLL with alias here ResourceString = RESOURCE$( RCDATA, 937 ) 'ResourceString = RESOURCE$ (RCDATA, "#937") 'Try this before other changes I made. MSGBOX "Length: " + TRIM$(LEN(ResourceString)) END SUB ' --------------------------------
    Code:
     
    #COMPILE EXE DECLARE SUB MyProc LIB "My.dll" ALIAS "MyProc" (BYREF A_Str AS STRING) ' -------------------------------- FUNCTION PBMAIN () AS LONG LOCAL MyStr AS STRING MyProc(MyStr) END FUNCTION ' --------------------------------
    Dale

    Comment


    • #3
      >'ResourceString = RESOURCE$ (RCDATA, "#937") 'Try this before other changes I made.

      I tried that, but it didn't make any difference, I get 0 as well.

      Comment


      • #4
        This doesn't work either. IIt returns the correct length for the STRING resource, but not for the RCDATA


        $COMPILE DLL "My.DLL"
        #RESOURCE STRING, 112, "YourWideText"$$
        #RESOURCE RCDATA, 937 , "My.BMP"
        DECLARE SUB MyProc LIB "My.dll" ALIAS "MyProc" ( )
        ' --------------------------------
        SUB MyProc EXPORT

        LOCAL ResourceString AS STRING

        ResourceString = RESOURCE$(STRING,112)
        MSGBOX "Length: " + TRIM$(LEN(ResourceString))
        ResourceString = RESOURCE$( RCDATA,937 )
        MSGBOX "Length: " + TRIM$(LEN(ResourceString))
        END SUB
        ' --------------------------------

        Comment


        • #5
          Apparently a known problem:

          https://forum.powerbasic.com/forum/u...ource-question

          Specifically post #9 in that thread:
          Wasn't explicitly stated, but I think what people are saying is many (possibly all but RCData) resources work fine from a DLL. RCData does not using Resource$.
          ...
          Short summary (I think)
          • All #Resource statements are stored in a DLL.
          • RcData resources are not retrievable using Resource$, api code I posted is apparently close to what PB does, just with a module reference.
          • Several other PB methods of retrieving resources work fine from a dll.

          Comment


          • #6
            Thought the topic rang a bell See here too
            Rgds, Dave

            Comment


            • #7
              West coast here so just logging in. Thanks guys! Extra points to Dave for linking to Stuart's post, haha! I'll follow up with my final code once I get it working. So far I am getting the wrong length for the resource itself, but obviously I am way closer. I guess I need to study those code examples closer.

              Comment


              • #8
                Back again with good news! Thank you both for your help with this. Dale, as an FYI, I stated in my original post that I don't have any access to the routines in the EXE, so unfortunately your suggestion won't help me. I did learn that, at least for the RcData, I can fully control of every aspect of storing a resource in a DLL and also making use of it from within the same DLL. I also discovered along the way, that I can make use of a resource that resides in a different DLL, which I thought was very cool, and I have documented how to do that below.

                Here is the working code for the EXE, same as in my prior post above:
                Code:
                #COMPILE EXE
                DECLARE SUB MyProc LIB "My.DLL" ALIAS "MyProc" ( )
                ' --------------------------------
                FUNCTION PBMAIN () AS LONG
                    MyProc()
                END FUNCTION
                ' --------------------------------

                Here is the working code for the DLL. Biggest changes from how it works in an EXE are:
                1. using a character label for the resource versus numeric
                2. getting the instance handle from LIBMAIN()
                3. calling a number of other functions to get the address of the resource instead of using RESOURCE$()
                Note: no error checking here.
                Code:
                $COMPILE DLL
                $INCLUDE "WIN32API.INC"
                #RESOURCE RCDATA, myg , "My.BMP"
                DECLARE SUB MyProc LIB "My.DLL" ALIAS "MyProc" ( )
                
                GLOBAL hInst AS DWORD
                
                ' --------------------------------
                
                FUNCTION LIBMAIN( BYVAL hInstance AS LONG, _
                                  BYVAL fwdReason AS LONG, _
                                  BYVAL lpvReserved AS LONG) AS LONG
                
                    IF fwdReason = %DLL_PROCESS_ATTACH THEN
                        hInst = hInstance
                    END IF
                
                    FUNCTION = 1 ' everyone is happy
                
                END FUNCTION
                
                ' --------------------------------
                
                SUB MyProc() EXPORT
                
                    LOCAL ResourceString AS STRING
                    ResourceString = RESOURCE$( RCDATA, "myg" )
                    MSGBOX "Length: " + TRIM$(LEN(ResourceString)) ' This does not work
                                                                   ' Replace with code below
                
                    LOCAL hModule    AS DWORD
                    LOCAL hFind      AS DWORD
                    LOCAL ResHandle  AS DWORD
                    LOCAL ResSize    AS DWORD
                    LOCAL DataAddr   AS DWORD
                    LOCAL MyString   AS STRING
                
                    hModule   = hInst ' = LoadLibrary("Your.DLL") if resource is located in a different DLL from this one
                    hFind     = FindResource(hModule,"myg", BYVAL %RT_RCDATA)
                    ResSize   = SizeOfResource(hModule,hFind)
                    ResHandle = LoadResource(hModule, hFind)
                    DataAddr  = LockResource(ResHandle)
                    MyString  = PEEK$(DataAddr, ResSize)
                
                    MSGBOX "Inst: "      + TRIM$(hInst)
                    MSGBOX "hModule: "   + TRIM$(hModule)
                    MSGBOX "hFind: "     + TRIM$(hFind)
                    MSGBOX "ResSize: "   + TRIM$(ResSize)
                    MSGBOX "ResHandle: " + TRIM$(ResHandle)
                    MSGBOX "DataAddr: "  + TRIM$(DataAddr)
                    MSGBOX "Length: "    + TRIM$(LEN(MyString))
                
                END SUB
                ' --------------------------------
                Note that prior to the end of MyProc(), I wrote MyString to disk and compared it bit by bit with the original file and they are identical. Yippee!
                I did read that SizeOfResource() may not be entirely accurate but so far it has worked for me. I'll skin that cat at some other time.

                Comment

                Working...
                X