home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / findex.zip / FINDEX.DOC < prev    next >
Text File  |  1993-09-16  |  38KB  |  754 lines

  1. FINDEXEC.EXE (VERSION 1.1)              Copyright (c) 1993 Douglas Boling
  2. -------------------------------------------------------------------------
  3.                    First Published in PC Magazine August 1993 (Utilities)
  4. -------------------------------------------------------------------------
  5. FINDEXEC BY DOUGLAS BOLING
  6.  
  7.         FINDEX.EXE lets you search all drives/directories on the system
  8. PATH for a program and reports the location of its executable files.
  9. Under Windows or OS/2, FINDEXEC also reports the requisite dynamic link
  10. libraries (DLLs). FINDEXEC is a chararcter-mode application but is
  11. operating-system neutral. You can run it from a DOS or OS/2 command line
  12. or from a Windows DOS box.
  13.  
  14. Version 1.1 fixes a number of small bugs and adds one feature.
  15. The new feature allows FINDEXEC to perform a Windows type search outside
  16. of a Windows DOS box by looking in the PATH for the file WIN.COM.
  17. The directory of WIN.COM is then assumed to be the Windows directory.
  18. -------------------------------------------------------------------------
  19.  
  20.      Have you ever entered a program name at the command prompt only to
  21. find yourself running a different application than you expected?  The same
  22. DOS PATH variable that lets you run programs without specifying their
  23. directories can necessitate a tedious search if you have to track down a
  24. same-named application located somewhere earlier on the PATH than the
  25. program you intended to execute.
  26.  
  27.      FINDEXEC, does the searching for you.  It prints out the location
  28. of a program without executing it.  The utility is unusual in that it
  29. is operating-system neutral:  You can run it from a DOS or OS/2 command
  30. line or from a Windows DOS box and it will adjust its search method for
  31. the operating system in use.  (The one restriction is that since FINDEXEC
  32. is a character-mode application, you must be in character mode rather
  33. than in graphics mode.)  Because Windows and OS/2 programs usually
  34. require dynamic link libraries (DLLs),  FINDEXEC also reports the
  35. locations of any libraries needed to run those programs.
  36.  
  37.      Compiling the FINDEXEC source is a little more involved than is
  38. usual for PC Magazine utilities, so I'll discuss this issue toward the
  39. end of the article.
  40.  
  41. USING FINDEXEC
  42.  
  43.      Whether you run FINDEXEC under DOS, OS/2 1.x, OS/2 2.x, or from a
  44. Windows DOS box, its syntax is the same:
  45.  
  46.                FINDEXEC [/W] [/V  /Ln] [/?] program_name
  47.  
  48. For example, when I enter 
  49.  
  50.                           FINDEXEC COMMAND
  51.  
  52. at my DOS prompt FINDEXEC returns the line
  53.  
  54.                           DOS program: C:\DOS50\COMMAND.COM
  55.  
  56.     FINDEXEC generally defaults to the search method used by the
  57. operating system in use.  I'll discuss these in some detail below.
  58. In the case of Windows, the FINDEXEC default uses the DOS search
  59. procedure, since many times you may want a conventional DOS check from
  60. a Windows DOS box.  By using the /W command line switch, however, you can
  61. tell FINDEXEC to use the specific Windows search method instead.  In that
  62. case, FINDEXEC depends on the windir= environment variable to locate the
  63. Windows directory.  Since this environment variable is present only in a
  64. Windows DOS box, the /W switch should not be used anywhere else.
  65. If the /W switch is used when Windows is not running, FINDEXEC displays
  66. an error message.
  67.  
  68.     A FINDEXEC search under Windows or OS/2 does not end with the finding
  69. of a designated Windows or OS/2 program.  Rather, FINDEXEC goes on to
  70. examine the .EXE file to determine which DLLs are required to run the
  71. program properly.  FINDEXEC then searches for and reports the locations
  72. of these additional necessary files.
  73.  
  74.     Again using my machine to illustrate, the command
  75.  
  76.  
  77.                           FINDEXEC klondike
  78.  
  79.  
  80. when executed from an OS/2 window, reports the following:
  81.  
  82. OS/2 2.x Program: C:\OS2\APPS\KLONDIKE.EXE
  83. Loads:
  84. OS/2 DLL: DOSCALLS
  85. OS/2 2.x DLL: C:\OS2\DLL\PMGPI.DLL
  86. OS/2 2.x DLL: C:\OS2\DLL\PMWIN.DLL
  87. OS/2 2.x DLL: C:\OS2\DLL\PMSHAPI.DLL
  88. OS/2 2.x DLL: C:\OS2\DLL\HELPMGR.DLL
  89.  
  90.     Notice in the above list that KLONDIKE must load a DLL called
  91. DOSCALLS, but that FINDEXEC did not report its path. The reason is that
  92. there is actually no such file, so there is no path to it.  When OS/2
  93. starts, it loads its main operating system DLL by reading from one of a
  94. set of DLLs.  Once in memory, the resulting DLL is simply called DOSCALLS,
  95. and FINDEXEC does all that it can by indicating that the program needs
  96. this unusual DLL.
  97.  
  98.     A similar situation arises with Windows programs.  Once Windows is
  99. loaded, KERNEL.DLL and DISPLAY.DLL are in memory, but there are no
  100. actual files named KERNEL or DISPLAY for FINDEXEC to locate.  So again,
  101. the utility simply prints out a line indicating that the program requires
  102. these DLLs.
  103.  
  104.     Fortunately, it doesn't matter that FINDEXEC can't print a path to
  105. these particular DLLs.  Since Windows can't run without KERNEL and
  106. DISPLAY, and OS/2 requires DOSCALLS, if Windows or OS/2 can run, the
  107. requisite DLLs are available. (Windows can't run without other DLLs
  108. such as USER and GDI. Remember, though, that the problem isn't that
  109. KERNEL and DISPLAY are required files, the problem is that there is
  110. no file called KERNEL.DLL or DISPLAY.DLL.)
  111.  
  112.     Dynamic link libraries under Windows or OS/2 may require DLLs of
  113. their own in order to run.  Thus, since there may be a DLL that cannot
  114. load because one of its necessary DLLs is missing, FINDEXEC can also
  115. search for every DLL required by every DLL!  The /Ln and /V switches
  116. control how much information FINDEXEC prints for each of the required
  117. DLLs.
  118.  
  119.     The /Ln switch tells FINDEXEC to descend to level n before ending
  120. its search.  Using the switch /L3 will cause FINDEXEC to display all
  121. the DLLs required by the executable file, its required DLLs, their
  122. required DLLs, and their required DLLs!
  123.  
  124.     For example, on my system, entering the following line
  125.  
  126.  
  127.                         FINDEXEC /L3 /w notepad
  128.  
  129. in a Windows DOS box returns the listing shown (below) in Figure 1. In
  130. this rather extensive list you'll notice that many of the DLLs are
  131. repeated.  This simply means that some of the DLLs NOTEPAD loads depend
  132. on the same lower-level DLLs.
  133.  
  134.     The /V (verbose) switch goes even further by telling FINDEXEC to
  135. continue searching until it has listed every file required by every
  136. DLL.  Especially under OS/2, using the /V switch can result in hundreds
  137. of lines of library listings. In most cases, checking one or two levels
  138. is enough, but if you want the complete rundown for all libraries,
  139. the /V switch will provide it .
  140.  
  141.     FINDEXEC's final switch parameter, /?, brings up a help screen that
  142. explains the program's full syntax.
  143.  
  144. FINDING A PROGRAM
  145.  
  146.     As indicated earlier, depending on the operating system in use,
  147. FINDEXEC employs the same search methods used by DOS, Windows, or OS/2
  148. to find an executable file.  Since these search methods differ somewhat,
  149. however, it may be useful to discuss them in detail.
  150.  
  151.     The search for DOS executable files is actually performed by
  152. COMMAND.COM.  If the user enters a path along with the desired program
  153. name, COMMAND.COM looks no further than the specified directory for the
  154. file.  If no extension is specified, COMMAND.COM looks first for a .COM
  155. file, then for an .EXE file, and finally for a .BAT file that matches
  156. the filename.  Under DOS versions earlier than 4.0, even a user-specified
  157. file extension is ignored and the .COM-.EXE-.BAT search order is imposed. 
  158. When a matching file is found, COMMAND.COM uses DOS's Exec function
  159. (Int 21 function 4Bh) to execute the file.
  160.  
  161.     If the user does not enter a path along with the program name,
  162. COMMAND.COM starts by looking for the file in the current directory.
  163. Here again, if the user does not specify an extension (or even if he
  164. does, under DOS versions prior to 4.0), DOS follows the .COM-.EXE-.BAT
  165. order in looking for the file.  If no matching file is found, COMMAND.COM
  166. then searches for it successively in each of the directories listed in
  167. the PATH environment variable.  The .COM-.EXE-.BAT sequence is followed
  168. within each directory, but a batch file with a .BAT extension will be
  169. executed instead of a program with a .COM extension if the .BAT file is
  170. in a directory listed earlier in the PATH.
  171.  
  172.     The DOS APPEND program can modify the program search order.
  173. If APPEND is loaded with the /X:ON switch specified, COMMAND.COM looks
  174. in the APPENDed directories before it turns its attention to any path
  175. directories.  Indeed, if both the /PATH:ON and /X:ON switches are set
  176. on APPEND, COMMAND.COM will load a program from the APPENDed directories
  177. even if the user specifies a path along with the program name.  Thus,
  178. the effect of APPEND is to make COMMAND.COM (and any other DOS program)
  179. think that all the files in the APPENDed directories are located in
  180. the current directory.  Since the current directory is checked before
  181. PATH directories, files in the APPENDed directories are executed before
  182. programs in the path.
  183.  
  184.     The Windows search method is more complex. It is used by Windows
  185. when a program is launched from the File|Run menu item in the Program
  186. Manager or when a path is not included for an icon in the Program
  187. Manager window.  Actually, the Program Manager doesn't perform the
  188. search for the program; Windows does.  Windows uses its search method
  189. for any program (including the Program Manger) that uses WinExec, the
  190. Windows API function, to launch a program.
  191.  
  192.     Thus, there is a fundamental difference between DOS and Windows
  193. file searches.  In DOS, it is COMMAND.COM that determines the order of
  194. the search.  In Windows, it is the WinExec API call that determines the
  195. search order.  Any program that uses WinExec, such as my own WinCmd
  196. interpreter (which appeared in the April 27, 1993, Utilities column),
  197. automatically ends up using the Windows search method.  The equivalent
  198. DOS API--that is, Exec (Int 21 Function 4Bh)--performs no searches.
  199. The Exec function works only if the program specified is in the
  200. current directory or if a path is specified along with the program
  201. name. As with a DOS search, a Windows search depends on whether a path
  202. is specified with the filename.  If so, then the search for the file
  203. is restricted to the directory specified.  If a filename is entered by
  204. itself, Windows starts its search with the working directory, just as
  205. in DOS.  DOS users know the working directory as the current directory.
  206.  
  207.     If the program name sent to WinExec includes an extension, Windows
  208. looks only for a file that matches the name and extension.  If an
  209. extension is not specified, however, Windows does not restrict itself
  210. to the familiar .COM, .EXE, and .BAT DOS extensions.  Instead, Windows
  211. looks for files with extensions that are listed in the Programs= item
  212. in the [Windows] section of WIN.INI.  By default, these extensions are
  213. .COM, .EXE, .BAT, and .PIF, but other extensions can be added.  For
  214. example, an .SCR extension is often added to the Programs= list so
  215. that Windows will look for screen savers.  Windows uses the extensions
  216. in the order they are listed in Programs=.  The default order looks
  217. like the DOS extension order with the .PIF extension added.  In
  218. Windows, PIF (program information file) files are used to customize
  219. a DOS program's execution.
  220.  
  221.     After looking for the file in the current directory, Windows turns
  222. to the Windows directory.  The Windows directory is where files such
  223. as WIN.COM, WIN.INI, and SYSTEM.INI are stored.  Next, Windows looks
  224. in its system directory.  This is the directory that holds such files
  225. as GDI.EXE and USER.EXE, along with the driver files that Windows uses.
  226.  
  227.     If the file has still not been found, Windows looks next in
  228. the directory that holds the program calling WinExec.  This directory
  229. may be different from the current or working directory.  For example,
  230. if the calling program is launched from C:\DATA, but the Windows
  231. program itself is located in the C:\PROGRAMS directory, the current
  232. directory is C:\DATA, but the directory containing the executable file
  233. for the current task is C:\PROGRAMS.  After checking the calling
  234. program's directory, Windows looks successively in each of the
  235. directories that are listed in the PATH. If the program is not found
  236. there, Windows examines any network directories that have been mapped.
  237.  
  238.     When a Windows program requires a DLL, Windows checks to see
  239. whether another program has already loaded the same DLL.  If so,
  240. Windows simply directs any calls to the DLL to the already-loaded copy.
  241. If the DLL is not in memory, Windows looks for it in the same directories
  242. that were scanned in the original program search.  The only difference
  243. is that in this search Windows looks only for files with a .DLL
  244. extension.  (Windows driver files with a .DRV extension are also DLLs,
  245. but they will already have been loaded at the time Windows was
  246. started.)
  247.  
  248.     OS/2's method for searching for programs is closer to that of DOS
  249. than to that of Windows.  The search is performed by CMD.EXE, which is
  250. OS/2's version of DOS's COMMAND.COM.  If no path is specified with the
  251. program name, CMD.EXE looks in the current directory, then in each one
  252. of the directories listed on the PATH. CMD.EXE looks for the files with
  253. the extensions .COM, .EXE, .CMD, and .BAT, in that order.  (CMD files
  254. are OS/2's equivalent of DOS batch files.)
  255.  
  256.     As with DOS 4.0 and later, and as with Windows, the user can restrict
  257. the search by specifying the program's extension.  Thus, if the user asks
  258. for PROG.EXE, CMD.EXE will ignore a program called PROG.COM even if the
  259. latter is in the same directory.  OS/2 is intelligent enough to launch
  260. a Presentation Manager or DOS application from the OS/2 command line if
  261. the program found is a PM or DOS application.  By contrast, attempting
  262. to execute a Windows program from a Windows DOS box results in the
  263. silly message, ``This program requires Microsoft Windows.''
  264.  
  265.     Like Windows programs, OS/2 programs frequently require DLLs in order
  266. to run.  When trying to locate a DLL, OS/2 looks first in the directories
  267. specified in the LIBPATH parameter of CONFIG.SYS.  If the DLL is not found
  268. in one of the LIBPATH directories, the directory containing the program
  269. is searched.  Unlike the program search, the search for DLLs is performed
  270. by the OS/2 system, not by CMD.EXE.  That's because DLLs are used by all
  271. OS/2 programs, not just by those launched by CMD.EXE.
  272.  
  273. FINDEXEC SEARCHES
  274.  
  275.      Simply put, FINDEXEC itself uses the same rules to hunt for programs
  276. as do DOS, Windows, and OS/2.  For DOS and OS/2, FINDEXEC looks in the
  277. current directory, then checks each directory listed in the PATH
  278. statement.  The Windows search is a bit more complex, since the Windows
  279. and Windows system directories must be checked.  FINDEXEC performs all
  280. these searches by brute force, using the DosFindFirst API function to
  281. locate the first file with a proper extension.
  282.  
  283.     FINDEXEC's real work comes after an OS/2 or Windows executable file
  284. is found during a Windows or OS/2 search.  In these cases, FINDEXEC must
  285. determine whether the program requires any DLLs and, if so, it must then
  286. locate those DLLs.  And to know what DLLs a program needs, FINDEXEC must
  287. know a little about the format of the executable file.
  288.  
  289.     The structure of Windows .EXE and OS/2 1.x .EXE files is quite
  290. similar; both use the New Executable (NE) .EXE format.  NE format
  291. programs are actually two programs bundled into one.  The file begins
  292. with a standard (old) DOS .EXE header and a small DOS stub program.
  293. When run under DOS, the DOS Exec function sees the DOS .EXE header
  294. and loads the small DOS stub.  Normally, the stub program simply prints
  295. out a message, such as ``This program requires OS/2,'' or ``This program
  296. requires Microsoft Windows.''  However, a pointer in the old .EXE header
  297. contains the offset in the file of the real .EXE header for the program.
  298. Both OS/2 and Windows look for this new header, which they use in loading
  299. the program.
  300.  
  301.     The NE header is much more complex than the old, standard DOS header.
  302. The NE header begins with a signature word--the ASCII characters NE--that
  303. serves to identify it.  The header itself contains pointers and offsets
  304. to various tables for resources, entry points into the program, and--what
  305. FINDEXEC is interested in--the list of the program's required DLLs.
  306. The NE header is documented both in the Windows Software Development Kit
  307. and in Appendix D of Ray Duncan's Advanced OS/2 Programming
  308. (Microsoft Press, 1991).
  309.  
  310.     Enhanced-mode Windows applications, OS/2 2.x applications, and
  311. Windows/NT applications use different and mutually incompatible .EXE
  312. file formats.  All that these formats have in common are the real-mode
  313. DOS stub program idea and a format-identifying signature in the first
  314. 2 or 4 bytes at the start of their new .EXE headers.
  315.  
  316.       The alphabet soup of .EXE formats includes the LX format for
  317. OS/2 2.x programs, the LE format for Windows VxD drivers, and the PE
  318. format for Windows/NT programs.  A detailed explanation of these formats
  319. is beyond the scope of this article, but Ray Duncan has discussed each
  320. of them (in the February 9, March 16, and March 30, 1993, Power
  321. Programming columns).
  322.  
  323.     For each supported .EXE type, FINDEXEC determines the type of .EXE
  324. and then reads in the list of required DLLs.  The code for determining
  325. the .EXE type is shown (below) in Figure 2.  Briefly summarized, the
  326. GetEXEType routine opens the file and reads in the DOS .EXE header.
  327. If the value at offset 18 hex is greater than 40 hex, the file contains
  328. one of the new header types.  A pointer to the new header is located at
  329. offset 3C hex in the old header.  GetEXEType reads in the header and then
  330. uses the signature bytes at the start of the new header to determine the
  331. .EXE type.
  332.  
  333. A FAPI APPLICATION
  334.  
  335.      How can one program be both a DOS application and an OS/2 application
  336. at the same time?  If you browse through the FINDEXEC source code,
  337. you'll find that there are a number of calls to the OS/2 API but none
  338. to DOS.  In fact, FINDEXEC is an OS/2 1.x program that uses a subset of
  339. the OS/2 1.x character-mode API.  So, how can FINDEXEC run under DOS
  340. when it is an OS/2 program?
  341.  
  342.     The answer is that FINDEXEC is compiled, linked, and bound into what
  343. is called a Family Application.  A Family Application uses a limited part
  344. of the OS/2 API that can be translated into DOS calls by means of a
  345. special binding layer when the program is run under DOS.
  346.  
  347.     With all the conflicts over PC operating systems these days, I find
  348. it amazing that the character-mode OS/2 1.x API is supported by all the
  349. new operating systems.  You'd expect that IBM's OS/2 2.x would be
  350. backward-compatible with OS/2 1.x, but even Microsoft's Windows/NT
  351. supports OS/2 1.x character-mode applications.  Add the ability of a
  352. Family Application to run under DOS, and you end up with an application
  353. that will execute under every mainstream operating system running on the
  354. PC today!
  355.  
  356.     The set of Family API (FAPI) functions is listed (below) in Figure 3.
  357. To an OS/2 programmer the list will look rather sparse, but a DOS
  358. programmer will find a veritable feast of powerful functions.  The
  359. only glaring omission is a set of mouse functions.  To handle a mouse,
  360. FAPI programs must use MOUSE.COM's Int 33 calls when run under DOS and
  361. OS/2 MouXXX calls when run under OS/2 or Windows NT.
  362.  
  363.     Family Applications must be written as OS/2 apps, with none of the
  364. straight-to-the-hardware practices normally found in DOS programs.
  365. Further, since a FAPI program executes in protected mode under OS/2,
  366. strict segment discipline must be maintained.  That means no accessing
  367. of unallocated memory locations and no segment arithmetic beyond what
  368. is allowed when dealing with huge pointers. Unfortunately, when executing
  369. under DOS, FAPI applications are subject to the DOS real-mode limit of
  370. 640K of total RAM.
  371.  
  372.     Though FAPI applications are supported by the current operating
  373. systems, actually creating one is an exercise in technological
  374. archeology.  The problem is that neither OS/2 1.x nor the FAPI concept
  375. ever really caught on.  To compile a FAPI application, you need both
  376. a compiler that supports OS/2 1.x and the BIND.EXE program that was
  377. bundled with the OS/2 1.x Software Development Kit.  Microsoft's C 5.1
  378. and 6.0 compilers represent another source for the OS/2 1.x libraries
  379. and for BIND.  Unfortunately, Microsoft removed OS/2 support and
  380. BIND.EXE from its C 7.0 product, so if you upgraded and deleted all
  381. the old compiler files, you're out of luck.  IBM is not much help
  382. either; the OS/2 2.0 Software Development Kit can't be used to create
  383. OS/2 1.x applications.  And although IBM has kept the OS/2 1.x SDK in
  384. its product list, it may be a chore actually getting hold of such an
  385. old product.  My advice is to hunt through your old compiler files or
  386. give your compiler vendor a call.
  387.  
  388.     FAPI applications are compiled as OS/2 character-mode applications.
  389. The compiler and linker must support OS/2 1.x.  The OS/2 resource compiler
  390. is also necessary to set the appropriate flags in the EXE header.
  391. Finally, the BIND program is necessary to turn the OS/2 application into
  392. a FAPI application.
  393.  
  394.     BIND.EXE is the key to the FAPI concept.  When BIND is run against
  395. an OS/2 1.x character-mode application, it replaces the standard DOS stub
  396. program with a set of libraries that translate the OS/2 API calls into
  397. DOS calls.  For example, if a FAPI program called the OS/2 function
  398. DosFindFirst, BIND would hook in a routine that would translate the
  399. DosFindFirst call into DOS's Find First call (Int 21h Function 4Eh).
  400. On the other hand, when the FAPI program is executed in protected mode,
  401. the DOS API translation program that BIND hooked in is skipped in favor
  402. of the native protected-mode code.
  403.  
  404.     Once the real-mode routines have been hooked into an OS/2
  405. application, that application will run under DOS and OS/2 without
  406. requiring any special files.  In fact, without looking at the structure
  407. of the .EXE file itself, you won't be able to tell a FAPI application
  408. from a DOS or OS/2 character-mode application.
  409.  
  410.     If the FAPI concept is so attractive, why isn't every DOS application
  411. a FAPI application?  The answer lies in the commercial fate of
  412. OS/2 1.x.  Faced with a lack of user enthusiasm for OS/2, the
  413. software industry saw no need to write applications that were compatible
  414. with both DOS and with the tiny OS/2 1.x market.  When IBM then released
  415. OS/2 2.0, with its excellent DOS emulation, FAPI was again deemed
  416. unnecessary, for now OS/2 could run almost every DOS application
  417. automatically.
  418.  
  419.     Despite industry indifference, however, there is still a place
  420. for FAPI.  It's the perfect format for utility programs such as
  421. FINDEXEC.  Utilities tend to be simple, but they must find a place
  422. under DOS, OS/2, and, in the future, Windows/NT.  One FAPI utility
  423. can take the place of DOS, OS/2, and Windows utilities and ensure
  424. that you won't have the wrong utility when you boot up a different
  425. operating system.  FAPI utilities are also needed on OS/2 systems
  426. whose DOS emulation has been disabled with the PROTECTONLY switch.
  427.  
  428.     FINDEXEC is a handy utility that works in all kinds of environments.
  429. Its services are useful on the smallest 256K PC as well as on the biggest
  430. server running OS/2.  So stop guessing exactly what program actually ran
  431. and where it is; let FINDEXEC tell you.
  432. ----------------------------------------------------------------------------
  433. DOUGLAS BOLING IS A CONTRIBUTING EDITOR TO PC MAGAZINE.
  434. ===========================================================================
  435.  
  436. Release History:
  437.  
  438. Version 1.0     Initial Release PC Mag Vol 12, No 14.
  439.  
  440. Version 1.1     Increased read buff to 16384 for big reference
  441.                  tables.
  442.  
  443.                 Save/Restored Program directory in recursive
  444.                  calls to GetxxRefs.
  445.  
  446.                 If WinDir not found, check for WIN.COM in PATH
  447. ---------------------------------------------------------------------------
  448.  
  449.                      Sample FINDEXEC Output
  450.  
  451.  
  452. Windows Program: C:\WINDOWS\NOTEPAD.EXE
  453. Loads:
  454.       Windows DLL: KERNEL
  455.       Windows DLL: C:\WINDOWS\SYSTEM\GDI.EXE
  456.             Windows DLL KERNEL
  457.       Windows DLL: C:\WINDOWS\SYSTEM\USER.EXE
  458.             Windows DLL: KERNEL
  459.             Windows DLL: CT:\WINDOWS\SYSTEM\GDI.EXE
  460.                   Windows DLL: KERNEL
  461.             Windows DLL: C:\WINDOWS\SYSTEM\SYSTEM.DRV
  462.                   Windows DLL: KERNEL
  463.             Windows DLL: C:\WINDOWS\SYSTEM\KEYBOARD.DRV
  464.                   Windows DLL: KERNEL
  465.             Windows DLL: C:\WINDOWS\SYSTEM\MOUSE.DRV
  466.                   Windows DLL: KERNEL
  467.                   Windows DLL: C:\WINDOWS\SYSTEM\SYSTEM.DRV
  468.             Windows DLL: DISPLAY
  469.             Windows DLL: C:\WINDOWS\SYSTEM\SOUND.DRV
  470.                   Windows DLL: KERNEL
  471.             Windows DLL: C:\WINDOWS\SYSTEM\COMM.DRV
  472.                   Windows DLL: C:\WINDOWS\SYSTEM\SYSTEM.DRV
  473.                   Windows DLL: KERNEL
  474.       Windows DLL: C:\WINDOWS\SYSTEM\KEYBOARD.DRV
  475.             Windows DLL: KERNEL
  476.       Windows DLL: C:\WINDOWS\SYSTEM\COMMDLG.DLL
  477.             Windows DLL: KERNEL
  478.             Windows DLL: C:\WINDOWS\SYSTEM\GDI.EXE
  479.                   Windows DLL: KERNEL
  480.             Windows DLL: C:\WINDOWS\SYSTEM\USER.EXE
  481.                   Windows DLL: KERNEL
  482.                   Windows DLL: C:\WINDOWS\SYSTEM\GDI.EXE
  483.                   Windows DLL: C:\WINDOWS\SYSTEM\SYSTEM.DRV
  484.                   Windows DLL: C:\WINDOWS\SYSTEM\KEYBOARD.DRV
  485.                   Windows DLL: C:\WINDOWS\SYSTEM\MOUSE.DRV
  486.                   Windows DLL: DISPLAY
  487.                   Windows DLL: C:\WINDOWS\SYSTEM\SOUND.DRV
  488.                   Windows DLL: C:\WINDOWS\SYSTEM\COMM.DRV
  489.             Windows DLL: C:\WINDOWS\SYSTEM\KEYBOARD.DRV
  490.                   Windows DLL: KERNEL
  491.       Windows DLL: C:\WINDOWS\SYSTEM\SHELL.DLL
  492.             Windows DLL: KERNEL
  493.             Windows DLL: C:\WINDOWS\SYSTEM\GDI.EXE
  494.                   Windows DLL: KERNEL
  495.             Windows DLL: C:\WINDOWS\SYSTEM\USER.EXE
  496.                   Windows DLL: KERNEL
  497.                   Windows DLL: C:\WINDOWS\SYSTEM\GDI.EXE
  498.                   Windows DLL: C:\WINDOWS\SYSTEM\SYSTEM.DRV
  499.                   Windows DLL: C:\WINDOWS\SYSTEM\KEYBOARD.DRV
  500.                   Windows DLL: C:\WINDOWS\SYSTEM\MOUSE.DRV
  501.                   Windows DLL: DISPLAY
  502.                   Windows DLL: C:\WINDOWS\SYSTEM\SOUND.DRV
  503.                   Windows DLL: C:\WINDOWS\SYSTEM\COMM
  504.  
  505. Figure 1: The FINDEXEC /Ln switch sets the number of levels of DLL
  506.           information that are reported.  To get this output, the
  507.           switch was set to /L3 on the author's machine.
  508. ===========================================================================
  509.                              FINDEXEC.C
  510.  
  511.                            Partial Listing
  512.  
  513.  
  514. // GetEXEType - Loads a file and returns its operating system.
  515. //-------------------------------------------------------------------
  516. INT GetEXEType (char *szFName, INT *psNumRefEnt, LONG *plFPtr) {
  517.  
  518.     PBYTE        lpbData;
  519.     USHORT    usSel, usBytesRead;
  520.     INT        sTargOS;
  521.     HFILE        hFile;
  522.  
  523.     if (DosAllocSeg (BUFFSIZE, &usSel, 0))
  524.         return ERR_OUTOFMEM;
  525.     lpbData = MAKEP (usSel, 0);
  526.  
  527.     hFile = FileOpen (szFName);
  528.     if (hFile == -1) {
  529.         DosFreeSeg (usSel);
  530.         return (ERR_NOOPENEXE);
  531.     }                    
  532.     DosRead (hFile, lpbData, BUFFSIZE, &usBytesRead);
  533.     if (usBytesRead < 0x40) {                
  534.         FileClose (hFile);
  535.         DosFreeSeg (usSel);
  536.         return 0;
  537.     }
  538.     //Check for "MZ"
  539.     if (*(PUSHORT)lpbData != 0x5a4d) {
  540.         FileClose (hFile);
  541.         sTargOS = 0;                 //DOS            
  542.         if (*(PLONG)(lpbData+0x171) == 0x5243494d) 
  543.             sTargOS = 7;              //Window PIF            
  544.         DosFreeSeg (usSel);
  545.         return sTargOS;
  546.     }
  547.     //Check for New EXE header
  548.     if (*((PSHORT)(lpbData+0x18)) < 0x40) {
  549.         FileClose (hFile);
  550.         DosFreeSeg (usSel);
  551.         return 0;
  552.     }
  553.     //Read New EXE header
  554.     *plFPtr = (LONG) *((PLONG)(lpbData+0x3C));
  555.     DosChgFilePtr (hFile, (LONG) *plFPtr, 0, plFPtr);
  556.  
  557.     DosRead (hFile, lpbData, BUFFSIZE, &usBytesRead);
  558.     FileClose (hFile);
  559.  
  560.     switch (*(PUSHORT)lpbData) {
  561.  
  562.         //Check for NewEXE (NE)
  563.         case 0x454E:
  564.             if (*(lpbData+0x36) & 2) 
  565.                 sTargOS = 1;                 //Windows
  566.             else if (*(lpbData+0x36) & 1) 
  567.                 sTargOS = 2;                 //OS/2 1.x
  568.  
  569.             if (*(PUSHORT)(lpbData+0x0C) & 0x8000) 
  570.                 sTargOS += 0x100;            //Library
  571.  
  572.             if (psNumRefEnt != 0)             
  573.                 *psNumRefEnt = *((PSHORT)(lpbData+0x1E));
  574.             if (plFPtr != 0) 
  575.                 *plFPtr += (LONG) *((PUINT)(lpbData+0x28));
  576.  
  577.             break;
  578.  
  579.         //Check for LinearEXE (LE)
  580.         case 0x454C:
  581.             sTargOS = 3;                    //Win 3.x Enh mode
  582.             if (*(PULONG)(lpbData+0x10) & 0x8000) 
  583.                 sTargOS += 0x100;            //Library
  584.  
  585.             if (psNumRefEnt != 0)
  586.                 *psNumRefEnt = (INT) *((PULONG)(lpbData+0x74));
  587.             if (plFPtr != 0) 
  588.                 *plFPtr += (LONG) *((PULONG)(lpbData+0x70));
  589.             break;
  590.  
  591.         //Check for LinearEXE (LX)
  592.         case 0x584C:
  593.             sTargOS = 4;                    //OS/2 2.x
  594.             if (*(PULONG)(lpbData+0x10) & 0x8000) 
  595.                 sTargOS += 0x100;            //Library
  596.  
  597.             if (psNumRefEnt != 0)
  598.                 *psNumRefEnt = (INT) *((PULONG)(lpbData+0x74));
  599.             if (plFPtr != 0) 
  600.                 *plFPtr += (LONG) *((PULONG)(lpbData+0x70));
  601.             break;
  602.  
  603.         //Check for LinearEXE (PE)
  604.         case 0x4550:
  605.             sTargOS = 5;                    //Win/NT
  606.             if (psNumRefEnt != 0)             
  607.                 *psNumRefEnt = 0;
  608.             break;
  609.     
  610.     }
  611.     DosFreeSeg (usSel);
  612.     return sTargOS;
  613. }
  614.  
  615.  
  616. Figure 2: The GetEXEType routine in FINDEXEC is used to determine the
  617.          target operating system of an executable.
  618. ===========================================================================
  619.             File, Memory, and Operating System Functions
  620.  
  621. Function                             Description
  622.  
  623. DosAllocHuge               Allocates huge memory block greater than 64KB
  624. DosAllocSeg                Allocates memory block
  625. DosBeep                    Generates tone
  626. DosBufReset                Flushes file buffers, updates directory
  627. DosCaseMap                 Translates ASCII string in place
  628. DosChDir                   Selects current directory
  629. DosChgFilePtr              Sets file pointer position
  630. DosCLIAccess               Notifies intent to use CLI and STI
  631. DosClose                   Closes file, pipe, or device
  632. DosCreateCSAlias           Obtains executable alias for data segment
  633. DosDelete                  Deletes file
  634. DosDevConfig               Returns system hardware configuration
  635. DosDevIOCtl                Device-specific commands and information
  636. DosDupHandle               Duplicates or redirects handle
  637. DosErrClass                Returns information about error code
  638. DosError                   Disables or enables system critical error handler
  639. DosExecPgm                 Creates child process
  640. DosExit                    Terminates thread or process
  641. DosFileLocks               Locks or unlocks file region
  642. DosFindClose               Releases directory search handle
  643. DosFindFirst               Searches for first matching file
  644. DosFindNext                Searches for additional matching files
  645. DosFreeSeg                 Releases selector
  646. DosGetCollate              Returns collating sequence table
  647. DosGetCp                   Returns current code page identifier
  648. DosGetCtryInfo             Returns internationalization information
  649. DosGetDateTime             Returns current time, date, and day of week
  650. DosGetDBCSEv               Returns table of double-byte character-set codes
  651. DosGetEnv                  Returns selector for process's environment
  652. DosGetHugeShift            Returns increment value for huge memory block
  653.                              selectors
  654. DosGetMachineMode          Returns flag indicating real or protected mode
  655. DosGetMessage              Retrieves message from disk file
  656. DosGetVersion              Returns DOS or OS/2 version number
  657. DosHoldSignal              Suspends signal processing for current process
  658. DosInsMessage              Inserts variable text into body of message
  659. DosMkDir                   Creates directory
  660. DosMove                    Renames and/or moves file
  661. DosNewSize                 Changes size of file
  662. DosOpen                    Opens, replaces, or creates file, or opens device
  663. DosPortAccess              Notifies intent to use range of I/O ports
  664. DosPutMessage              Sends message to file, pipe, or device
  665. DosQCurDir                 Returns current directory
  666. DosQCurDir                 Returns current directory
  667. DosQCurDisk                Returns current disk drive
  668. DosQFHState                Returns file handle sharing and access
  669.                              characteristics
  670. DosQFileInfo               Returns file size, attributes, and date and time
  671.                              stamps
  672. DosQFileMode               Returns file attributes
  673. DosQFSInfo                 Returns file system information or volume label
  674. DosQVerify                 Returns state of read-after-write flag
  675. DosRead                    Reads data from file, pipe, or device
  676. DosReallocHuge             Resizes huge memory block
  677. DosReallocSeg              Resizes normal memory block
  678. DosRmDir                   Deletes directory
  679. DosOpen                    Opens, replaces, or creates file, or opens device
  680. DosPortAccess              Notifies intent to use range of I/O ports
  681. DosPutMessage              Sends message to file, pipe, or device
  682. DosQCurDir                 Returns current directory
  683. DosQCurDisk                Returns current disk drive
  684. DosQFHState                Returns file handle sharing and access
  685.                              characteristics
  686. DosQFileInfo               Returns file size, attributes, and date and time
  687.                            stamps
  688. DosQFileMode               Returns file attributes
  689. DosQFSInfo                 Returns file system information or volume label
  690. DosQVerify                 Returns state of read-after-write flag
  691. DosRead                    Reads data from file, pipe, or device
  692. DosReallocHuge             Resizes huge memory block
  693. DosReallocSeg              Resizes normal memory block
  694. DosRmDir                   Deletes directory
  695. DosSelectDisk              Selects current disk drive
  696. DosSetDateTime             Sets current date and time
  697. DosSetFHState              Sets file handle characteristics
  698. DosSetFileInfo             Sets file time and date stamps
  699. DosSetFileMode             Sets file attributes
  700. DosSetFSInfo               Adds or changes volume label
  701. DosSetSigHandler           Registers signal handler
  702. DosSetVec                  Registers handler for hardware exception
  703. DosSetVerify               Sets system read-after-write flag
  704. DosSleep                   Suspends requesting thread for specified interval
  705. DosSubAlloc                Allocates memory from local heap
  706. DosSubFree                 Releases memory in local heap
  707. DosSubSet                  Initializes local heap
  708. DosWrite                   Writes to file, pipe, or device
  709.  
  710. Keyboard functions
  711.  
  712.  
  713. KbdCharIn                  Returns keyboard character and scan code
  714. KbdFlushBuffer             Discards waiting keyboard characters
  715. KbdGetStatus               Returns logical keyboard status
  716. KbdPeek                    Returns character-waiting status
  717. KbdSetStatus               Sets logical keyboard characteristics
  718. KbdStringIn                Reads buffered line from keyboard
  719.  
  720.  
  721. Video functions|
  722.  
  723.  
  724. VioGetBuf                  Returns address of logical video buffer
  725. VioGetConfig               Returns hardware characteristics of video adapter
  726. VioGetCurPos               Returns cursor position
  727. VioGetCurType              Returns cursor shape, size, and attribute
  728. VioGetMode                 Returns characteristics of current display mode
  729. VioGetPhysBuf              Returns selector for physical video display buffer
  730. VioReadCellStr             Reads string of character-attribute pairs
  731. VioReadCharStr             Retrieves character string from display buffer
  732. VioScrLock                 Locks physical display for I/O
  733. VioScrollDn                Scrolls display down
  734. VioScrollLf                Scrolls display left
  735. VioScrollRt                Scrolls display right
  736. VioScrollUp                Scrolls display up
  737. VioScrUnLock               Releases lock on physical display
  738. VioSetCurPos               Sets cursor position
  739. VioSetCurType              Sets cursor shape, size, and attribute
  740. VioSetMode                 Selects display mode
  741. VioShowBuf                 Updates physical display from logical display
  742.                              buffer
  743. VioWrtCellStr              Writes character-attribute pairs to display
  744. VioWrtCharStr              Writes character string to display
  745. VioWrtCharStrAtt           Writes character string with specified attribute
  746.                              to display
  747. VioWrtNAttr                Changes attributes of one or more characters on
  748.                              display
  749. VioWrtNCell                Writes one or more character-attribute pairs
  750. VioWrtNChar                Writes one or more characters
  751. VioWrtTTY                  Writes character string to display in teletype mode
  752.  
  753. Figure 3: Here is a list of the OS/2 Family Application functions.
  754. =============================================================================