Announcement

Collapse
No announcement yet.

Process Memory Info

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

  • Process Memory Info

    I have a client for whom I developed an application which reads and reformats a data file.

    Pseudo-code:

    Load File Data to single dynamic string. File contains variable length delimited records.
    Parse file to find each record, store into an Array, resizing array as required
    Call a series of data-fixup routines something like
    Code:
        CALL Fixup1 (Array())
        CALL Fixup2 (Array())
        etc.
    Save modified array to fixed-record-length file.

    In the Fixup routines, Array() is never resized.

    When the files were the size originally specified, (10-30 Mb), no problem.

    But due to increased business, files are now in the 60-80 Mb range, and when this program runs customer says system performance is degraded. This is an NT Server running lots of jobs all day long.

    We "think" the performance hit is due to the large dynamic allocation of memory. Program obviously allocates (filesize) bytes to load the file data, plus approximately (filesize) bytes to hold the array into which the file is parsed. And while I recently changed to allocate an approximate number of elements for the array 'as soon as possible' (that is, when the file is first loaded), it is possible that at some point during the program run I need to do a REDIM PRESERVE ARRAY(currentsize + more space), which means for a brief moment the RAM requirement is (filesize) + (2 * ArraySize) ... with a 70 Mb input file, about 210 Mb!

    We "think" we want to try to reduce the dynamic allocation requirement by using disk instead of RAM, but before we make the investment in this change (not really that much, maybe a half day. Will change to use memory-mapped file object for input, and fixed-length random-access work file for fixup routines), we want to get some idea of the actual usage of RAM by the program.

    So....

    I found the PSAPI WinAPi functions, especially GetProcessMemoryInfo(), which looks like it returns the info we want.. or at least, as close as we're going to get on a 'live' system.

    GetProcessMemoryInfo returns this structure:

    Code:
    TYPE PROCESS_MEMORY_COUNTERS
       cb AS DWORD                           '// Size of the structure, in bytes.
       PageFaultCount AS DWORD               '// Number of page faults.
       PeakWorkingSetSize AS DWORD           '// Peak working set size.
       WorkingSetSize AS DWORD               '// Current working set size.
       QuotaPeakPagedPoolUsage AS DWORD      '// Peak paged pool usage.
       QuotaPagedPoolUsage AS DWORD          '// Current paged pool usage.
       QuotaPeakNonPagedPoolUsage AS DWORD   '// Peak nonpaged pool usage.
       QuotaNonPagedPoolUsage AS DWORD       '// Current nonpaged pool usage.
       PagefileUsage AS DWORD                '// Current space allocated for the pagefile.
                                             '// Those pages may or may not be in memory.
       PeakPagefileUsage AS DWORD            '// Peak space allocated for the pagefile.
    END TYPE
    I've been thru the SDK a couple of times, and still can't figure out which of these numbers - if any - are the numbers which tell us "yes, this change has / has not reduced the dynamic allocation requirements of this application."

    I have to believe those "peak" members are the key values, but I'm not sure.

    Can anyone point me to a good reference, or explain which numbers are important? I'm going to report <U>everything</U> just before end of job. I just don't know which of those numbers is meaningful.

    Thanks,


    ------------------
    Michael Mattias
    Tal Systems Inc.
    Racine WI USA
    mailto:[email protected][email protected]</A>
    www.talsystems.com
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

  • #2
    if i may ask a favor??
    since i use win/98, i was unable to test this on a machine where it should work..

    could people with win nt, win2k and win xp please test this on those o/s's please?

    if it works out, i think this will produce something useful for everyone...

    thanks,
    Code:
    ' file : process_memoryinfo.bas
    ' file to be #included in programs to get memory usage info about the program
    ' psapi header conversions courtesy: jose roca 11/2002 at
    ' [url="http://www.powerbasic.com/support/pbforums/showthread.php?t=24980"]http://www.powerbasic.com/support/pbforums/showthread.php?t=24980[/url] 
    ' the psapi functions are only supported on platform 5 machines. this code detects os and acts accordingly
    ' this file contains only the declares, udts and functions necessary to
    ' support the getprocessmemoryinfo function
    ' 1/11/04
    ' michael mattias racine wi
    ' tested ok on win/98 1/11/04 (not that that is a terribly useful test.)
    ' compiier: pb.win v 7.02
    ' win32api.inc   may 9 2002
    
    
    ' structure returned by getprocessmemoryinfo
    '  the "workingsetsize" members are the best indicator of a process' memory usage.
    
    type w_process_memory_counters
       cb                         as dword   '// size of the structure, in bytes.
       pagefaultcount             as dword   '// number of page faults.
       peakworkingsetsize         as dword   '// peak working set size.
       workingsetsize             as dword   '// current working set size.
       quotapeakpagedpoolusage    as dword   '// peak paged pool usage.
       quotapagedpoolusage        as dword   '// current paged pool usage.
       quotapeaknonpagedpoolusage as dword   '// peak nonpaged pool usage.
       quotanonpagedpoolusage     as dword   '// current nonpaged pool usage.
       pagefileusage              as dword   '// current space allocated for the pagefile.
                                             '// those pages may or may not be in memory.
       peakpagefileusage          as dword   '// peak space allocated for the pagefile.
    end type
    
    
    #if 0
    ' original declare
    declare function getprocessmemoryinfo lib "psapi.dll" alias "getprocessmemoryinfo" ( _
            byval hprocess as dword, _
            ppsmemcounters as process_memory_counters, _
            byval cb as dword _
    ) as long
    #endif
    
    ' declare for use with call dword
    declare function w_getprocessmemoryinfo _
          ( byval             hprocess as dword, _
            ppsmemcounters             as w_process_memory_counters, _
            byval             cb       as dword _
          ) as long
           
    
    #if not %def(%winapi)
      #include "win32api.inc"
    #endif
    
    $psapi_libname               =   "psapi.dll"
    $psapi_getprocessmemoryinfo  = "getprocessmemoryinfo"
    
    type formatwpmctype
        statistic       as string *  40
        value           as string *  16
        eol             as string *   2   ' end of line
    end type
    
    
    function formatted_wpmc (wpmc as w_process_memory_counters) as string
        local w as string, mask as string, fw as formatwpmctype
        
        mask   = "* #,"      ' format for integers
        w      = "
        
        fw.eol               =  $cr & $lf           ' or $crlf if sufficient compiler version
        
        lset fw.statistic    = "page fault count"
        rset fw.value        =  format$(wpmc.pagefaultcount, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
        
        lset fw.statistic    =  "peak working set size"
        rset fw.value        =  format$(wpmc.peakworkingsetsize, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
        
        lset fw.statistic    =  "current working set size"
        rset fw.value        =  format$(wpmc.workingsetsize, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
        
        lset fw.statistic    =  "quota peak paged pool usage"
        rset fw.value        =  format$(wpmc.quotapeakpagedpoolusage, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
        
        lset fw.statistic    =  "current quota paged pool usage"
        rset fw.value        =  format$(wpmc.quotapagedpoolusage, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
        
        lset fw.statistic    =  "quota peak non-paged pool usage"
        rset fw.value        =  format$(wpmc.quotapeaknonpagedpoolusage, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
    
        lset fw.statistic    =  "current quota non-paged pool usage"
        rset fw.value        =  format$(wpmc.quotanonpagedpoolusage, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
        
        lset fw.statistic    =  "peak page file usage"
        rset fw.value        =  format$(wpmc.peakpagefileusage, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
    
        lset fw.statistic    =  "current page file usage"
        rset fw.value        =  format$(wpmc.pagefileusage, mask)
        w                    =  w & peek$(varptr(fw), sizeof(fw))
    
        function             =  rtrim$(w, any chr$(13,10))   'remove trailing crlf
        
    end function
    
    
    ' returns: true: s has crlf delimited process memory info, false s contains messages why it doesn't
    
    function getprocessmemorystatistics (s as string) as long
        
        local hprocess as dword,  lret as long, cb as long, isp5 as long
        local wpmc     as w_process_memory_counters
        local osv as osversioninfo
        local szlibname    as asciiz * %max_path, szprocname as asciiz * %max_path
        local hlib         as long,  dwaddr as dword
        
        function                  =  %false         ' don't set to true until we have the info
        s                         = "
        
        ' get the os version and decide if we are on a platform 5 machine
        osv.dwosversioninfosize   =  sizeof(osv)
        lret                      =  getversionex (osv)
        if istrue lret then
            isp5                  =  (osv.dwplatformid  = %ver_platform_win32_nt)
        else
            s = "can't get operating system version.. this is really bad!"
            exit function
        end if
        
        ' if this is a platform 5 machine..
        
        ' lie about os for test on win/98, should return unable to load library, it does.
        ' isp5     = %true
        
        if istrue  isp5 then
            ' get the address of the function in psapi.dll
            szlibname      = $psapi_libname
            szprocname     = $psapi_getprocessmemoryinfo
            
            hlib           = loadlibrary (szlibname)
            if istrue  hlib then
                dwaddr     =  getprocaddress (hlib, szprocname)
                if istrue dwaddr then
                    hprocess      = getcurrentprocess
                    cb            = sizeof(wpmc)
                    ' call the function
                    call dword dwaddr using w_getprocessmemoryinfo (hprocess, wpmc,cb) to lret
                    if istrue lret then     ' function succeeded, format the wpmc structure
                        s     = formatted_wpmc (wpmc)
                        function   = %true
                    else
                        s     = "getprocessmemoryinfofailed"
                    end if
                else
                    s         = "can't get address for " & szprocname
                end if
                freelibrary      hlib
            else
                s             = "can't load library " & szlibname
            end if
            
         else
                s             = "process memory information n/a on this operating system."
    
                #if 0
                ' for test of formatting only on win 9x..
                wpmc.pagefaultcount              = 1234567890
                wpmc.peakworkingsetsize          = 1234567891
                wpmc.workingsetsize              = 1234567892
                wpmc.quotapeakpagedpoolusage     = 1234567893
                wpmc.quotapagedpoolusage         = 1234567894
                wpmc.quotapeaknonpagedpoolusage  = 1234567895
                wpmc.quotanonpagedpoolusage      = 1234567896
                wpmc.peakpagefileusage           = 1234567897
                wpmc.pagefileusage               = 1234567898
                s             = formatted_wpmc (wpmc)
                #endif
         end if
         
                    
    end function
    
                    
    function pbmain () as long
        
      local s as string, l as long
      
      
      ' typically you would call this as the last action of winmain...
      l = getprocessmemorystatistics (s)
      
      msgbox s,,"process memory statistics"
        
        
    end function
    
        
    ' // end of file
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      Windows 2000 Server, Service Pack 4, 512 MB
      Code:
        
        ---------------------------
        Process Memory Statistics
        ---------------------------
        Page Fault Count                                     354
        Peak Working Set Size                          1,458,176
        Current Working Set Size                       1,458,176
        Quota Peak Paged Pool Usage                       14,988
        Current Quota Paged Pool Usage                    14,676
        Quota Peak Non-Paged Pool Usage                    2,544
        Current Quota Non-Paged Pool Usage                 1,668
        Peak Page File Usage                             380,928
        Current Page File Usage                          380,928
        ---------------------------
        OK
        ---------------------------
       
       
      Windows XP, Service Pack 1, 512 MB
       
        ---------------------------
        Process Memory Statistics
        ---------------------------
        Page Fault Count                                     331
        Peak Working Set Size                          1,359,872
        Current Working Set Size                       1,359,872
        Quota Peak Paged Pool Usage                       17,136
        Current Quota Paged Pool Usage                    16,924
        Quota Peak Non-Paged Pool Usage                    2,288
        Current Quota Non-Paged Pool Usage                 1,320
        Peak Page File Usage                             356,352
        Current Page File Usage                          356,352
        ---------------------------
        OK   
        ---------------------------
      ------------------


      [This message has been edited by John Revill (edited January 11, 2004).]

      Comment


      • #4
        Thank you... so it "appears" that I didn't do anything totally dopey...

        But now it becomes obvious from the statistics that I should have put in some memory allocation function to look at Peak v Current

        So what if we make the PbMain function look like this...
        Code:
        FUNCTION PBMAIN () AS LONG
            
          LOCAL s AS STRING, l AS LONG, Z() AS STRING * 1024
        
          ' allocate   50 mb of memory and get statistics..
            REDIM  Z(50 * 1024)
            L = GetProcessMemoryStatistics (s)
            MSGBOX S,,"Process Memory Statistics with Array Allocated"
        
          ' De-allocate the memory... 
            ERASE Z()
        
          ' ... and get 'end of job' statistics.   
          ' We should see 'peak' numbers much less than 'current' numbers
          ' (and somewhere approximately 50 Mb of difference)
        
            L = GetProcessMemoryStatistics (s)
          
           MSGBOX S,,"Process Memory Statistics at End of Job"
            
        END FUNCTION
        Thanks,
        MCM

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

        Comment


        • #5
          Code:
          (compiled with #debug error on, #register none)
          Modified PBmain code used
          
          
          W2K Workstation, SP4, 786mb
          ---------------------------
          Process Memory Statistics with Array Allocated
          ---------------------------
          Page Fault Count                                  13,170
          
          Peak Working Set Size                         54,005,760
          
          Current Working Set Size                      54,005,760
          
          Quota Peak Paged Pool Usage                       15,052
          
          Current Quota Paged Pool Usage                    14,740
          
          Quota Peak Non-Paged Pool Usage                    1,968
          
          Current Quota Non-Paged Pool Usage                 1,720
          
          Peak Page File Usage                          52,871,168
          
          Current Page File Usage                       52,871,168
          ---------------------------
          ---------------------------
          Process Memory Statistics at End of Job
          ---------------------------
          Page Fault Count                                  13,285
          
          Peak Working Set Size                         54,439,936
          
          Current Working Set Size                       1,970,176
          
          Quota Peak Paged Pool Usage                       15,852
          
          Current Quota Paged Pool Usage                    14,812
          
          Quota Peak Non-Paged Pool Usage                    1,968
          
          Current Quota Non-Paged Pool Usage                 1,928
          
          Peak Page File Usage                          53,010,432
          
          Current Page File Usage                          552,960
          ---------------------------
          
          
          XP Workstation, SP1, 786mb, Dual CPU 
          ---------------------------
          Process Memory Statistics with Array Allocated
          ---------------------------
          Page Fault Count                                  13,230
          
          Peak Working Set Size                         54,239,232
          
          Current Working Set Size                      54,239,232
          
          Quota Peak Paged Pool Usage                       17,988
          
          Current Quota Paged Pool Usage                    17,988
          
          Quota Peak Non-Paged Pool Usage                    2,416
          
          Current Quota Non-Paged Pool Usage                 1,560
          
          Peak Page File Usage                          52,871,168
          
          Current Page File Usage                       52,871,168
          ---------------------------
          ---------------------------
          Process Memory Statistics at End of Job
          ---------------------------
          Page Fault Count                                  13,422
          
          Peak Working Set Size                         54,894,592
          
          Current Working Set Size                       2,441,216
          
          Quota Peak Paged Pool Usage                       19,096
          
          Current Quota Paged Pool Usage                    18,956
          
          Quota Peak Non-Paged Pool Usage                    2,656
          
          Current Quota Non-Paged Pool Usage                 1,800
          
          Peak Page File Usage                          53,047,296
          
          Current Page File Usage                          593,920
          ---------------------------
          [This message has been edited by Steve Matthews (edited January 11, 2004).]

          Comment


          • #6
            Michael,

            What about using a Memory map file you think that would help?

            Enjoy
            Ray


            ------------------
            Raymond L. King
            Custom Software Designers.

            http://www.csdsoft.com
            mailto:[email protected][email protected]</A>
            Raymond L. King
            eBook Home Biz.

            http://www.ebook-home-biz.com
            mailto:[email protected][email protected]</A>

            Comment


            • #7
              Aha! So it looks like Windows sends the big allocation directly to the swap file instead of sucking up current RAM.. actually makes sense, since we never modified any of the 50 Mb we allocated.

              This is going to be a fun thing to see what happens when I change the "real" application....

              >What about using a Memory map file you think that would help?

              That is <U>exactly</U> what I am planning. But I wanted to get this 'report memory statistics' thing working first, so we have a reasonable "before" picture. (I am putting the statistics thing in the existing software, and client will run it against "big file" keep the numbers.)

              How I am going to change the application is...
              1. Instead of loading the file data to a string and parsing it, I will memory map the file and parse the mapped view. (I'm already parsing via a pointer variable anyway).
              2. Instead of creating the array and loading data to it, I am going to write each array element to a disk file.
              3. When the input has been parsed and all the output written to the work file, I will memory map that file, and do a "REDIM array(size) AT (pointer returned by MapViewOfFile)"

              The rest of the code remains the same.

              I should have "before" and "after" info with "live" data later this week.

              This should be very interesting!

              (I'll also clean up the above demo and post it in the source code section so others can find it and use it.

              MCM

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

              Comment


              • #8
                Bravely, he posted the actual 'before' figures from the Real Live Customer system (Windows/2000) ...knowing full well if his proposed change doesn't do anything dramatic he's going to look like a dope...

                Code:
                 ========================================
                    MEMORY STATISTICS FOR THIS PROCESS
                =======================================
                
                Page Fault Count                               1,176,265
                Peak Working Set Size                        154,173,440
                Current Working Set Size                      81,588,224
                Quota Peak Paged Pool Usage                       15,036
                Current Quota Paged Pool Usage                    14,832
                Quota Peak Non-Paged Pool Usage                    3,096
                Current Quota Non-Paged Pool Usage                 2,188
                Peak Page File Usage                         223,109,120
                Current Page File Usage                      149,454,848
                
                
                      *** END OF RUN REPORT ***
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  cleaned up demo, tested only pb/windows but should work as is with pb/cc:

                  http://www.powerbasic.com/support/pb...ad.php?t=24120

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

                  Comment


                  • #10
                    Michael,

                    can't you stream the file so that you don't put so much data in memory? what happens if the file is a Gig or just too big to keep in memory some time in the future. Since it happened once sure it can happen again?

                    If the records require processing 'vertically' then it might be a problem but otherwise wouldn't it scale better (and hog less resources on this busy box) by reading say 100 records, processing them and then reading 100 more etc etc?

                    This application seems like each function does it's job once them passes the buck, perhaps a more flowing approach would work better?

                    sort of depends on what "fixupX" does I suppose

                    ------------------
                    Paul Dwyer
                    Network Engineer
                    Aussie in Tokyo

                    Comment


                    • #11
                      >can't you stream the file ...

                      Actually, yes, I could have... well, if not 'streamed' I could parse part of the file, process it, and continue with the next part of the file. But as I pointed out, when the file sizes were "as advertised" I did not see any need to do so.

                      As far as the 'passing the buck' to multiple 'fixup' function things...
                      Client has a <U>long</U> history of changing one particular fixup, adding more fixups and deleting still other fixups after initial specifications. I chose to use the approach above specifically on the assumption client would make changes after I delivered. (FWIW, he did) (several times). In other words, I put "maintainability" very, very high on the list of "considerations when designing this software."

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

                      Comment


                      • #12
                        Client ran the revised program, same input file... here are the results

                        Stats for the revised program:
                        Code:
                         ========================================
                            MEMORY STATISTICS FOR THIS PROCESS
                        =======================================
                        
                        Page Fault Count                                  36,796
                        Peak Working Set Size                         76,447,744
                        Current Working Set Size                       1,941,504
                        Quota Peak Paged Pool Usage                       87,624
                        Current Quota Paged Pool Usage                    14,944
                        Quota Peak Non-Paged Pool Usage                    3,044
                        Current Quota Non-Paged Pool Usage                 2,084
                        Peak Page File Usage                             647,168
                        Current Page File Usage                          610,304
                        
                        
                              *** END OF RUN REPORT ***
                        Still not really sure what this means.. However, I <U>am</U> sure that when customer said,"this is fantastic!" whatever it means is good.


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

                        Comment


                        • #13
                          MCM
                          This code (post2) is just what I'm looking so...Thanks for posting it.
                          Unfortunately, I'm having trouble running it, and the cleaned up version,...
                          on a PIII/Windows ME box i.e I'm getting....
                          "can't load psapi.dll"...
                          despite putting the dll in the same directory as the program.

                          I seem to be getting meaningful variable values just before the line...
                          hlib = loadlibary... but hlib is returning 0.

                          BTW I did...
                          ' lie about os for test on win/98, should return unable to load library, it does...
                          isp5 = %true.

                          As it seems to run on 98 and later Windows versions I have no idea why its not working here. Any suggestions would be very much appreciated i.e..
                          I'd like to use it to try to understand why an In-memory sqlite database isn't keeling over when I try to overfill it.

                          Comment


                          • #14
                            Your problem is...
                            Code:
                            $psapi_getprocessmemoryinfo  = "getprocessmemoryinfo"
                            The BBS software lowercased everything (even quoted literals!) when the BBS software was converted a few years ago.

                            BUT....

                            ... I reposted the program (a long time ago) with all the correct capitalization at:

                            http://www.powerbasic.com/support/pb...ad.php?t=24120

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

                            Comment


                            • #15
                              I'm still having problems despite seeing these values...
                              Code:
                              szLibName = "PSAPI.DLL"
                              szProcName = "GetProcessMemoryInfo"
                              just before the line...
                              Code:
                              "hLib           = LoadLibrary (szLibName)"
                              which...is still returning 0.

                              This is despite my changes i.e...
                              1 change name of dll in current dir from "psapi.dll" to "PSAPI.DLL"

                              2 change the line in "Process_memoryInfo.INC" i.e...
                              " lRet &nbmage GetVersionEx (OSV)" to...
                              " lRet = GetVersionEx (OSV)"

                              3 uncommenting the line in "Process_memoryInfo.INC" i.e...
                              " ' isP5 = %TRUE " to " isP5 = %TRUE "

                              Any further comments on why LoadLibrary() isn't doing it's "thing"
                              would be very welcome.

                              I even tried...
                              Code:
                               
                              '$PSAPI_GETPROCESSMEMORYINFO  = "GetProcessMemoryInfo"
                              $PSAPI_GETPROCESSMEMORYINFO  = "GETPROCESSMEMORYINFO"
                              but nada.
                              Last edited by Dean Gwilliam; 2 Dec 2010, 05:20 AM.

                              Comment


                              • #16
                                Any further comments on why LoadLibrary() isn't doing it's "thing"
                                would be very welcome.
                                ===>
                                Return Values
                                If the function succeeds, the return value is a handle to the module.

                                If the function fails, the return value is NULL. To get extended error information, call GetLastError.
                                The obvious question is, is PSAPI.DLL on the load path? (see: SearchPath() WinAPI function)

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

                                Comment


                                • #17
                                  This may help.

                                  I can never remember the name "searchpath" so I wrote this to look for "onpath"

                                  Code:
                                  ' TRUE: file found on load path. False=not 
                                  FUNCTION IsOnPath (szFile AS ASCIIZ) AS LONG
                                   LOCAL iRet AS LONG
                                   LOCAL LOCAL szFullPath AS ASCIIZ * %MAX_PATH, szFilePart AS ASCIIZ * %MAX_PATH
                                   
                                    iRet = SearchPath (BYVAL %NULL, _    ' use standard windows search order
                                                       szFile,  _
                                                       BYVAL  %NULL, _   ' file extension, if wanted
                                                       SIZEOF(szFullPath), _
                                                       szFullPath, _
                                                       szFilePart)
                                    
                                    FUNCTION = ISTRUE (iret)
                                  END FUNCTION
                                  MCM
                                  Michael Mattias
                                  Tal Systems (retired)
                                  Port Washington WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment


                                  • #18
                                    Unaware of the above two posts...
                                    I carried out the following tests as a result of the thread below.
                                    eg1 just confirms that psapi.ddl is not ALREADY loaded.
                                    eg2 tries to load Kernel32.dll OR psapi.dll depending on which is commented in.
                                    LoadLibrary() returns non-zero for Kernel32.dll but...zero for psapi.dll.
                                    INTERESTINGLY...BOTH dlls reside in C:\WINDOWS\SYSTEM.
                                    Thank you for the path search function and...
                                    how to get extended error messages.
                                    Please see GetLastError result at the bottom.

                                    Re these tests...
                                    doesn't the successful loading of Kernel32.dll rule out a path problems?

                                    Code:
                                    'http://www.powerbasic.com/support/pbforums/showthread.php?t=45395&highlight=LoadLibrary
                                    #COMPILE EXE
                                    #DIM ALL
                                    #INCLUDE "win32api.inc"
                                    
                                    SUB eg1
                                        LOCAL hLib&
                                        hLib&=GetModuleHandle("psapi.dll")
                                        ? STR$(hLib&)
                                    END SUB
                                    
                                    SUB eg2
                                      LOCAL dwOSMajorVersion        AS DWORD
                                      LOCAL dwOSMinorVersion        AS DWORD
                                      LOCAL dwSpMajorVersion        AS DWORD
                                      LOCAL dwSpMinorVersion        AS DWORD
                                      LOCAL pdwReturnedProductType  AS DWORD
                                      LOCAL lpfnGetProductInfo      AS DWORD
                                      LOCAL hLib                    AS DWORD
                                      LOCAL lRetVal                 AS LONG
                                    
                                      'hLib = LoadLibrary("Kernel32.dll") 'returns non-zero
                                      hLib = LoadLibrary("psapi.dll") 'returns zero
                                    'test
                                    ? STR$(hLib)
                                    
                                      IF hLib THEN
                                    
                                        lpfnGetProductInfo = GetProcAddress(hLib, "GetProductInfo")
                                        IF lpfnGetProductInfo THEN
                                          ! push  edi
                                          ! push  esi
                                          ! push  ebx
                                          ! lea   esi, pdwReturnedProductType
                                          ! push  esi
                                          ! push  dwSpMinorVersion
                                          ! push  dwSpMajorVersion
                                          ! push  dwOSMinorVersion
                                          ! push  dwOSMajorVersion
                                          ! call  lpfnGetProductInfo
                                          ! mov   lRetVal, eax
                                          ! pop   ebx
                                          ! pop   esi
                                          ! pop   edi
                                        END IF
                                        FreeLibrary hLib
                                      END IF
                                    
                                      ' If call succeeded
                                      IF lRetVal THEN
                                    
                                      END IF
                                    END SUB
                                    
                                    
                                    FUNCTION PBMAIN () AS LONG
                                        eg1
                                        eg2
                                    END FUNCTION
                                    BTW GetLastError if I've correctly understood it's usage i.e...
                                    Code:
                                      hLib = LoadLibrary("psapi.dll") 'returns zero
                                    IF ISFALSE hLib THEN ? "GetLastError returning..." & STR$(GetLastError)
                                    is returning 0???

                                    I also ran...
                                    Code:
                                    FUNCTION PBMAIN () AS LONG
                                        eg1
                                        eg2
                                        IF ISTRUE IsOnPath ("psapi.dll") THEN ? "true"
                                        IF ISTRUE IsOnPath ("Kernel32.dll") THEN ? "true"
                                        IF ISTRUE IsOnPath ("doesntexist.dll") THEN ? "true" ELSE ? "false"
                                    END FUNCTION
                                    where IsOnPath() returned true, true and false respectively.

                                    Is this looking like a dodgy dll???



                                    [/code]
                                    Last edited by Dean Gwilliam; 2 Dec 2010, 12:06 PM.

                                    Comment


                                    • #19
                                      You may never call GetLastError() if the function you are querying (in your case LoadLibrary()) is called with a string literal or string expression parameter. (This has been explained here many times, take my word for it, you can't do that).

                                      The correct sequence requires you use a variable for that parameter:
                                      Code:
                                       LOCAL szLib AS ASCIIZ * %MAX_PATH, LE AS LONG 
                                      
                                        szLib = "psapi.dll" 
                                        hLib =  LoadLibrary (szLib) 
                                        LE =    GetLastError()        ' <<< CALL IMMEDIATELY
                                        IF isFalse hLib THEN 
                                           MSGBOX SystemErrorMessageText(LE),%MB_ICONHAND, "Can't load " & szLib
                                        ....
                                      OK, you can have this here too..
                                      Code:
                                      #IF NOT %DEF (%SYSEMT_INC)
                                        %SYSEMT_INC  = 1
                                      FUNCTION SystemErrorMessageText (BYVAL ECode AS LONG) AS STRING
                                        LOCAL Buffer AS ASCIIZ * 255
                                        FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, ECode, %NULL, buffer, SIZEOF(buffer), BYVAL %NULL
                                        FUNCTION = FORMAT$(ECode, "##### ") & Buffer
                                      END FUNCTION
                                      
                                      #ENDIF
                                      MCM
                                      Michael Mattias
                                      Tal Systems (retired)
                                      Port Washington WI USA
                                      [email protected]
                                      http://www.talsystems.com

                                      Comment


                                      • #20
                                        Code:
                                          'hLib = LoadLibrary("Kernel32.dll") 'returns non-zero
                                          hLib = LoadLibrary("psapi.dll") 'returns zero
                                          LE = GetLastError()        ' <<< CALL IMMEDIATELY
                                          IF ISFALSE hLib THEN
                                             MSGBOX SystemErrorMessageText(LE),%MB_ICONHAND, "Can't load " & "psapi.dll"
                                          END IF
                                        Thanks for the correction and for SystemErrorMessageText()
                                        When incorporated...as above...MSGBOX returns...
                                        Code:
                                        "0 The operation completed successfully"
                                        and yet...
                                        as shown above...
                                        the message only get's shown when...hLib is false.
                                        Am I right in thinking that's surprising?

                                        Just out of interest I loaded Kernel32.dll again...
                                        without testing hLib and...
                                        it returned the same message which I would expect.
                                        Last edited by Dean Gwilliam; 2 Dec 2010, 01:32 PM.

                                        Comment

                                        Working...
                                        X