Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

PB/Win32(any): Show program's modules and path from which loaded

  • Filter
  • Time
  • Show
Clear All
new posts

  • PB/Win32(any): Show program's modules and path from which loaded

    debugging tool for pb and "brand m" basic users.

    shell'ed exe source code follows; requires pb/win 7.x to compile.

    complete archive - all source code, compiled exes, and "brand m" #include file and demo program

    thanks to balthasar indermuehle, who ported the pb #include file and wrote the "brand m" demo application.

    ***** #include file for pb/cc or pb/win *****
    ' file:
    ' #include file to use with pb/win or pb/cc program to show loaded modules
    ' this file intended to be used to call the 'modlist.exe' program
    ' as a debugging tool.
    ' author: michael mattias racine wi usa.
    ' visual basic conversion of this file and test program courtesy balthasar indermuehle
    ' comments/suggestions via email to [email protected]
    ' use and redistribution: source and executable placed in public domain
    '    by the authors june 7 2003.
    ' written: june 2003.
    ' compilers used for testing: powerbasic pb/win version 7.02 and pb/cc 3.02
    ' dates of pb-supplied windows header files used in this include file:
    '    may      9, 2002
    ' program usage:
    ' the shelled program is executed with a command line of:
    '  modlist.exe   process-id [program-name]
    '  process-id can be obtained by using the windows api call getcurrentprocessid
    '  (it can also be obtained a number of other ways).
    '  optional program-name is simply a string which will be put in the caption
    '  of the dialog of $modlist_program_name; if null it does not hurt.
    ' ====[ history ] =================================================================
    ' 06/07/03  1.0.0  original
    ' ================================================================
    ' usage at the powerbasic pb/cc or pb/win source code level
    ' #include this file. requires windows functions/equates detailed below.
    ' so include after including
    ' call the function "showmeallloadedmodules" at whatever points
    ' in the program you want to know exactly which modules are loaded
    ' into your process space. the listing will include any modules
    ' loaded at load-time (i.e., declared with a lib) or any modules
    ' currently dynamically loaded with loadlibrary
    ' requirements
    ' 1. $modlist_program_name must available via shell to calling program: on path,
    '     in system directory or in or in the same directory as calling program).
    ' 2. $modlist_program_name may not contain spaces unless quotation marks
    '     are explictly added when building the command line to shell
    ' 3. relies on powerbasic compilers continuing to translate shell into a
    '    call to the windows function createprocess.
    '    this is an undocumented feature, so it  is subject to change in future
    '    versions of compilers; and since the feature is undocumentd, any  changes
    '    will likely be undocumented, too.
    ' 3a. ok, so i could have used createprocess myself and spared myself the angst
    '     regarding the shell function.
    ' the author originally used shellexecuteex rather than shell; however,
    ' shellexecuteex itself requires shell32.dll, gdi32.dll, shwlapi.dll and comctl32.dll
    ' which are not necessarily required by the program being tested (or imported by
    ' default by the powerbasic compiler).
    ' === end of preliminaries. begin main event =====================================
    ' program shelled by the main function; must be available to calling program.
    $modlist_program_name = "modlist.exe"
    ' ===== alternate program which can be shelled ====================================
    ' at  is another
    ' version of this program, which enumerates all processes and modules with version
    ' info currently running on the system. that program may be substituted for this
    ' program if complete system process and module listing is desired. (does not
    ' isolate modules for specific process).
    ' that software is collaborative effort of semen matusovsky, borje hagsten,
    ' dave navarro and bob scott
    ' =================================================================================
    ' include the windows header file
    #if not %def(%winapi)
      #include ""
    ' =================================================================================
    ' function to shell $modlist_program_name and wait until it enters idle state
    ' (that program does not enter idle state until snapshot taken and dialog is built)
    ' =================================================================================
    function showmeallloadedmodules () as long
    ' build command line = "pid, space, program name to appear in dialog caption"
    ' shell function to get pid
    ' open that pid to get process handle on which to wait
    ' wait for shelled program (a gui program) to enter idle state and exit.
       local dwpid as dword, szprogramname as asciiz * %max_path, szparameters as asciiz * %max_path
       local stat as long, e as long, szfile as asciiz * %max_path
       local idshellprocess as dword
       local hshellprocess  as dword
       local timeout2 as long, smsg as string
       local funcval        as long
       funcval     =  -1       ' default to failure
       ' get the name and process id of this (the calling) program
       getmodulefilename   byval %null, szprogramname, sizeof(szprogramname)
       szprogramname     = mid$(szprogramname, instr(-1, szprogramname, "\") + 1)
       dwpid             = getcurrentprocessid()
       ' get the name and build the parameters for the program which will actually
       ' show the modules loaded by this program
       szfile           = $modlist_program_name
       szparameters     = ltrim$(str$(dwpid)) & $spc & szprogramname
       timeout2         = %infinite          ' this ought be be long enough!
       ' start the module-lister program and wait until it has entered idle state,
       ' meaning it has completed its snapshot and has all the info it needs.
       idshellprocess   = shell (szfile & $spc & szparameters)
       if idshellprocess > &h20 then
           hshellprocess = openprocess (%synchronize, %false, idshellprocess)
           if istrue hshellprocess then
               stat = waitforinputidle (hshellprocess, timeout2)
               select case as long stat
                    case %wait_object_0
                      ' program entered input idle, this is good, we do nothing
                        funcval  =  0   ' success!
               end select
               closehandle hshellprocess
              smsg  = "could not open shelled process for synchronize access!"
              #if %def(%pb_cc32)
                 stdout smsg
                 msgbox smsg, %mb_iconhand, "oops"
          end if
      elseif idshellprocess = 0 then
          e     =  err
          smsg  =  "shell failed on error " & str$(e) & $spc & error$(e)
          #if %def(%pb_cc32)
             stdout smsg
             msgbox smsg, %mb_iconhand, "oops"
      end if
      function = funcval
    end function
    ' *** end of file
    ***** demo appplication for pb/cc 3.x or 7.x *****

    ' test_modlist.bas
    ' program to test the shell of the modlist program
    ' author: michael mattias racine wi usa  6/7/03
    ' for pb/cc 3.02 and pb win 7.02
    ' placed in public domain by author.
    #compile     exe
    #register    none
    #debug error on
    #dim         all
    #tools       off
    ' include file for modlist program
    #include ""
    ' just for testing to make sure i am reading the loaded from path correctly..
    ' this should be loaded from c:\utility\dll
    $test_dll_name =  "ddoc32.dll"
    ' declare a function in $test_dll_name to test if modules correctly itemized
    ' when load-time linking is done
    'declare function dpprintercount lib "ddoc32.dll" alias "dpprintercount" as long
    function winmain( byval  hinstance   as long      , _
                      byval  hprevinst   as long      , _
                             lpszcmdline as asciiz ptr, _
                      byval  ncmdshow    as long        ) as long
       local hlib as long, smsg as string, lresult as long
       hlib = %null
      ' statements for testing
       if 2 = 2 then
       ' test if it shows modules loaded by loadlibrary. yes, it does
         hlib = loadlibrary ("ddoc32.dll")
       ' test if it shows modules loaded when program starts. yes, it does.
         'call dpprintercount           < ' uncomment to test load-time linking
       end if
       call showmeallloadedmodules to lresult
        ' launches the viewer and returns
       if istrue hlib then
            freelibrary hlib
       end if
       smsg = iif$(lresult, "error getting module list", "all currently loaded modules shown.")
       #if %def(%pb_cc32)
          stdout smsg
          stdout "any key to terminate program"
          msgbox smsg, %mb_iconinformation, "all done"
    end function
    ' ** end of file ***

    michael mattias
    tal systems inc.
    racine wi usa
    mailto:[email protected][email protected]</a>
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]

  • #2
    compiled exe available at

    ** modlist.exe source code - requires 7.x
    ' file: modlist.bas
    ' gui program to list the loaded modules of a process id passed as command-line
    ' parameter. this program only works with initial input. it is meant to be
    ' called from another program only, primarily as a debugging tool.
    ' ===========================================================================
    ' author: michael mattias racine wi usa.
    ' comments/suggestions via email to [email protected]
    ' use and redistribution: source and executable placed in public domain
    '   by the author june 7 2003.
    ' written: june 2003.
    ' compiler used: powerbasic pb/win version 7.02
    ' dates of pb-supplied windows header files used:
    '    may      9, 2002
    '    april    8, 2002
    '    january  9, 2003
    ' program usage:
    ' execute with a command line of:
    '  modlist.exe   process-id [program-name]
    '  process-id can be obtained by using the windows api call getcurrentprocessid
    '  (it can also be obtained a number of other ways).
    '  optional program-name is simply a string which will be put in the caption
    '  of the dialog if null it does not hurt.
    '  the file "" may be used from a pb/cc or pb/win program
    '  to call from a pb program.
    ' ---------------------------------------------------------------------------------
    ' this program uses the toolhelp functions to get the module list for the specified
    ' process. the enumprocessmodules function could be used, but this function is not
    ' supported on win 9x/me.
    ' alternate software available:
    ' at  is another
    ' version of this program, which enumerates all processes and modules with version
    ' info currently running on the system. that program may be substituted for this
    ' program if complete system process and module listing is desired. (does not
    ' isolate modules for specific process).
    ' that software is collaborative effort of semen matusovsky, borje hagsten,
     'dave navarro and bob scott
    ' ---------------------------------------------------------------------------------
    ' ====[ history ] =================================================================
    ' 06/07/03  1.0.0  original
    #compile  exe
    #debug    error on
    #register none
    #dim      all
    #tools    off
    '===[windows api header files]=========================================
    '  if you don't need all of the functionality supported by these apis
    '  (and who does?), you can selectively turn off various modules by putting
    '  the following constants in your program before you #include "":
    '  %nogdi = 1     ' no gdi (graphics device interface) functions
    '  %nommids = 1   ' no multimedia id definitions
    %nommids  = 1
    #include ""
    ' windows 'tool help' file containing functions and udts used to take the snapshot:
    #include ""
    #resource "modlist.pbr"
    ' ==[ code for source code bundler program ] =======================
    ' include the *.rc script and its includes without trying to compile it
    ' works because resource compiler uses "#include", too; and any resource
    ' include is assumed to be the same as the compiler include (not necessarily true,
    ' but i don't feel like writing more code when this works for me).
    ' can use this method to include any files which belong with the 'source code bundle'
    #if 0
       #include "modlist.rc"
       #include "modlist.ico"
       ' include in source code bundle the "inc" file used
       #include ""
       ' the compiled exe, this program
       #include "modlist.exe"
       ' pb (win & cc) test program source code:
       #include "test_modlist.bas"
       ' microsoft visual basic demo materiels
       #include "vb_tester.exe"
       #include "modmodlist.bas"
       #include "tester.vbp"
    ' ==== common controls include =============
    '  you can disable support (and code) for the various common controls by
    '  defining the following constants in your code *before* the #include statement.
    '  note that the value does not have to be 1 as bases
    '  everything on #if def(%noxxx)
    %skel_use_commoncontrol = 1
    #if %skel_use_commoncontrol
    ' these equates must be commented out - not set to zero - to activate the particular control
    ' (now *that* is weird!, hey?)
        %noanimate       = 1  ' animate control.
        %nobutton        = 1  ' button_xxx macros
        %nocombo         = 1  ' combobox_xxx macros
        %nodatetimepick  = 1
        %nodraglist      = 1  ' apis to make a listbox source and sink drag&drop actions.
        %noedit          = 1  ' edit_xxx macros
        %noflatsbapis    = 1
        %noheader        = 1  ' header bar control.
        %nohotkey        = 1  ' hotkey control.
        %noimagelist     = 1  ' imagelist apis.
        %noipaddress     = 1
        %nolist          = 1  ' listbox_xxx macros
    '    %nolistview      = 1  ' listview control.
        %nomenuhelp      = 1  ' apis to help manage menus, especially with a status bar.
        %nomonthcal      = 1
        %nomui           = 1
        %nonativefontctl = 1
        %nopagescroller  = 1
        %noprogress      = 1  ' progress gas gauge.
        %norebar         = 1
        %nostatusbar     = 1  ' status bar control.
        %notabcontrol    = 1
        %notoolbar       = 1  ' customizable bitmap-button toolbar control.
        %notooltips      = 1
        %notrackbar      = 1  ' customizable column-width tracking control.
        %notreeview      = 1  ' treeview control.
        %noupdown        = 1  ' up and down arrow increment/decrement control.
       #include ""
    ' === end of common controls include ===========
    ' ====[utility macros ] ========================
    function isscclose (byval wparam as long ) as long
        function = (wparam and &h0fff0) = %sc_close
    end function
    macro postbuttonclick(hwnd,ctrlid)
      postmessage hwnd, %wm_command, makdwd(ctrlid,%bn_clicked), getdlgitem(hwnd,ctrlid)
    end macro
    ' ====[ control ids and equates:  main dialog proc ] ========================
    $main_dlg_name           =   "maindialog"
    %id_lv                   =    102&
    %id_save                 =    103&   ' not used yet; reserved
    %id_quit                 =    104&   ' uses idok, not idquit. reserved.
    ' ====[ internal declares ] ========================
    declare function moduleversionstring (szfile as asciiz) as string
    ' ====[program entry point ] ========================
    function winmain (byval hinstance     as long, _
                      byval hprevinstance as long, _
                      lpcmdline           as asciiz ptr, _
                      byval icmdshow      as long) as long
       local iccex as init_common_controlsex
       local szdlgname as asciiz * 64, dwaddr as dword, param as long, hdlg as long
       local msg as tagmsg, nmodule as long
       local hprocess as long
       local wstring as string, dwpid as dword, scommandline as string, i as long
       local szprogramname as asciiz * %max_path
            scommandline = @lpcmdline
           ' for test only...
           ' scommandline = ltrim$(str$(getcurrentprocessid())) & " " & "program name"
            dwpid          = val(parse$(scommandline, $spc, 1))
            i = instr (scommandline, $spc)
            if i then
                szprogramname  = mid$(scommandline, i+ 1)
                szprogramname  = "not provided"
            end if
            if dwpid = 0 then
                msgbox "usage: modlist process-id [program-name]", %mb_iconhand,"command-line error"
                exit function
                hprocess  =  openprocess (%process_dup_handle, %false, dwpid)
                if isfalse hprocess then
                    msgbox  "can't open process id " & str$(dwpid) & ". probably invalid", %mb_iconhand, "process id error"
                    exit function
                    closehandle hprocess
                end if
            end if
      ' initialize the common controls library
            iccex.dwsize         = sizeof(iccex)
            iccex.dwicc          = %icc_listview_classes
            initcommoncontrolsex   iccex
      ' get a snapshot and load module info to an array
            redim me32(0) as moduleentry32
            call  enumloadedmodules (dwpid, me32()) to nmodule
            if  nmodule = %null then
                msgbox "no modules found. this is real bad.", %mb_iconhand,"get modules error"
                exit function
            end if
      ' set up to create the dialog.
            szdlgname      = $main_dlg_name
            dwaddr         = codeptr (maindialogproc)
            ' set param = address of me32() array descriptor
            param     = varptr (me32())
            ' create a modeless dialog ..
            hdlg     =  createdialogparam (hinstance, szdlgname, getdesktopwindow(), dwaddr, param)
            ' set the caption of that dialog
            setwindowtext hdlg, "loaded module list for program " & szprogramname
      ' enter message loop...
      while getmessage(msg, %null, 0, 0)
           if isfalse isdialogmessage (hdlg, msg) then
                  translatemessage msg
                  dispatchmessage msg
           end if
      function = msg.wparam
    end function  ' winmain
    ' =========================================================
    ' for listview setup called on wm_initdialog
    ' sets up the columns. for version 1, only four columns
    %col_module_name   = 0
    %col_version       = 1
    %col_base_size     = 2
    %col_load_path     = 3
    %lv_col_max        = 3&
    ' columns i may add later:
    ' ====[main dialog proc ] ========================
    ' lparam on wm_initdialog = address of me32() array descriptor
    function maindialogproc (byval hwnd as long, byval wmsg as long, _
                      byval wparam as long, byval lparam as long) export as long
        local sztext as asciiz * %max_path, i as long
        select case wmsg
              case %wm_initdialog
              ' set the icon in caption bar..
                  i = loadicon (getmodulehandle(byval %null), "_program")
                  sendmessage hwnd, %wm_seticon, %icon_big, i
                  sendmessage hwnd, %wm_seticon, %icon_small, i
                  ' set up listview columns, passing address of me32() array
                  call setupmainlistview (getdlgitem(hwnd, %id_lv))
                  ' load the data to the listview control..
                  call loadmoduleinfotolistview (getdlgitem(hwnd, %id_lv), byval lparam)
                  function = %true
                  exit function
              case %wm_syscommand
               ' handle a system close by posting an idok
               ' not actually necessary in this program, since there is nothing
               ' to be 'cleaned up' when dialog closes.
                 if   isscclose(wparam) then
                      postbuttonclick (hwnd,%idok)
                      function = 0: exit function   ' app should return zero if it processes this mesage
                 end if
                 function = 0 ' do not exit, as other syscommands must be hit by default window proc!
              case %wm_destroy
                  ' when dialog is destroyed, the program ends..
                  postquitmessage 0
              ' believe it or not, this program does nothing with the listview control
              ' case %wm_notify
              ' handle "commands" from the dialog...
              case %wm_command
                   select case lowrd(wparam)
                        case %idok
                            destroywindow hwnd
                            function = %true
                            exit function
                   end select
       end select
       function = %false
    end function
    function setupmainlistview (byval hlv as long) as long
       local sztext as asciiz * %max_path   ' we re-use this, a lot
       local i as long, j as long, k as long    ' just counters
      ' for the listview setup
       local  lvc       as lvcolumn
       local  lvexstyle as dword
              ' set the extended style for the control
               lvexstyle = %ws_ex_clientedge
               i         = sendmessage (hlv, %lvm_setextendedlistviewstyle, lvexstyle, lvexstyle)
              ' add the column headers to the listview control
              ' initialize the column structure and set the column headers
                lvc.mask        =  %lvcf_fmt or %lvcf_text or %lvcf_width
                lvc.psztext     = varptr(sztext)
                lvc.isubitem    = 0
                lvc.iimage      = 0
                lvc.iorder      = 0
                for i = 0 to %lv_col_max
                  select case i
                     case %col_module_name
                          sztext   = "module name"
                          lvc.fmt  = %lvcfmt_left
                   = 90
                     case %col_version
                          sztext   = "version"
                          lvc.fmt  = %lvcfmt_left
                   = 90
                     case %col_base_size
                          sztext   = "base size"
                          lvc.fmt  = %lvcfmt_right
                   = 70
                     case %col_load_path
                          sztext   = "loaded from path"
                          lvc.fmt  = %lvcfmt_left
                   = 500
                  end select
                  j = sendmessage (hlv, %lvm_insertcolumn, i, byval varptr(lvc))
               next i
    end function
    ' =============================================================================
    ' load the me32() array to the listvew control
    ' note that the second parameter passed to this function is the address of the
    ' me32() array descriptor.
    ' =============================================================================
    function  loadmoduleinfotolistview (byval hwnd as long, me32() as moduleentry32) as long
      local lvi as lvitem, maxrow as long
      local i   as long, j as long, k as long
      local sztext as asciiz * %max_path
      maxrow  = ubound(me32,1)    ' 0 based array, 0 based row numbers
      for i   = 0 to maxrow       ' for each row of listview
        lvi.iitem = sendmessage(hwnd,%lvm_getitemcount, 0,0)
        for j = 0 to %lv_col_max                  ' for each column
               lvi.isubitem       = j             ' subitem = col#
                ' set the text based on which column we are filling
                select case as long j
                  case  %col_module_name
                      sztext =  me32(i).szmodule
                  case  %col_version
                      sztext = moduleversionstring (me32(i).szexepath)
                  case  %col_base_size
                      sztext = rset$(format$(me32(i).modbasesize, "* #,"), 12)
                  case %col_load_path
                      sztext = left$(me32(i).szexepath, instr(-1, me32(i).szexepath, "\")-1)
                end select     ' of j, column number
                lvi.psztext       = varptr(sztext)
                if j = 0 then    ' adding the row, subitem=0
                   lvi.mask       = %lvif_text
                   k              = sendmessage (hwnd, %lvm_insertitem, 0, varptr(lvi))
                   if k < 0 then
                        msgbox "lvm_insertitem failure when i=" & str$(i)
                   end if
                else ' updating the row, subitems > 0, no param
                  lvi.mask        = %lvif_text
                  k               = sendmessage (hwnd, %lvm_setitem,0, varptr(lvi))
                end if
            next j  ' next column
        next i       ' next row
    end function
    ' ==================================================================
    '   function to enumerate all modules loaded by passed process id
    '   returns: number of modules loaded; me32() redimed 0-(nmodule-1)
    ' ==================================================================
    function enumloadedmodules (byval dwpid as dword, ame32() as moduleentry32) as long
        local hsnapshot as dword, lresult as dword
        local me32      as moduleentry32
        local i         as long
        local dwsnapshotflags as dword, dwmesize as dword, sme32 as string, nmodule as long
       ' ================================================================================
       ' create a snapshot of all modules in named process. parameter two (pid)
       ' ignored unless th32cs_snapheaplist or tc32cs_snapmodule are specified.
       ' ================================================================================
        dwsnapshotflags        = %th32cs_snapmodule
        hsnapshot              = createtoolhelp32snapshot (dwsnapshotflags, dwpid)
        if hsnapshot <> %invalid_handle_value then
                me32.dwsize         = sizeof(me32)               ' must be set; may be changed lower
                sme32               = "                         ' but will not be greater
                lresult             = module32first (hsnapshot,me32)
                while istrue lresult
                    ' we found a module so get the actual length and save to a string..
                    ' save the entire *defined* me32 structure; we'll shorten later if needed
                     incr          nmodule
                     dwmesize    = me32.dwsize
                     sme32       = sme32 & peek$(varptr(me32), sizeof(me32))
                     lresult     = module32next (hsnapshot, me32)
                closehandle        hsnapshot
                if nmodule then
                ' we now have the module info in sme32; resize array and move data there
                ' dwmesize is actual valid size of me32; as it turns out we do not
                ' use this in this program, we just use the defined me32 size.
                    redim ame32(nmodule-1)
                    copymemory  byval varptr(ame32(0)), byval strptr(sme32), len(sme32)
                end if
        else                     ' could not get snapshot..invalid_handle_value
                msgbox "can't get snapshot handle, process may have terminated", %mb_iconhand, "get module list error"
        end if
        function = nmodule
    end function
    ' =================================================================
    ' get a string representation of a module's version number
    ' if target module has no version resource returns "not found"
    ' =================================================================
    function moduleversionstring (szfile as asciiz) as string
      local major as long, minor as long, build as long, subbuild as long, w as string
      local ressize as long
      local ffi  as vs_fixedfileinfo ptr
      local  ret as long
      local buffer as string
      major=0: minor = 0:  build = 0: subbuild = 0
      ressize        = getfileversioninfosize (szfile, ret)
      if ressize     = 0 then
        function     = " not found"
        exit function
      end if
      buffer          =  space$(ressize)
      ret             =  getfileversioninfo(szfile, %null, ressize, byval strptr(buffer))
    ' ** read the vs_fixedfileinfo info
      verqueryvalue byval strptr(buffer), "\", ffi, sizeof(@ffi)
      major       = @ffi.dwproductversionms  \  &h10000
      minor       = @ffi.dwproductversionms mod &h10000
      build       = @ffi.dwproductversionls  \  &h10000
      subbuild    = @ffi.dwproductversionls mod &h10000
      w =     str$(major) & "." & trim$(str$(minor))
      w = w & iif$(build=0, ", "." & ltrim$(str$(build)))
      w = w & iif$(subbuild=0, ", "." & ltrim$(str$(subbuild)))
      function = w
    end function
    '//   end of file modlist.bas
    ** modlist.rc resource script
    //  modlist.rc
    //  resource to be used with modlist program
    //  created: 6/6/03
    #include "resource.h"
    //  ===================================================//
    //      standard version resource and #defines
    //  ===================================================//
    #define version_major     1
    #define version_minor     0
    #define version_build     0
    #define version_literal    "version 1.0.0"
    #define version_date      "june 6 2003"
    #define version_purpose   "show loaded modules"
    #define program_name      "modlist"
    vs_version_info versioninfo
    fileversion    version_major, version_minor, 0, version_build
    productversion version_major, version_minor, 0, version_build
    fileos vos_windows32
    filetype vft_app
    //filetype vft_dll   // << for dlls
      block "stringfileinfo"
        block "040904e4"
          value "companyname",      "tal systems inc\0"
          value "filedescription",   version_purpose
          value "fileversion",       version_literal
          value "author",           "michael mattias, tal systems inc.\0"
          value "internalname",      program_name
          value "legalcopyright",   "placed in public domain by author, michael c. mattias\0"
          value "legaltrademarks",  "none\0"
          value "originalfilename", "modlist\0"
          value "productname",      "none\0"
          value "versiondate",       version_date
    // program icon
    _program   icon modlist.ico
    // main dialog
    #define dlg_style ws_visible | ws_caption | ws_sysmenu|ws_minimizebox
    #define dlg_exstyle ws_ex_clientedge
    #define lv_style ws_group|ws_tabstop| lvs_report |lvs_singlesel|ws_visible |ws_border|lvs_nosortheader|lvs_showselalways
    #define id_lv                       102
    #define id_save                     103   // reserved for the future
    #define id_quit                     104   // ditto
    maindialog dialogex 6, 18, 348, 192
    style dlg_style
    exstyle dlg_exstyle
    caption "loaded modules - program name"
    font 8, "ms sans serif"
        control         "listview", id_lv, "syslistview32", lv_style, 2, 2, 344, 141
        control         "&ok", idok, "button", ws_tabstop, 154, 156, 40, 14
        control         "loaded module listing v 1.0.0 courtesy michael mattias racine wi usa",
                        -1, "static", ss_center | ws_group, 2, 180, 344, 8
    // end of resource file

    [this message has been edited by michael mattias (edited june 12, 2003).]
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]