Announcement

Collapse

Maintenance

The forum could be offline for 30-60 minutes in the very near future for maintenance (said 3pm Pacific). I was behind on getting this notice. I do apologize.
See more
See less

Extarcting resource for in memory program

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

  • Extarcting resource for in memory program

    Hi all
    Any Idea if it's possible to extract a resource of a running program (not from the exe file)

    TIA


  • #2
    Hi Gafny,

    I'm not sure exactly what you are asking, but more importantly, I have to ask why you would want to do this?

    Embedded resources are stored in the disk image because Windows has the ability to load and free them as required. Just because an EXE has a resource file embedded does not mean that all of the items are loaded into memory. Just like DLL's permit truely dynamic loading, resources work in the same fashion. When an app is loaded in memory, Windows locks it's disk file for this purpose, so it cant execute without a disk file present.

    Further, lets consider a specific case: Lets say we have an EXE with a String Table embedded into the resource file. It is not very unlikely that the actual app will load the complete string table into memory - it may just load one or two strings, or none at all, etc. It is also possible that the app may load the string table and store the strings in "random order", so the effect is that the string table items could be scattered across memory. Finally, in the resource file, strings are actually stored in Unicode - when PB loaded string's Windows translates them to Ansi.

    In this case, it is:
    a) Virtually impossible to access memory of a non-owned process anyway
    b) Virtually impossible to identify the location of the resource or portion of the resource when it is loaded into memory anyway - there is no "address table" for this type of data - the app itself will keep track of the resource usually by a handle rather than a pointer.
    c) The memory image of the resource could be in a different format, as compared to the disk image.
    d) there are probably more issues...

    Using LoadLibrary() to load the EXE or DLL and extract the resource(s) from this file is the best all round solution.



    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    Lance
    mailto:[email protected]

    Comment


    • #3
      Hi Lance

      First, thank for your answer.

      The situation I ran to is like this.

      I have a main program which SHELL very often three smaller
      programs. All the programs are relatively small
      (100 to 250 kb) but they all have big resources.

      The program is installed on a slow network. I don't care
      How much time it'll take to load the main program, but I need
      fast load of the smaller program.

      So i thought to embed all the resources in the main program
      and once the main program is in memory, to extract
      the resource and save the load time.

      If you have a better (and working) solution or idea, I'll
      be glad to know

      Thanks

      Gafny Jacob



      ------------------

      Comment


      • #4
        Jacob,
        How about this??
        Put your resources in the main program.
        When you shell put the instance handle in the command line:
        SHELL "MySmall.exe " + FORMAT$(ghInst).
        You can then use the instance handle to load your resources from the main
        program.

        James


        ------------------

        Comment


        • #5
          Or you could put the resources in a DLL. If the DLL contained only the shared resources and a single function that would return the DLL instance, any EXE could use the resources. And only one copy of the DLL would be loaded into memory on any given machine.

          -- Eric

          ------------------
          Perfect Sync: Perfect Sync Development Tools
          Email: mailto:[email protected][email protected]</A>

          "Not my circus, not my monkeys."

          Comment


          • #6
            Hi Jcfuller

            The problem is not getting the running program Instance
            but as Lance pointed out, It's not possible to extract resource
            from another process.

            Hi Eric.

            Yesterday morning, I implemented the Dll Concept you mentioned
            But in the evening it came to my mind, What a big mistake.
            Why so?

            Assuming that the 3 small programs are 100 kb code + 300 kb resource
            (each program has different resources). Now, if each program
            embedded its own resource, every time you shall a program
            you have to load from disk 400 Kb

            But when I embedded all resources to one dll, I ended up with
            three 100 kb program and one 900 kb Dll.

            Now, every time you shall to a small program, the program have
            To load 100 kb + 900 kb dll

            Well, The remaining option as I can see it right now is
            to use file mapping (The main program will map the resource
            to a file, and the small program will peek it from the memory file).

            Thanks for your answers

            Gafny Jacob



            ------------------

            Comment


            • #7
              > Now, every time you shall to a small program, the
              > program have To load 100 kb + 900 kb dll

              The first time one of the 100k programs is run, that is true. But when the second program runs it will load 100k, and Windows will link it to the 900k DLL that is already in memory. Remember, only one copy of a DLL is in memory at any given time.

              -- Eric

              ------------------
              Perfect Sync: Perfect Sync Development Tools
              Email: mailto:[email protected][email protected]</A>

              "Not my circus, not my monkeys."

              Comment


              • #8
                > Remember, only one copy of a DLL is in memory at any given Time.

                Are you sure about it Eric ?. I thought that each process load
                the dll to its own address space. Please let me know if I'm wrong

                Thank
                Jacob Gafny



                ------------------

                Comment


                • #9
                  I'm pretty sure, but resources do get tricky sometimes. Can somebody else confirm whether or not I'm right?




                  [This message has been edited by Eric Pearson (edited March 03, 2000).]
                  "Not my circus, not my monkeys."

                  Comment


                  • #10
                    Eric --
                    In Vb I already tested this moment (ActiveX Dll) and was sure that Jacob is right. But in any case decided to test "truely" dll.
                    Compile DLL
                    Code:
                    #Compile Dll "a.DLL"
                    #Register None
                    Global i As Long
                    Sub SetValue Alias "SetValue" (aa As Long) Export
                      i = aa
                    End Sub
                    Function GetValue Alias "GetValue" Export As Long
                      Function = i
                    End Function
                    and Exe
                    Code:
                    #Compile Exe
                    #Register None
                    #Dim All
                    #Include "WIN32API.INC"
                    
                    Declare Sub SetValue Lib "a.DLL" Alias "SetValue" (v As Long)
                    Declare Function GetValue Lib "a.Dll" Alias "GetValue" As Long
                    
                    CallBack Function DlgProc
                       Local a$
                       If CbMsg = %WM_COMMAND Then
                          If CbCtl = 101 Then
                             Control Get Text CbHndl, 103 To a$
                             SetValue Val(a$)
                          ElseIf CbCtl = 102 Then
                             SetWindowText CbHndl, Time$ + Str$(GetValue)
                          End If
                       End If
                    End Function
                    
                    Function PbMain As Long
                    Dim hDlg As Local Long
                    Dialog New 0, "Test Dll",,, 150, 45, %WS_SYSMENU Or %WS_CAPTION To hDlg
                    Control Add TextBox, hDlg, 103, "", 5, 5, 140, 12
                    Control Add Button, hDlg, 101, "Set", 5, 25, 50, 14
                    Control Add Button, hDlg, 102, "Get", 95, 25, 50, 14
                    Dialog Show Modal hDlg, Call DlgProc
                    End Function
                    Start two EXE. Place two boxes near each other.
                    And you will see that they work independent.

                    ------------------

                    Comment


                    • #11
                      Semen, your code successfully tests for process-isolation (which we know works fine), but does nothing to test the instance count of the DLL involved. GLOBAL variables in a DLL are "local" to the DLL and "local" to the process (and shared amoung the threads within that process) - another instance loaded into a 2nd process is not able to see the GLOBAL variables in another process.

                      Eric is correct in that there is only one instance of the DLL loaded into memory and it is mapped into the address space of the processes that use it.

                      {things get tricky here...}

                      However, I'm sure I've read that there are certain conditions that causes Windows to load additional copies of a DLL for separate processes - it has to do with a specific base-address of a DLL - if I understand this correctly, then if a DLL with a specific base address is loaded, and another DLL with the same base-address is loaded afterwards(and this DLL is already in memory for another process), then Windows is unable to perform the process mapping into the address space of the latest process requesting the DLL, so it loads and relocates another copy of the DLL.

                      Whew! I hope the preceding paragraph is correct... if anyone can identify an [MSDN] article on this issue then I'd appreciate it. Thanks!




                      ------------------
                      Lance
                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>
                      Lance
                      mailto:[email protected]

                      Comment


                      • #12
                        Lance --

                        So... Do PB/DLL DLL's have specific base addresses?

                        Either way, it seems like Windows would be smart enough to do a memory-copy if it needed another copy of a DLL, rather than loading it from disk again, but that doesn't address memory use.

                        Gafney --

                        How about doing a pragmatic test? With numbers like yours (100 and 900) it should be easy to run a program, check the Task Manager "memory use" statistics, run a second program, and check the stats again. If the numbers jump by 100 or 1,000 you have your basic answer.

                        -- Eric

                        ------------------
                        Perfect Sync: Perfect Sync Development Tools
                        Email: mailto:[email protected][email protected]</A>

                        "Not my circus, not my monkeys."

                        Comment


                        • #13
                          Lance & Eric --
                          In additional to my sample, pls, do following test.
                          Make two variants of Dll: first in my previous message - name it a1.bas and compile into a1.dll and the second variant
                          Code:
                          #Compile Dll "a2.DLL"
                          #Register None
                          Global i As Long
                          Sub SetValue Alias "SetValue" (aa As Long) Export
                            i = aa
                          End Sub
                          Function GetValue Alias "GetValue" Export As Long
                            Function = i * 2
                          End Function
                          Difference in GetValue (here - multiply 2).

                          Copy a1.dll to a.dll, start EXE, press Get/Set.
                          Without exiting from this EXE, delete a.dll and try to start EXE again.
                          Not starts. Rename a2.dll to a.dll. You will see that unlike first exe, works second variant of dll.

                          So, I am very doubt "that there is only one instance of the DLL loaded into memory and it is mapped into the address space of the processes that use it".
                          I mean PB/DLL only.
                          In VBn you can create "Private", "Multi-Use", "Global Multi-use" ActiveX DLL.
                          Perhaps, last works exactly like Eric described.
                          Could be also that classic DLL files have a special flag. Difficult to beleive that Windows download "user32.dll" each time from HDD.



                          [This message has been edited by Semen Matusovski (edited March 04, 2000).]

                          Comment


                          • #14
                            Semen --

                            I believe that your test code is attempting to "fool" Windows, and Windows is simply not being fooled.

                            The behavior that Lance and I are describing is a basic attribute of DLLs...

                            > Difficult to beleive that Windows download "user32.dll"
                            > each time from HDD.

                            Exactly! That's the way DLLs work. Under most circumstances, the "static" part (code/data/resources/etc.) is loaded into memory once, and each application that links to a DLL gets its own set of variables. That is why Windows maintains an "instance count" for DLLs. Each time an application links to a DLL the instance count is incremented, and each time an app unloads the count is decremented. When it reaches zero, Windows automatically unloads the DLL from memory.

                            I'll try to find some reference materials about this property of DLLs on MSDN and post the URLs tomorrow. The one I was thinking about has apparently been moved in just the last few days.

                            Also, I think it is a mistake to compare Visual Basic DLLs to "real" DLLs. It was recently explained to me that they are really "in process OLE servers" that do not really fit the original description of a DLL. But I guess since Microsoft defined DLLs to begin with, they are free to change the definition. I am referring to "basic" DLLs, according to the "traditional" meaning of the term.

                            -- Eric

                            ------------------
                            Perfect Sync: Perfect Sync Development Tools
                            Email: mailto:[email protected][email protected]</A>

                            "Not my circus, not my monkeys."

                            Comment


                            • #15
                              Hi Eric

                              all PBCC and PBDLLs have a base address of: 0x00400000 (I believe the lowest address range for exes and dlls). There are several rebase utilities around which you can use if you want to (unfortunately I don't have the URLs on hand).

                              Cheers

                              Florent



                              [This message has been edited by Florent Heyworth (edited March 04, 2000).]

                              Comment


                              • #16
                                Originally posted by Eric Pearson:
                                Lance --
                                So... Do PB/DLL DLL's have specific base addresses?
                                Bob Zale commented on this in the past after someone requested a way to explicitly specify the base address of a DLL (which some other compilers permit). His response to this was 'it's not worth doing' because there is no measurable benefit in terms of load time or performance - Just let Windows rebase the DLL at load time.

                                However, he made no reference to instancing issues - maybe I'm dreaming about this I'll have to see if I can find the article I read on instancing or maybe I just dreamed about such an article.

                                I think I'm going mad!


                                ------------------
                                Lance
                                PowerBASIC Support
                                mailto:[email protected][email protected]</A>
                                Lance
                                mailto:[email protected]

                                Comment


                                • #17
                                  Eric --
                                  Are you sure that DLLs, compiled in PB-DLL, have "classic" behavior ?

                                  I reconstructed Exe module (see bellow).
                                  When I lock for read-write "user32.dll" I can start another copy of this EXE. For me this is a signal that Windows takes this DLL from memory.
                                  But if to lock "a.dll" I can't start the second copy.
                                  How can you explain this difference ?

                                  If you know C, try to do the same test (EXE & DLL should be C-modules). I expect that you will be able to start the second copy of exe, even if a.dll will be busy.

                                  Code:
                                  #Compile Exe
                                  #Register None
                                  #Dim All
                                  #Include "WIN32API.INC"
                                  
                                  Declare Sub SetValue Lib "a.DLL" Alias "SetValue" (v As Long)
                                  Declare Function GetValue Lib "a.Dll" Alias "GetValue" As Long
                                  
                                  CallBack Function DlgProc
                                     Local a$, v As Long
                                     v = GetParent(CbHndl) ' To be sure that a.exe use User32.Dll
                                     If CbMsg = %WM_COMMAND Then
                                        If CbCtl = 101 Then
                                           Control Get Text CbHndl, 103 To a$
                                           SetValue Val(a$)
                                           Open "G:\Winnt\System32\User32.dll" For Binary Lock Read Write As #1
                                           MsgBox "User32 is Busy"
                                           Close #1
                                  
                                        ElseIf CbCtl = 102 Then
                                           SetWindowText CbHndl, Time$ + Str$(GetValue)
                                           Open "A.dll" For Binary Lock Read Write As #1
                                           MsgBox "A.Dll is Busy"
                                           Close #1
                                        End If
                                     End If
                                  End Function
                                  
                                  Function PbMain As Long
                                  Dim hDlg As Local Long
                                  Dialog New 0, "Test Dll",,, 150, 45, %WS_SYSMENU Or %WS_CAPTION To hDlg
                                  Control Add TextBox, hDlg, 103, "", 5, 5, 140, 12
                                  Control Add Button, hDlg, 101, "Set", 5, 25, 50, 14
                                  Control Add Button, hDlg, 102, "Get", 95, 25, 50, 14
                                  Dialog Show Modal hDlg, Call DlgProc
                                  End Function


                                  ------------------

                                  Comment


                                  • #18
                                    Semen, all you your code does is confirm that Windows examines the DLL on the disk as it goes about it job of dynamic linking - it certainly does not prove or disprove that the DLL is loaded into memory a second time.

                                    In fact, what actually happens is that Windows load one copy of "A.DLL" into memory AND it only loads one copy of the EXE into memory too! Now try to confirm too.

                                    I would hazzard a guess that this behavior (of failing if the DLL disk image was locked) could be to verify what the DLL is, and can it be loaded, etc... for example, you could be loading an identical DLL from another folder on the harddisk, and it has to determine if it is the same DLL as in memory - Microsoft can problem shed more light on the process involved.

                                    I suggest that you read the WIN32.HLP file under the section "About Dynamic-Link Libraries", and also Rector/Newcomers "Win32 Programming" which discusses EXE and DLL instancing.

                                    ------------------
                                    Lance
                                    PowerBASIC Support
                                    mailto:[email protected][email protected]</A>
                                    Lance
                                    mailto:[email protected]

                                    Comment


                                    • #19
                                      Lance --
                                      Yes, I read Chapter 16 (nice book, I should say).

                                      I try to prove that DLL, compiled in PB/DLL, is not "classic" DLL.

                                      About floppy - good thought. I changed to "a:\a.dll" and made following experiment: wrote first variant of a.dll on diskette 1 and second variant on diskette 2.
                                      Insterted diskette #1 and started Exe (from HDD).
                                      Changed diskettes and started again.
                                      Like I expected, work different realeases.

                                      Interesting, Windows doesn't not examine "User32.Dll" (you can even delete it from HDD and to start another EXE) and examines "a.dll". Where is a logic ?
                                      There are enough Microsoft bugs, but main parts are written by very good developers and difficult to imagine that Windows tries to open a DLL without necessary.
                                      Perhaps, somebody will do the same test with C' DLL (simply I don't know this language).
                                      And if it will be possible to delete C "a.dll" before next start it shows that PB-DLL are not "classic".

                                      [This message has been edited by Semen Matusovski (edited March 05, 2000).]

                                      Comment


                                      • #20
                                        Semen --

                                        > I try to prove that DLL, compiled in PB/DLL, is not "classic" DLL.

                                        Here are a couple of easy ways to prove to yourself that PB/DLL produces "normal", "classic" DLLs that behave in the standard (and beneficial) way that Lance and I are describing.

                                        Create this DLL using PB/DLL:

                                        Code:
                                        #COMPILE DLL "INSTANCE.DLL"
                                        #DIM ALL
                                        #REGISTER NONE
                                         
                                        FUNCTION LibMain(BYVAL hInstance AS LONG, _
                                                         BYVAL Reason AS LONG, _ 
                                                         BYVAL Reserved AS LONG) EXPORT AS LONG
                                         
                                            DIM ghInstance AS GLOBAL LONG
                                            ghInstance = hInstance
                                            FUNCTION = 1
                                         
                                        END FUNCTION
                                         
                                        FUNCTION DLLInstance ALIAS "DLLInstance" EXPORT AS LONG
                                            DIM ghInstance AS GLOBAL LONG
                                            FUNCTION = ghInstance
                                        END FUNCTION
                                        ...and this EXE...

                                        Code:
                                        #COMPILE EXE "TESTINST.EXE"
                                        #DIM ALL
                                        #REGISTER NONE
                                         
                                        DECLARE FUNCTION DLLInstance LIB "INSTANCE.DLL" ALIAS "DLLInstance" AS LONG
                                        
                                        FUNCTION PBMain AS LONG
                                            MSGBOX FORMAT$(DLLInstance)  'use PRINT and WAITKEY$ if using PB/CC.
                                        END FUNCTION
                                        ...and you will see that no matter how many instances of the EXE you run (all at the same time), Windows will always report exactly the same "instance handle" for the DLL. Remember, that number is being passed to your program by Windows, it is not being produced or calculated by PB/DLL. Since the instance handle can be used to access resources that are embedded in a DLL, the technique that I originally suggested to Gafney should work fine.

                                        Another technique...

                                        If you have access to a Windows 98 computer, you can use this program:

                                        Start / Programs / Accessories / System Tools / System Information

                                        ...to examine several useful things. Use the Software Environment / 32-bit Modules Loaded display, and you will see a list of all of the DLL and EXE modules that are currently in memory. Run your test program from above and use the View/Refresh menu option, and you will see that your EXE and DLL will have been added to the list. Switch to the Running Tasks display and you will see your app listed.

                                        Then, without closing the first one, start a second copy of the test app. Use View/Refresh and you'll see that a second copy will have been added to the Running Tasks list. But if you return to the 32-Bit Modules Loaded display, you will see that only one copy of the DLL and one copy of the EXE are currently loaded.

                                        (BTW, does anybody know how to obtain a similar display on an NT machine?)

                                        It is very important to note that just because only one copy of a DLL is in memory, and that it is being used by more than one EXE, that does NOT mean that anything "non-static" is actually shared between the applications, such as the values of variables. Each EXE, and each instance of each DLL, is automatically given its own set of variables by Windows. Applications cannot "see" each other just because they share a DLL. In fact, Windows explicitly, purposely prevents apps from "seeing" each other unless a number of complex steps are taken.

                                        -- Eric

                                        ------------------
                                        Perfect Sync: Perfect Sync Development Tools
                                        Email: mailto:[email protected][email protected]</A>

                                        "Not my circus, not my monkeys."

                                        Comment

                                        Working...
                                        X