//
// This program was written by Sang Cho, assistant professor at
//                                       the department of
//                                                                               computer science and engineering
//                                                                               chongju university
// this program is based on the program pefile.c
// which is written by Randy Kath(Microsoft Developmer Network Technology Group)
// in june 12, 1993.
// I have investigated P.E. file format as thoroughly as possible,
// but I cannot claim that I am an expert yet, so some of its information
// may give you wrong results.
//
//
//
// language used: djgpp
// date of creation: September 28, 1997
//
// date of first release: October 15, 1997
//
//
//      you can contact me: e-mail address: sangcho@alpha94.chongju.ac.kr
//                            hitel id: chokhas
//                        phone number: (0431) 229-8491    +82-431-229-8491
//
//
//
//   Copyright (C) 1997.                                 by Sang Cho.
//
//   Permission is granted to make and distribute verbatim copies of this
// program provided the copyright notice and this permission notice are
// preserved on all copies.
//
//
// File: pedump.c ( I included header file into source file. )
//
// LICENSE
//      Sources released under GNU General Public License version 2
//      or later by Mr. Sang Cho permission.
//
// REVISIONS
//      2000-04-23 (ea) Initial adaptation to GCC/MinGW/ROS.
//      2000-08-05 (ea) Initial raw adaptation done.
//

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>
#include <malloc.h>
#include <ctype.h>

#ifndef bcopy
#define bcopy(s,d,z) memcpy((d),(s),(z))
#endif

typedef char CHAR;
typedef short WCHAR;
typedef short SHORT;
typedef long LONG;
typedef unsigned short USHORT;
typedef unsigned long DWORD;
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef BYTE *PBYTE;
typedef WORD *PWORD;
typedef DWORD *PDWORD;
typedef void *LPVOID;
typedef int boolean;

#define VOID                void
#define BOOLEAN             boolean

#ifndef NULL
#define NULL                0
#endif

#define FALSE               0
#define TRUE                1
#define CONST               const
#define LOWORD(l)           ((WORD)(l))
#define WINAPI		__stdcall

//
// Image Format
//

#define IMAGE_DOS_SIGNATURE                 0x5A4D	// MZ
#define IMAGE_OS2_SIGNATURE                 0x454E	// NE
#define IMAGE_OS2_SIGNATURE_LE              0x454C	// LE
#define IMAGE_VXD_SIGNATURE                 0x454C	// LE
#define IMAGE_NT_SIGNATURE                  0x00004550	// PE00

typedef struct _IMAGE_DOS_HEADER
  {				// DOS .EXE header

    WORD e_magic;		// Magic number

    WORD e_cblp;		// Bytes on last page of file

    WORD e_cp;			// Pages in file

    WORD e_crlc;		// Relocations

    WORD e_cparhdr;		// Size of header in paragraphs

    WORD e_minalloc;		// Minimum extra paragraphs needed

    WORD e_maxalloc;		// Maximum extra paragraphs needed

    WORD e_ss;			// Initial (relative) SS value

    WORD e_sp;			// Initial SP value

    WORD e_csum;		// Checksum

    WORD e_ip;			// Initial IP value

    WORD e_cs;			// Initial (relative) CS value

    WORD e_lfarlc;		// File address of relocation table

    WORD e_ovno;		// Overlay number

    WORD e_res[4];		// Reserved words

    WORD e_oemid;		// OEM identifier (for e_oeminfo)

    WORD e_oeminfo;		// OEM information; e_oemid specific

    WORD e_res2[10];		// Reserved words

    LONG e_lfanew;		// File address of new exe header

  }
IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

//
// File header format.
//



typedef struct _IMAGE_FILE_HEADER
  {
    WORD Machine;
    WORD NumberOfSections;
    DWORD TimeDateStamp;
    DWORD PointerToSymbolTable;
    DWORD NumberOfSymbols;
    WORD SizeOfOptionalHeader;
    WORD Characteristics;
  }
IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

#define IMAGE_SIZEOF_FILE_HEADER             20

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001	// Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002	// File is executable  (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004	// Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008	// Local symbols stripped from file.
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080	// Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100	// 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200	// Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400	// If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800	// If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                    0x1000	// System File.
#define IMAGE_FILE_DLL                       0x2000	// File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000	// File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000	// Bytes of machine word are reversed.

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_I386              0x14c	// Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x162	// MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x166	// MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x168	// MIPS little-endian
#define IMAGE_FILE_MACHINE_ALPHA             0x184	// Alpha_AXP
#define IMAGE_FILE_MACHINE_POWERPC           0x1F0	// IBM PowerPC Little-Endian



//
// Directory format.
//

typedef struct _IMAGE_DATA_DIRECTORY
  {
    DWORD VirtualAddress;
    DWORD Size;

  }
IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

//
// Optional header format.
//

typedef struct _IMAGE_OPTIONAL_HEADER
  {
    //
    // Standard fields.
    //
    WORD Magic;
    BYTE MajorLinkerVersion;
    BYTE MinorLinkerVersion;
    DWORD SizeOfCode;
    DWORD SizeOfInitializedData;
    DWORD SizeOfUninitializedData;
    DWORD AddressOfEntryPoint;
    DWORD BaseOfCode;
    DWORD BaseOfData;

    //
    // NT additional fields.
    //

    DWORD ImageBase;
    DWORD SectionAlignment;
    DWORD FileAlignment;
    WORD MajorOperatingSystemVersion;
    WORD MinorOperatingSystemVersion;
    WORD MajorImageVersion;
    WORD MinorImageVersion;
    WORD MajorSubsystemVersion;
    WORD MinorSubsystemVersion;
    DWORD Win32VersionValue;
    DWORD SizeOfImage;
    DWORD SizeOfHeaders;
    DWORD CheckSum;
    WORD Subsystem;
    WORD DllCharacteristics;
    DWORD SizeOfStackReserve;
    DWORD SizeOfStackCommit;
    DWORD SizeOfHeapReserve;
    DWORD SizeOfHeapCommit;
    DWORD LoaderFlags;
    DWORD NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

  }
IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;


typedef struct _IMAGE_NT_HEADERS
  {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER OptionalHeader;

  }
IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;


// Directory Entries

#define IMAGE_DIRECTORY_ENTRY_EXPORT         0	// Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT         1	// Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE       2	// Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION      3	// Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY       4	// Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC      5	// Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG          6	// Debug Directory
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT      7	// Description String
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR      8	// Machine Value (MIPS GP)
#define IMAGE_DIRECTORY_ENTRY_TLS            9	// TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG   10	// Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  11	// Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT           12	// Import Address Table

//
// Section header format.
//

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef struct _IMAGE_SECTION_HEADER
  {
    BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
    union
      {
	DWORD PhysicalAddress;
	DWORD VirtualSize;
      }
    Misc;
    DWORD VirtualAddress;
    DWORD SizeOfRawData;
    DWORD PointerToRawData;
    DWORD PointerToRelocations;
    DWORD PointerToLinenumbers;
    WORD NumberOfRelocations;
    WORD NumberOfLinenumbers;
    DWORD Characteristics;

  }
IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

#define IMAGE_SIZEOF_SECTION_HEADER          40


//
// Export Format
//

typedef struct _IMAGE_EXPORT_DIRECTORY
  {
    DWORD Characteristics;
    DWORD TimeDateStamp;
    WORD MajorVersion;
    WORD MinorVersion;
    DWORD Name;
    DWORD Base;
    DWORD NumberOfFunctions;
    DWORD NumberOfNames;
    PDWORD *AddressOfFunctions;
    PDWORD *AddressOfNames;
    PWORD *AddressOfNameOrdinals;

  }
IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

//
// Import Format
//

typedef struct _IMAGE_IMPORT_BY_NAME
  {
    WORD Hint;
    BYTE Name[1];

  }
IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

#define IMAGE_ORDINAL_FLAG 0x80000000
#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)


//
// Resource Format.
//

//
// Resource directory consists of two counts, following by a variable length
// array of directory entries.  The first count is the number of entries at
// beginning of the array that have actual names associated with each entry.
// The entries are in ascending order, case insensitive strings.  The second
// count is the number of entries that immediately follow the named entries.
// This second count identifies the number of entries that have 16-bit integer
// Ids as their name.  These entries are also sorted in ascending order.
//
// This structure allows fast lookup by either name or number, but for any
// given resource entry only one form of lookup is supported, not both.
// This is consistant with the syntax of the .RC file and the .RES file.
//

// Predefined resource types ... there may be some more, but I don't have
//                               the information yet.  .....sang cho.....

#define    RT_NEWRESOURCE   0x2000
#define    RT_ERROR         0x7fff
#define    RT_CURSOR        1
#define    RT_BITMAP        2
#define    RT_ICON          3
#define    RT_MENU          4
#define    RT_DIALOG        5
#define    RT_STRING        6
#define    RT_FONTDIR       7
#define    RT_FONT          8
#define    RT_ACCELERATORS  9
#define    RT_RCDATA        10
#define    RT_MESSAGETABLE  11
#define    RT_GROUP_CURSOR  12
#define    RT_GROUP_ICON    14
#define    RT_VERSION       16
#define    NEWBITMAP        (RT_BITMAP|RT_NEWRESOURCE)
#define    NEWMENU          (RT_MENU|RT_NEWRESOURCE)
#define    NEWDIALOG        (RT_DIALOG|RT_NEWRESOURCE)


typedef struct _IMAGE_RESOURCE_DIRECTORY
  {
    DWORD Characteristics;
    DWORD TimeDateStamp;
    WORD MajorVersion;
    WORD MinorVersion;
    WORD NumberOfNamedEntries;
    WORD NumberOfIdEntries;
//      IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[1];

  }
IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

#define IMAGE_RESOURCE_NAME_IS_STRING        0x80000000
#define IMAGE_RESOURCE_DATA_IS_DIRECTORY     0x80000000

//
// Each directory contains the 32-bit Name of the entry and an offset,
// relative to the beginning of the resource directory of the data associated
// with this directory entry.  If the name of the entry is an actual text
// string instead of an integer Id, then the high order bit of the name field
// is set to one and the low order 31-bits are an offset, relative to the
// beginning of the resource directory of the string, which is of type
// IMAGE_RESOURCE_DIRECTORY_STRING.  Otherwise the high bit is clear and the
// low-order 16-bits are the integer Id that identify this resource directory
// entry. If the directory entry is yet another resource directory (i.e. a
// subdirectory), then the high order bit of the offset field will be
// set to indicate this.  Otherwise the high bit is clear and the offset
// field points to a resource data entry.
//

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY
  {
    DWORD Name;
    DWORD OffsetToData;

  }
IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

//
// For resource directory entries that have actual string names, the Name
// field of the directory entry points to an object of the following type.
// All of these string objects are stored together after the last resource
// directory entry and before the first resource data object.  This minimizes
// the impact of these variable length objects on the alignment of the fixed
// size directory entry objects.
//

typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING
  {
    WORD Length;
    CHAR NameString[1];

  }
IMAGE_RESOURCE_DIRECTORY_STRING, *PIMAGE_RESOURCE_DIRECTORY_STRING;


typedef struct _IMAGE_RESOURCE_DIR_STRING_U
  {
    WORD Length;
    WCHAR NameString[1];

  }
IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;


//
// Each resource data entry describes a leaf node in the resource directory
// tree.  It contains an offset, relative to the beginning of the resource
// directory of the data for the resource, a size field that gives the number
// of bytes of data at that offset, a CodePage that should be used when
// decoding code point values within the resource data.  Typically for new
// applications the code page would be the unicode code page.
//

typedef struct _IMAGE_RESOURCE_DATA_ENTRY
  {
    DWORD OffsetToData;
    DWORD Size;
    DWORD CodePage;
    DWORD Reserved;

  }
IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;


//  Menu Resources       ... added by .....sang cho....

// Menu resources are composed of a menu header followed by a sequential list
// of menu items. There are two types of menu items: pop-ups and normal menu
// itmes. The MENUITEM SEPARATOR is a special case of a normal menu item with
// an empty name, zero ID, and zero flags.

typedef struct _IMAGE_MENU_HEADER
  {
    WORD wVersion;		// Currently zero

    WORD cbHeaderSize;		// Also zero

  }
IMAGE_MENU_HEADER, *PIMAGE_MENU_HEADER;

typedef struct _IMAGE_POPUP_MENU_ITEM
  {
    WORD fItemFlags;
    WCHAR szItemText[1];

  }
IMAGE_POPUP_MENU_ITEM, *PIMAGE_POPUP_MENU_ITEM;

typedef struct _IMAGE_NORMAL_MENU_ITEM
  {
    WORD fItemFlags;
    WORD wMenuID;
    WCHAR szItemText[1];

  }
IMAGE_NORMAL_MENU_ITEM, *PIMAGE_NORMAL_MENU_ITEM;

#define GRAYED       0x0001	// GRAYED keyword
#define INACTIVE     0x0002	// INACTIVE keyword
#define BITMAP       0x0004	// BITMAP keyword
#define OWNERDRAW    0x0100	// OWNERDRAW keyword
#define CHECKED      0x0008	// CHECKED keyword
#define POPUP        0x0010	// used internally
#define MENUBARBREAK 0x0020	// MENUBARBREAK keyword
#define MENUBREAK    0x0040	// MENUBREAK keyword
#define ENDMENU      0x0080	// used internally


// Dialog Box Resources .................. added by sang cho.

// A dialog box is contained in a single resource and has a header and
// a portion repeated for each control in the dialog box.
// The item DWORD IStyle is a standard window style composed of flags found
// in WINDOWS.H.
// The default style for a dialog box is:
// WS_POPUP | WS_BORDER | WS_SYSMENU
//
// The itme marked "Name or Ordinal" are :
// If the first word is an 0xffff, the next two bytes contain an ordinal ID.
// Otherwise, the first one or more WORDS contain a double-null-terminated string.
// An empty string is represented by a single WORD zero in the first location.
//
// The WORD wPointSize and WCHAR szFontName entries are present if the FONT
// statement was included for the dialog box. This can be detected by checking
// the entry IStyle. If IStyle & DS_SETFONT ( which is 0x40), then these
// entries will be present.

typedef struct _IMAGE_DIALOG_BOX_HEADER1
  {
    DWORD IStyle;
    DWORD IExtendedStyle;	// New for Windows NT

    WORD nControls;		// Number of Controls

    WORD x;
    WORD y;
    WORD cx;
    WORD cy;
//      N_OR_O MenuName;         // Name or Ordinal ID
    //      N_OR_O ClassName;                // Name or Ordinal ID
    //      WCHAR  szCaption[];
    //      WORD   wPointSize;       // Only here if FONT set for dialog
    //      WCHAR  szFontName[];     // This too
  }
IMAGE_DIALOG_HEADER, *PIMAGE_DIALOG_HEADER;

typedef union _NAME_OR_ORDINAL
  {				// Name or Ordinal ID

    struct _ORD_ID
      {
	WORD flgId;
	WORD Id;
      }
    ORD_ID;
    WCHAR szName[1];
  }
NAME_OR_ORDINAL, *PNAME_OR_ORDINAL;

// The data for each control starts on a DWORD boundary (which may require
// some padding from the previous control), and its format is as follows:

typedef struct _IMAGE_CONTROL_DATA
  {
    DWORD IStyle;
    DWORD IExtendedStyle;
    WORD x;
    WORD y;
    WORD cx;
    WORD cy;
    WORD wId;
//  N_OR_O  ClassId;
    //  N_OR_O  Text;
    //  WORD    nExtraStuff;
  }
IMAGE_CONTROL_DATA, *PIMAGE_CONTROL_DATA;

#define BUTTON       0x80
#define EDIT         0x81
#define STATIC       0x82
#define LISTBOX      0x83
#define SCROLLBAR    0x84
#define COMBOBOX     0x85

// The various statements used in a dialog script are all mapped to these
// classes along with certain modifying styles. The values for these styles
// can be found in WINDOWS.H. All dialog controls have the default styles
// of WS_CHILD and WS_VISIBLE. A list of the default styles used follows:
//
// Statement           Default Class         Default Styles
// CONTROL             None                  WS_CHILD|WS_VISIBLE
// LTEXT               STATIC                ES_LEFT
// RTEXT               STATIC                ES_RIGHT
// CTEXT               STATIC                ES_CENTER
// LISTBOX             LISTBOX               WS_BORDER|LBS_NOTIFY
// CHECKBOX            BUTTON                BS_CHECKBOX|WS_TABSTOP
// PUSHBUTTON          BUTTON                BS_PUSHBUTTON|WS_TABSTOP
// GROUPBOX            BUTTON                BS_GROUPBOX
// DEFPUSHBUTTON       BUTTON                BS_DFPUSHBUTTON|WS_TABSTOP
// RADIOBUTTON         BUTTON                BS_RADIOBUTTON
// AUTOCHECKBOX        BUTTON                BS_AUTOCHECKBOX
// AUTO3STATE          BUTTON                BS_AUTO3STATE
// AUTORADIOBUTTON     BUTTON                BS_AUTORADIOBUTTON
// PUSHBOX             BUTTON                BS_PUSHBOX
// STATE3              BUTTON                BS_3STATE
// EDITTEXT            EDIT                  ES_LEFT|WS_BORDER|WS_TABSTOP
// COMBOBOX            COMBOBOX              None
// ICON                STATIC                SS_ICON
// SCROLLBAR           SCROLLBAR             None
///

#define WS_OVERLAPPED   0x00000000L
#define WS_POPUP        0x80000000L
#define WS_CHILD        0x40000000L
#define WS_CLIPSIBLINGS 0x04000000L
#define WS_CLIPCHILDREN 0x02000000L
#define WS_VISIBLE      0x10000000L
#define WS_DISABLED     0x08000000L
#define WS_MINIMIZE     0x20000000L
#define WS_MAXIMIZE     0x01000000L
#define WS_CAPTION      0x00C00000L
#define WS_BORDER       0x00800000L
#define WS_DLGFRAME     0x00400000L
#define WS_VSCROLL      0x00200000L
#define WS_HSCROLL      0x00100000L
#define WS_SYSMENU      0x00080000L
#define WS_THICKFRAME   0x00040000L
#define WS_MINIMIZEBOX  0x00020000L
#define WS_MAXIMIZEBOX  0x00010000L
#define WS_GROUP        0x00020000L
#define WS_TABSTOP      0x00010000L

// other aliases
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
#define WS_POPUPWINDOW  (WS_POPUP | WS_BORDER | WS_SYSMENU)
#define WS_CHILDWINDOW  (WS_CHILD)
#define WS_TILED        WS_OVERLAPPED
#define WS_ICONIC       WS_MINIMIZE
#define WS_SIZEBOX      WS_THICKFRAME
#define WS_TILEDWINDOW  WS_OVERLAPPEDWINDOW

#define WS_EX_DLGMODALFRAME     0x00000001L
#define WS_EX_NOPARENTNOTIFY    0x00000004L
#define WS_EX_TOPMOST           0x00000008L
#define WS_EX_ACCEPTFILES       0x00000010L
#define WS_EX_TRANSPARENT       0x00000020L

#define BS_PUSHBUTTON           0x00000000L
#define BS_DEFPUSHBUTTON        0x00000001L
#define BS_CHECKBOX             0x00000002L
#define BS_AUTOCHECKBOX         0x00000003L
#define BS_RADIOBUTTON          0x00000004L
#define BS_3STATE               0x00000005L
#define BS_AUTO3STATE           0x00000006L
#define BS_GROUPBOX             0x00000007L
#define BS_USERBUTTON           0x00000008L
#define BS_AUTORADIOBUTTON      0x00000009L
#define BS_OWNERDRAW            0x0000000BL
#define BS_LEFTTEXT             0x00000020L

#define ES_LEFT         0x00000000L
#define ES_CENTER       0x00000001L
#define ES_RIGHT        0x00000002L
#define ES_MULTILINE    0x00000004L
#define ES_UPPERCASE    0x00000008L
#define ES_LOWERCASE    0x00000010L
#define ES_PASSWORD     0x00000020L
#define ES_AUTOVSCROLL  0x00000040L
#define ES_AUTOHSCROLL  0x00000080L
#define ES_NOHIDESEL    0x00000100L
#define ES_OEMCONVERT   0x00000400L
#define ES_READONLY     0x00000800L
#define ES_WANTRETURN   0x00001000L

#define LBS_NOTIFY            0x0001L
#define LBS_SORT              0x0002L
#define LBS_NOREDRAW          0x0004L
#define LBS_MULTIPLESEL       0x0008L
#define LBS_OWNERDRAWFIXED    0x0010L
#define LBS_OWNERDRAWVARIABLE 0x0020L
#define LBS_HASSTRINGS        0x0040L
#define LBS_USETABSTOPS       0x0080L
#define LBS_NOINTEGRALHEIGHT  0x0100L
#define LBS_MULTICOLUMN       0x0200L
#define LBS_WANTKEYBOARDINPUT 0x0400L
#define LBS_EXTENDEDSEL       0x0800L
#define LBS_DISABLENOSCROLL   0x1000L

#define SS_LEFT             0x00000000L
#define SS_CENTER           0x00000001L
#define SS_RIGHT            0x00000002L
#define SS_ICON             0x00000003L
#define SS_BLACKRECT        0x00000004L
#define SS_GRAYRECT         0x00000005L
#define SS_WHITERECT        0x00000006L
#define SS_BLACKFRAME       0x00000007L
#define SS_GRAYFRAME        0x00000008L
#define SS_WHITEFRAME       0x00000009L
#define SS_SIMPLE           0x0000000BL
#define SS_LEFTNOWORDWRAP   0x0000000CL
#define SS_BITMAP           0x0000000EL

//
// Debug Format
//

typedef struct _IMAGE_DEBUG_DIRECTORY
  {
    DWORD Characteristics;
    DWORD TimeDateStamp;
    WORD MajorVersion;
    WORD MinorVersion;
    DWORD Type;
    DWORD SizeOfData;
    DWORD AddressOfRawData;
    DWORD PointerToRawData;
  }
IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;

#define IMAGE_DEBUG_TYPE_UNKNOWN          0
#define IMAGE_DEBUG_TYPE_COFF             1
#define IMAGE_DEBUG_TYPE_CODEVIEW         2
#define IMAGE_DEBUG_TYPE_FPO              3
#define IMAGE_DEBUG_TYPE_MISC             4
#define IMAGE_DEBUG_TYPE_EXCEPTION        5
#define IMAGE_DEBUG_TYPE_FIXUP            6
#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC      7
#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC    8


typedef struct _IMAGE_DEBUG_MISC
  {
    DWORD DataType;		// type of misc data, see defines

    DWORD Length;		// total length of record, rounded to four
    // byte multiple.

    BOOLEAN Unicode;		// TRUE if data is unicode string

    BYTE Reserved[3];
    BYTE Data[1];		// Actual data

  }
IMAGE_DEBUG_MISC, *PIMAGE_DEBUG_MISC;


//
// Debugging information can be stripped from an image file and placed
// in a separate .DBG file, whose file name part is the same as the
// image file name part (e.g. symbols for CMD.EXE could be stripped
// and placed in CMD.DBG).  This is indicated by the IMAGE_FILE_DEBUG_STRIPPED
// flag in the Characteristics field of the file header.  The beginning of
// the .DBG file contains the following structure which captures certain
// information from the image file.  This allows a debug to proceed even if
// the original image file is not accessable.  This header is followed by
// zero of more IMAGE_SECTION_HEADER structures, followed by zero or more
// IMAGE_DEBUG_DIRECTORY structures.  The latter structures and those in
// the image file contain file offsets relative to the beginning of the
// .DBG file.
//
// If symbols have been stripped from an image, the IMAGE_DEBUG_MISC structure
// is left in the image file, but not mapped.  This allows a debugger to
// compute the name of the .DBG file, from the name of the image in the
// IMAGE_DEBUG_MISC structure.
//

typedef struct _IMAGE_SEPARATE_DEBUG_HEADER
  {
    WORD Signature;
    WORD Flags;
    WORD Machine;
    WORD Characteristics;
    DWORD TimeDateStamp;
    DWORD CheckSum;
    DWORD ImageBase;
    DWORD SizeOfImage;
    DWORD NumberOfSections;
    DWORD ExportedNamesSize;
    DWORD DebugDirectorySize;
    DWORD SectionAlignment;
    DWORD Reserved[2];
  }
IMAGE_SEPARATE_DEBUG_HEADER, *PIMAGE_SEPARATE_DEBUG_HEADER;

#define IMAGE_SEPARATE_DEBUG_SIGNATURE  0x4944

#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000
#define IMAGE_SEPARATE_DEBUG_MISMATCH   0x8000	// when DBG was updated, the
						// old checksum didn't match.


//
// End Image Format
//


#define SIZE_OF_NT_SIGNATURE	sizeof (DWORD)
#define MAXRESOURCENAME 	13

/* global macros to define header offsets into file */
/* offset to PE file signature                                 */
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a		     +	\
			((PIMAGE_DOS_HEADER)a)->e_lfanew))

/* DOS header identifies the NT PEFile signature dword
   the PEFILE header exists just after that dword              */
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a		     +	\
			 ((PIMAGE_DOS_HEADER)a)->e_lfanew    +	\
			 SIZE_OF_NT_SIGNATURE))

/* PE optional header is immediately after PEFile header       */
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a		     +	\
			 ((PIMAGE_DOS_HEADER)a)->e_lfanew    +	\
			 SIZE_OF_NT_SIGNATURE		     +	\
			 sizeof (IMAGE_FILE_HEADER)))

/* section headers are immediately after PE optional header    */
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a		     +	\
			 ((PIMAGE_DOS_HEADER)a)->e_lfanew    +	\
			 SIZE_OF_NT_SIGNATURE		     +	\
			 sizeof (IMAGE_FILE_HEADER)	     +	\
			 sizeof (IMAGE_OPTIONAL_HEADER)))


typedef struct tagImportDirectory
  {
    DWORD dwRVAFunctionNameList;
    DWORD dwUseless1;
    DWORD dwUseless2;
    DWORD dwRVAModuleName;
    DWORD dwRVAFunctionAddressList;
  }
IMAGE_IMPORT_MODULE_DIRECTORY, *PIMAGE_IMPORT_MODULE_DIRECTORY;


/* global prototypes for functions in pefile.c */
/* PE file header info */
BOOL WINAPI GetDosHeader (LPVOID, PIMAGE_DOS_HEADER);
DWORD WINAPI ImageFileType (LPVOID);
BOOL WINAPI GetPEFileHeader (LPVOID, PIMAGE_FILE_HEADER);

/* PE optional header info */
BOOL WINAPI GetPEOptionalHeader (LPVOID, PIMAGE_OPTIONAL_HEADER);
LPVOID WINAPI GetModuleEntryPoint (LPVOID);
int WINAPI NumOfSections (LPVOID);
LPVOID WINAPI GetImageBase (LPVOID);
LPVOID WINAPI ImageDirectoryOffset (LPVOID, DWORD);
LPVOID WINAPI ImageDirectorySection (LPVOID, DWORD);

/* PE section header info */
//int   WINAPI GetSectionNames (LPVOID, HANDLE, char **);
int WINAPI GetSectionNames (LPVOID, char **);
BOOL WINAPI GetSectionHdrByName (LPVOID, PIMAGE_SECTION_HEADER, char *);

//
// structur to store string tokens
//
typedef struct _Str_P
  {
    char flag;			// string_flag '@' or '%' or '#'

    char *pos;			// starting postion of string

    int length;			// length of string

    BOOL wasString;		// if it were stringMode or not

  }
Str_P;

/* import section info */
int WINAPI GetImportModuleNames (LPVOID, char **);
int WINAPI GetImportFunctionNamesByModule (LPVOID, char *, char **);

// import function name reporting
int WINAPI GetStringLength (char *);
void WINAPI GetPreviousParamString (char *, char *);
void WINAPI TranslateParameters (char **, char **, char **);
BOOL WINAPI StringExpands (char **, char **, char **, Str_P *);
char * WINAPI TranslateFunctionName (char *);

/* export section info */
int WINAPI GetExportFunctionNames (LPVOID, char **);

/* resource section info */
int WINAPI GetNumberOfResources (LPVOID);
int WINAPI GetListOfResourceTypes (LPVOID, char **);
int WINAPI MenuScan (int *, WORD **);
int WINAPI MenuFill (char **, WORD **);
void WINAPI StrangeMenuFill (char **, WORD **, int);
int WINAPI GetContentsOfMenu (LPVOID, char **);
int WINAPI PrintMenu (int, char **);
int WINAPI PrintStrangeMenu (char **);
int WINAPI dumpMenu (char **psz, int size);

/* debug section info */
BOOL WINAPI IsDebugInfoStripped (LPVOID);
int WINAPI RetrieveModuleName (LPVOID, char **);
BOOL WINAPI IsDebugFile (LPVOID);
BOOL WINAPI GetSeparateDebugHeader (LPVOID, PIMAGE_SEPARATE_DEBUG_HEADER);


/**********************************************************************
 * NAME
 *
 * DESCRIPTION
 *	Copy DOS header information to structure.
 *
 * ARGUMENTS
 */
BOOL WINAPI
GetDosHeader (
	       LPVOID lpFile,
	       PIMAGE_DOS_HEADER pHeader
)
{
  /*
   * DOS header represents first structure
   * of bytes in PE image file.
   */
  if ((WORD) IMAGE_DOS_SIGNATURE == *(WORD *) lpFile)
    {
      bcopy (
	      lpFile,
	      (LPVOID) pHeader,
	      sizeof (IMAGE_DOS_HEADER)
	);
      return TRUE;
    }
  return FALSE;
}




/* return file signature */
DWORD WINAPI
ImageFileType (
		LPVOID lpFile)
{
  /* dos file signature comes first */
  if (*(USHORT *) lpFile == IMAGE_DOS_SIGNATURE)
    {
      /* determine location of PE File header from dos header */
      if (LOWORD (*(DWORD *) NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE ||
	  LOWORD (*(DWORD *) NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE_LE)
	return (DWORD) LOWORD (*(DWORD *) NTSIGNATURE (lpFile));

      else if (*(DWORD *) NTSIGNATURE (lpFile) == IMAGE_NT_SIGNATURE)
	return IMAGE_NT_SIGNATURE;

      else
	return IMAGE_DOS_SIGNATURE;
    }

  else
    /* unknown file type */
    return 0;
}




/* copy file header information to structure */
BOOL WINAPI
GetPEFileHeader (
		  LPVOID lpFile,
		  PIMAGE_FILE_HEADER pHeader)
{
  /* file header follows dos header */
  if (ImageFileType (lpFile) == IMAGE_NT_SIGNATURE)
    bcopy (PEFHDROFFSET (lpFile), (LPVOID) pHeader, sizeof (IMAGE_FILE_HEADER));
  else
    return FALSE;

  return TRUE;
}





/* copy optional header info to structure */
BOOL WINAPI
GetPEOptionalHeader (
		      LPVOID lpFile,
		      PIMAGE_OPTIONAL_HEADER pHeader)
{
  /* optional header follows file header and dos header */
  if (ImageFileType (lpFile) == IMAGE_NT_SIGNATURE)
    bcopy (OPTHDROFFSET (lpFile), (LPVOID) pHeader, sizeof (IMAGE_OPTIONAL_HEADER));
  else
    return FALSE;

  return TRUE;
}




/* function returns the entry point for an exe module lpFile must
   be a memory mapped file pointer to the beginning of the image file */
LPVOID WINAPI
GetModuleEntryPoint (
		      LPVOID lpFile)
{
  PIMAGE_OPTIONAL_HEADER poh = (PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (lpFile);

  if (poh != NULL)
    return (LPVOID) (poh->AddressOfEntryPoint);
  else
    return NULL;
}




/* return the total number of sections in the module */
int WINAPI
NumOfSections (
		LPVOID lpFile)
{
  /* number os sections is indicated in file header */
  return ((int) ((PIMAGE_FILE_HEADER) PEFHDROFFSET (lpFile))->NumberOfSections);
}




/* retrieve entry point */
LPVOID WINAPI
GetImageBase (
	       LPVOID lpFile)
{
  PIMAGE_OPTIONAL_HEADER poh = (PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (lpFile);

  if (poh != NULL)
    return (LPVOID) (poh->ImageBase);
  else
    return NULL;
}



//
// This function is written by sang cho
//                                                 .. october 5, 1997
//
/* function returns the actual address of given RVA,      lpFile must
   be a memory mapped file pointer to the beginning of the image file */
LPVOID WINAPI
GetActualAddress (
		   LPVOID lpFile,
		   DWORD dwRVA)
{
//    PIMAGE_OPTIONAL_HEADER   poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
  PIMAGE_SECTION_HEADER psh = (PIMAGE_SECTION_HEADER) SECHDROFFSET (lpFile);
  int nSections = NumOfSections (lpFile);
  int i = 0;

  if (dwRVA == 0)
    return NULL;
  if (dwRVA & 0x80000000)
    {
      //return (LPVOID)dwRVA;
      printf ("\n$$ what is going on $$");
      exit (0);
    }

  /* locate section containing image directory */
  while (i++ < nSections)
    {
      if (psh->VirtualAddress <= (DWORD) dwRVA &&
	  psh->VirtualAddress + psh->SizeOfRawData > (DWORD) dwRVA)
	break;
      psh++;
    }

  if (i > nSections)
    return NULL;

  /* return image import directory offset */
  return (LPVOID) (((int) lpFile + (int) dwRVA - psh->VirtualAddress) +
		   (int) psh->PointerToRawData);
}


//
// This function is modified by sang cho
//
//
/* return offset to specified IMAGE_DIRECTORY entry */
LPVOID WINAPI
ImageDirectoryOffset (
		       LPVOID lpFile,
		       DWORD dwIMAGE_DIRECTORY)
{
  PIMAGE_OPTIONAL_HEADER poh = (PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (lpFile);
  PIMAGE_SECTION_HEADER psh = (PIMAGE_SECTION_HEADER) SECHDROFFSET (lpFile);
  int nSections = NumOfSections (lpFile);
  int i = 0;
  LPVOID VAImageDir;

  /* must be 0 thru (NumberOfRvaAndSizes-1) */
  if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
    return NULL;

  /* locate specific image directory's relative virtual address */
  VAImageDir = (LPVOID) poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;

  if (VAImageDir == NULL)
    return NULL;
  /* locate section containing image directory */
  while (i++ < nSections)
    {
      if (psh->VirtualAddress <= (DWORD) VAImageDir &&
	  psh->VirtualAddress + psh->SizeOfRawData > (DWORD) VAImageDir)
	break;
      psh++;
    }

  if (i > nSections)
    return NULL;

  /* return image import directory offset */
  return (LPVOID) (((int) lpFile + (int) VAImageDir - psh->VirtualAddress) +
		   (int) psh->PointerToRawData);
}


/* function retrieve names of all the sections in the file */
int WINAPI
GetSectionNames (
		  LPVOID lpFile,
		  char **pszSections)
{
  int nSections = NumOfSections (lpFile);
  int i, nCnt = 0;
  PIMAGE_SECTION_HEADER psh;
  char *ps;


  if (ImageFileType (lpFile) != IMAGE_NT_SIGNATURE ||
      (psh = (PIMAGE_SECTION_HEADER) SECHDROFFSET (lpFile)) == NULL)
    return 0;

  /* count the number of chars used in the section names */
  for (i = 0; i < nSections; i++)
    nCnt += strlen ((char *)psh[i].Name) + 1;

  /* allocate space for all section names from heap */
  ps = *pszSections = (char *) calloc (nCnt, 1);


  for (i = 0; i < nSections; i++)
    {
      strcpy (ps, (char *)psh[i].Name);
      ps += strlen ((char *)psh[i].Name) + 1;
    }

  return nCnt;
}




/* function gets the function header for a section identified by name */
BOOL WINAPI
GetSectionHdrByName (
		      LPVOID lpFile,
		      IMAGE_SECTION_HEADER * sh,
		      char *szSection)
{
  PIMAGE_SECTION_HEADER psh;
  int nSections = NumOfSections (lpFile);
  int i;


  if ((psh = (PIMAGE_SECTION_HEADER) SECHDROFFSET (lpFile)) != NULL)
    {
      /* find the section by name */
      for (i = 0; i < nSections; i++)
	{
	  if (!strcmp ((char *)psh->Name, szSection))
	    {
	      /* copy data to header */
	      bcopy ((LPVOID) psh, (LPVOID) sh, sizeof (IMAGE_SECTION_HEADER));
	      return TRUE;
	    }
	  else
	    psh++;
	}
    }
  return FALSE;
}



//
// This function is modified by sang cho
//
//
/* get import modules names separated by null terminators, return module count */
int WINAPI
GetImportModuleNames (
		       LPVOID lpFile,
		       char **pszModules)
{
  PIMAGE_IMPORT_MODULE_DIRECTORY pid = (PIMAGE_IMPORT_MODULE_DIRECTORY)
  ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
  //
  // sometimes there may be no section for idata or edata
  // instead rdata or data section may contain these sections ..
  // or even module names or function names are in different section.
  // so that's why we need to get actual address of RVAs each time.
  //         ...................sang cho..................
  //
  // PIMAGE_SECTION_HEADER     psh = (PIMAGE_SECTION_HEADER)
  // ImageDirectorySection (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
  // BYTE                  *pData = (BYTE *)pid;
  //      DWORD            *pdw = (DWORD *)pid;
  int nCnt = 0, nSize = 0, i;
  char *pModule[1024];		/* hardcoded maximum number of modules?? */
  char *psz;

  if (pid == NULL)
    return 0;

  // pData = (BYTE *)((int)lpFile + psh->PointerToRawData - psh->VirtualAddress);

  /* extract all import modules */
  while (pid->dwRVAModuleName)
    {
      /* allocate temporary buffer for absolute string offsets */
      //pModule[nCnt] = (char *)(pData + pid->dwRVAModuleName);
      pModule[nCnt] = (char *) GetActualAddress (lpFile, pid->dwRVAModuleName);
      nSize += strlen (pModule[nCnt]) + 1;

      /* increment to the next import directory entry */
      pid++;
      nCnt++;
    }

  /* copy all strings to one chunk of memory */
  *pszModules = (char *) calloc (nSize, 1);
  psz = *pszModules;
  for (i = 0; i < nCnt; i++)
    {
      strcpy (psz, pModule[i]);
      psz += strlen (psz) + 1;
    }
  return nCnt;
}


//
// This function is rewritten by sang cho
//
//
/* get import module function names separated by null terminators, return function count */
int WINAPI
GetImportFunctionNamesByModule (
				 LPVOID lpFile,
				 char *pszModule,
				 char **pszFunctions)
{
  PIMAGE_IMPORT_MODULE_DIRECTORY pid = (PIMAGE_IMPORT_MODULE_DIRECTORY)
  ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
  //
  // sometimes there may be no section for idata or edata
  // instead rdata or data section may contain these sections ..
  // or even module names or function names are in different section.
  // so that's why we need to get actual address each time.
  //         ...................sang cho..................
  //
  //PIMAGE_SECTION_HEADER           psh = (PIMAGE_SECTION_HEADER)
  //ImageDirectorySection (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
  //DWORD                  dwBase;
  int nCnt = 0, nSize = 0;
  int nnid = 0;
  int mnlength, i;
  DWORD dwFunctionName;
  DWORD dwFunctionAddress;
  char name[128];
  char buff[256];		// enough for any string ??

  char *psz;
  DWORD *pdw;

  //dwBase = (DWORD)((int)lpFile + psh->PointerToRawData - psh->VirtualAddress);

  /* find module's pid */
  while (pid->dwRVAModuleName &&
	 strcmp (pszModule, (char *) GetActualAddress (lpFile, pid->dwRVAModuleName)))
    pid++;

  /* exit if the module is not found */
  if (!pid->dwRVAModuleName)
    return 0;

  // I am doing this to get rid of .dll from module name
  strcpy (name, pszModule);
  mnlength = strlen (pszModule);
  for (i = 0; i < mnlength; i++)
    if (name[i] == '.')
      break;
  name[i] = 0;
  mnlength = i;

  /* count number of function names and length of strings */
  dwFunctionName = pid->dwRVAFunctionNameList;

  // IMAGE_IMPORT_BY_NAME OR IMAGE_THUNK_DATA
  // modified by Sang Cho
  while (dwFunctionName &&
	 *(pdw = (DWORD *) GetActualAddress (lpFile, dwFunctionName)))
    {
      if ((*pdw) & 0x80000000)
	nSize += mnlength + 10 + 1 + 6;
      else
	nSize += strlen ((char *) GetActualAddress (lpFile, *pdw + 2)) + 1 + 6;
      dwFunctionName += 4;
      nCnt++;
    }

  /* allocate memory  for function names */
  *pszFunctions = (char *) calloc (nSize, 1);
  psz = *pszFunctions;

  //
  // I modified this part to store function address (4 bytes),
  //                               ord number (2 bytes),
  //                                                      and      name strings (which was there originally)
  // so that's why there are 6 more bytes...... +6,  or +4 and +2 etc.
  // these informations are used where they are needed.
  //                      ...........sang cho..................
  //
  /* copy function names to mempry pointer */
  dwFunctionName = pid->dwRVAFunctionNameList;
  dwFunctionAddress = pid->dwRVAFunctionAddressList;
  while (dwFunctionName &&
	 *(pdw = (DWORD *) GetActualAddress (lpFile, dwFunctionName)))
    {
      if ((*pdw) & 0x80000000)
	{
	  *(int *) psz = (int) (*(DWORD *) GetActualAddress (lpFile, dwFunctionAddress));
	  psz += 4;
	  *(short *) psz = *(short *) pdw;
	  psz += 2;
	  sprintf (buff, "%s:NoName%04d", name, nnid++);
	  strcpy (psz, buff);
	  psz += strlen (buff) + 1;
	}
      else
	{
	  *(int *) psz = (int) (*(DWORD *) GetActualAddress (lpFile, dwFunctionAddress));
	  psz += 4;
	  *(short *) psz = (*(short *) GetActualAddress (lpFile, *pdw));
	  psz += 2;
	  strcpy (psz, (char *) GetActualAddress (lpFile, *pdw + 2));
	  psz += strlen ((char *) GetActualAddress (lpFile, *pdw + 2)) + 1;
	}
      dwFunctionName += 4;
      dwFunctionAddress += 4;
    }

  return nCnt;
}




//
// This function is written by sang cho
//                                                         October 6, 1997
//
/* get numerically expressed string length */
int WINAPI
GetStringLength (
		  char *psz)
{
  if (!isdigit (*psz))
    return 0;
  if (isdigit (*(psz + 1)))
    return (*psz - '0') * 10 + *(psz + 1) - '0';
  else
    return *psz - '0';
}




//
// This function is written by sang cho
//                                                         October 12, 1997
//

/* translate parameter part of condensed name */
void WINAPI
GetPreviousParamString (
			 char *xpin,	// read-only source
			  char *xpout)	// translated result
 {
  int n = 0;
  char *pin, *pout;

  pin = xpin;
  pout = xpout;

  pin--;
  if (*pin == ',')
    pin--;
  else
    {
      printf ("\n **error PreviousParamString1 char = %c", *pin);
      exit (0);
    }

  while (*pin)
    {
      if (*pin == '>')
	n++;
      else if (*pin == '<')
	n--;
      else if (*pin == ')')
	n++;

      if (n > 0)
	{
	  if (*pin == '(')
	    n--;
	}
      else if (strchr (",(", *pin))
	break;
      pin--;
    }

  //printf("\n ----- %s", pin);
  if (strchr (",(", *pin))
    {
      pin++;
    }				// printf("\n %s", pin); }

  else
    {
      printf ("\n **error PreviousParamString2");
      exit (0);
    }

  n = xpin - pin - 1;
  strncpy (pout, pin, n);
  *(pout + n) = 0;
}




//
// This function is written by sang cho
//                                                         October 10, 1997
//

/* translate parameter part of condensed name */
void WINAPI
TranslateParameters (
		      char **ppin,	// read-only source
		       char **ppout,	// translated result
		       char **pps)	// parameter stack
 {
  int i, n;
  char c;
  char name[128];
  char *pin, *pout, *ps;

  //printf(" %c ", **in);
  pin = *ppin;
  pout = *ppout;
  ps = *pps;
  c = *pin;
  switch (c)
    {
      // types processing
    case 'b':
      strcpy (pout, "byte");
      pout += 4;
      pin++;
      break;
    case 'c':
      strcpy (pout, "char");
      pout += 4;
      pin++;
      break;
    case 'd':
      strcpy (pout, "double");
      pout += 6;
      pin++;
      break;
    case 'f':
      strcpy (pout, "float");
      pout += 5;
      pin++;
      break;
    case 'g':
      strcpy (pout, "long double");
      pout += 11;
      pin++;
      break;
    case 'i':
      strcpy (pout, "int");
      pout += 3;
      pin++;
      break;
    case 'l':
      strcpy (pout, "long");
      pout += 4;
      pin++;
      break;
    case 's':
      strcpy (pout, "short");
      pout += 5;
      pin++;
      break;
    case 'v':
      strcpy (pout, "void");
      pout += 4;
      pin++;
      break;
      // postfix processing
    case 'M':
    case 'p':
      if (*(pin + 1) == 'p')
	{
	  *ps++ = 'p';
	  pin += 2;
	}
      else
	{
	  *ps++ = '*';
	  pin++;
	}
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    case 'q':
      *pout++ = '(';
      pin++;
      *ps++ = 'q';
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    case 'r':
      if (*(pin + 1) == 'p')
	{
	  *ps++ = 'r';
	  pin += 2;
	}
      else
	{
	  *ps++ = '&';
	  pin++;
	}
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
      // repeat processing
    case 't':
      if (isdigit (*(pin + 1)))
	{
	  n = *(pin + 1) - '0';
	  pin++;
	  pin++;
	  GetPreviousParamString (pout, name);
	  strcpy (pout, name);
	  pout += strlen (name);
	  for (i = 1; i < n; i++)
	    {
	      *pout++ = ',';
	      strcpy (pout, name);
	      pout += strlen (name);
	    }
	}
      else
	pin++;
      break;
      // prefix processing
    case 'u':
      strcpy (pout, "u");
      pout += 1;
      pin++;
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    case 'x':
      strcpy (pout, "const ");
      pout += 6;
      pin++;
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    case 'z':
      strcpy (pout, "static ");
      pout += 7;
      pin++;
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    default:
      strcpy (pout, "!1!");
      pout += 3;
      *pout++ = *pin++;
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    }
  // need to process postfix finally
  c = *(ps - 1);
  if (strchr ("tqx", c))
    {
      if (*(pin) && !strchr ("@$%", *(pin)))
	*pout++ = ',';
      *ppin = pin;
      *ppout = pout;
      *pps = ps;
      return;
    }
  switch (c)
    {
    case 'r':
      strcpy (pout, "*&");
      pout += 2;
      ps--;
      break;
    case 'p':
      strcpy (pout, "**");
      pout += 2;
      ps--;
      break;
    case '&':
      strcpy (pout, "&");
      pout += 1;
      ps--;
      break;
    case '*':
      strcpy (pout, "*");
      pout += 1;
      ps--;
      break;
    default:
      strcpy (pout, "!2!");
      pout += 3;
      ps--;
      break;
    }
  if (*(pin) && !strchr ("@$%", *(pin)))
    *pout++ = ',';
  *ppin = pin;
  *ppout = pout;
  *pps = ps;
}


//
// This function is written by sang cho
//                                                         October 11, 1997
//

/* translate parameter part of condensed name */
BOOL WINAPI
StringExpands (
		char **ppin,	// read-only source
		 char **ppout,	// translated result
		 char **pps,	// parameter stack
		 Str_P * pcstr)	// currently stored string
 {
//      int         n;
  //      char        c;
  char *pin, *pout, *ps;
  Str_P c_str;
  BOOL stringMode = TRUE;

  pin = *ppin;
  pout = *ppout;
  ps = *pps;
  c_str = *pcstr;

  if (strncmp (pin, "bctr", 4) == 0)
    {
      strncpy (pout, c_str.pos, c_str.length);
      pout += c_str.length;
      pin += 4;
    }
  else if (strncmp (pin, "bdtr", 4) == 0)
    {
      *pout++ = '~';
      strncpy (pout, c_str.pos, c_str.length);
      pout += c_str.length;
      pin += 4;
    }
  else if (*pin == 'o')
    {
      strcpy (pout, "const ");
      pout += 6;
      pin++;
      stringMode = FALSE;
    }
  else if (*pin == 'q')
    {
      *pout++ = '(';
      pin++;
      *ps++ = 'q';
      stringMode = FALSE;
    }
  else if (*pin == 't')
    {
      //if (*(ps-1) == 't') { *pout++ = ','; pin++; }       // this also got me...
      //else                                                                                          october 12  .. sang
      {
	*pout++ = '<';
	pin++;
	*ps++ = 't';
      }
      stringMode = FALSE;
    }
  else if (strncmp (pin, "xq", 2) == 0)
    {
      *pout++ = '(';
      pin += 2;
      *ps++ = 'x';
      *ps++ = 'q';
      stringMode = FALSE;
    }
  else if (strncmp (pin, "bcall", 5) == 0)
    {
      strcpy (pout, "operator ()");
      pout += 11;
      pin += 5;
    }
  else if (strncmp (pin, "bsubs", 5) == 0)
    {
      strcpy (pout, "operator []");
      pout += 11;
      pin += 5;
    }
  else if (strncmp (pin, "bnwa", 4) == 0)
    {
      strcpy (pout, "operator new[]");
      pout += 14;
      pin += 4;
    }
  else if (strncmp (pin, "bdla", 4) == 0)
    {
      strcpy (pout, "operator delete[]");
      pout += 17;
      pin += 4;
    }
  else if (strncmp (pin, "bnew", 4) == 0)
    {
      strcpy (pout, "operator new");
      pout += 12;
      pin += 4;
    }
  else if (strncmp (pin, "bdele", 5) == 0)
    {
      strcpy (pout, "operator delete");
      pout += 15;
      pin += 5;
    }
  else if (strncmp (pin, "blsh", 4) == 0)
    {
      strcpy (pout, "operator <<");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "brsh", 4) == 0)
    {
      strcpy (pout, "operator >>");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "binc", 4) == 0)
    {
      strcpy (pout, "operator ++");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "bdec", 4) == 0)
    {
      strcpy (pout, "operator --");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "badd", 4) == 0)
    {
      strcpy (pout, "operator +");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "brplu", 5) == 0)
    {
      strcpy (pout, "operator +=");
      pout += 11;
      pin += 5;
    }
  else if (strncmp (pin, "bdiv", 4) == 0)
    {
      strcpy (pout, "operator /");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "brdiv", 5) == 0)
    {
      strcpy (pout, "operator /=");
      pout += 11;
      pin += 5;
    }
  else if (strncmp (pin, "bmul", 4) == 0)
    {
      strcpy (pout, "operator *");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "brmul", 5) == 0)
    {
      strcpy (pout, "operator *=");
      pout += 11;
      pin += 5;
    }
  else if (strncmp (pin, "basg", 4) == 0)
    {
      strcpy (pout, "operator =");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "beql", 4) == 0)
    {
      strcpy (pout, "operator ==");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "bneq", 4) == 0)
    {
      strcpy (pout, "operator !=");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "bor", 3) == 0)
    {
      strcpy (pout, "operator |");
      pout += 10;
      pin += 3;
    }
  else if (strncmp (pin, "bror", 4) == 0)
    {
      strcpy (pout, "operator |=");
      pout += 11;
      pin += 4;
    }
  else if (strncmp (pin, "bcmp", 4) == 0)
    {
      strcpy (pout, "operator ~");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "bnot", 4) == 0)
    {
      strcpy (pout, "operator !");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "band", 4) == 0)
    {
      strcpy (pout, "operator &");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "brand", 5) == 0)
    {
      strcpy (pout, "operator &=");
      pout += 11;
      pin += 5;
    }
  else if (strncmp (pin, "bxor", 4) == 0)
    {
      strcpy (pout, "operator ^");
      pout += 10;
      pin += 4;
    }
  else if (strncmp (pin, "brxor", 5) == 0)
    {
      strcpy (pout, "operator ^=");
      pout += 11;
      pin += 5;
    }
  else
    {
      strcpy (pout, "!$$$!");
      pout += 5;
    }
  *ppin = pin;
  *ppout = pout;
  *pps = ps;
  return stringMode;
}				// end of '$' processing



//----------------------------------------------------------------------
// structure to store string tokens
//----------------------------------------------------------------------
//typedef struct _Str_P {
//    char    flag;               // string_flag '@' or '%' or '#'
//    char    *pos;               // starting postion of string
//    int     length;     // length of string
//      BOOL    wasString;    // if it were stringMode or not
//} Str_P;
//----------------------------------------------------------------------
//
// I think I knocked it down finally. But who knows?
//                            october 12, 1997 ... sang
//
// well I have to rewrite whole part of TranslateFunctionName..
// this time I am a little bit more experienced than 5 days ago.
// or am i??? anyway i use stacks instead of recurcive calls
// and i hope this will take care of every symptoms i have experienced..
//                                                        october 10, 1997 .... sang
// It took a lot of time for me to figure out what is all about....
// but still some prefixes like z (static)
//     -- or some types like b (byte) ,g (long double) ,s (short) --
//         -- or postfix  like M ( * )
//     -- or $or ( & ) which is pretty wierd.         .. added.. october 12
//     -- also $t business is quite tricky too. (templates)
//             there may be a lot of things undiscovered yet....
// I am not so sure my interpretation is correct or not
// If I am wrong please let me know.
//                             october 8, 1997 .... sang
//
//
// This function is written by sang cho
//                                                         October 5, 1997
//
/* translate condesed import function name */
char * WINAPI
TranslateFunctionName (
			char *psz)
{


  int i, /*j,*/ n;
  char c = 0;
  char cc;

  static char buff[512];	// result of translation

  int is = 0;
  char pStack[32];		// parameter processing stack

  Str_P sStack[32];		// String processing stack

  Str_P tok;			// String token

  Str_P c_str;			// current string

  int iend = 0;
  char *endTab[8];		// end of string position check

  char *ps;
  char *pin, *pout;
  BOOL stringMode = TRUE;

  if (*psz != '@')
    return psz;
  pin = psz;
  pout = buff;
  ps = pStack;

  //................................................................
  // serious users may need to run the following code.
  // so I may need to include some flag options...
  // If you want to know about how translation is done,
  // you can just revive following line and you can see it.
  //                                                 october 6, 1997 ... sang cho
  //printf ("\n................................... %s", psz); // for debugging...

  //pa = pb = pout;
  pin++;
  tok.flag = 'A';
  tok.pos = pout;
  tok.length = 0;
  tok.wasString = stringMode;
  sStack[is++] = tok;		// initialize sStack with dummy marker

  while (*pin)
    {
      while (*pin)
	{
	  c = *pin;

	  //---------------------------------------------
	  // check for the end of number specified string
	  //---------------------------------------------

	  if (iend > 0)
	    {
	      for (i = 0; i < iend; i++)
		if (pin == endTab[i])
		  break;
	      if (i < iend)
		{
		  // move the end of endTab to ith position
		  endTab[i] = endTab[iend - 1];
		  iend--;

		  // get top of the string stack
		  tok = sStack[is - 1];

		  // I am expecting '#' token from stack
		  if (tok.flag != '#')

		    {
		      printf ("\n**some serious error1** %c is = %d char = %c",
			      tok.flag, is, *pin);
		      exit (0);
		    }

		  // pop '#' token  I am happy now.
		  else
		    {		//if (c)
		      //printf("\n pop # token ... current char = %c", c);
		      //else printf("\n pop percent token..next char = NULL");

		      is--;
		    }

		  stringMode = tok.wasString;

		  if (!stringMode)
		    {
		      // need to process postfix finally
		      cc = *(ps - 1);
		      if (strchr ("qtx", cc))
			{
			  if (!strchr ("@$%", c))
			    *pout++ = ',';
			}
		      else
			{
			  switch (cc)
			    {
			    case 'r':
			      strcpy (pout, "*&");
			      pout += 2;
			      ps--;
			      break;
			    case 'p':
			      strcpy (pout, "**");
			      pout += 2;
			      ps--;
			      break;
			    case '&':
			      strcpy (pout, "&");
			      pout += 1;
			      ps--;
			      break;
			    case '*':
			      strcpy (pout, "*");
			      pout += 1;
			      ps--;
			      break;
			    default:
			      strcpy (pout, "!3!");
			      pout += 3;
			      ps--;
			      break;
			    }
			  if (!strchr ("@$%", c))
			    *pout++ = ',';
			}
		    }
		  // string mode restored...
		  else;
		}
	      else;		// do nothing..

	    }

	  //------------------------------------------------
	  // special control symbol processing:
	  //------------------------------------------------

	  if (strchr ("@$%", c))
	    break;

	  //---------------------------------------------------------------
	  // string part processing : no '$' met yet
	  //                       or inside of '%' block
	  //                       or inside of '#' block (numbered string)
	  //---------------------------------------------------------------

	  else if (stringMode)
	    *pout++ = *pin++;
	  //else if (is > 1)         *pout++ = *pin++;

	  //------------------------------------------------
	  // parameter part processing: '$' met
	  //------------------------------------------------

	  else			// parameter processing

	    {
	      if (!isdigit (c))
		TranslateParameters (&pin, &pout, &ps);
	      else		// number specified string processing

		{
		  n = GetStringLength (pin);
		  if (n < 10)
		    pin++;
		  else
		    pin += 2;

		  // push '#' token
		  //if (*pin)
		  //printf("\n push # token .. char = %c", *pin);
		  //else printf("\n push percent token..next char = NULL");
		  tok.flag = '#';
		  tok.pos = pout;
		  tok.length = 0;
		  tok.wasString = stringMode;
		  sStack[is++] = tok;

		  // mark end of input string
		  endTab[iend++] = pin + n;
		  stringMode = TRUE;
		}
	    }
	}			// end of inner while loop
      //
      // beginning of new string or end of string ( quotation mark )
      //

      if (c == '%')
	{
	  pin++;		// anyway we have to proceed...

	  tok = sStack[is - 1];	// get top of the sStack

	  if (tok.flag == '%')
	    {
	      // pop '%' token and set c_str
	      //if (*pin)
	      //printf("\n pop percent token..next char = %c", *pin);
	      //else printf("\n pop percent token..next char = NULL");
	      is--;
	      c_str = tok;
	      c_str.length = pout - c_str.pos;
	      if (*(ps - 1) == 't')
		{
		  *pout++ = '>';
		  ps--;
		  stringMode = tok.wasString;
		}
	      else
		{
		  printf ("\n**some string error3** stack = %c", *(ps - 1));
		  exit (0);
		}
	    }
	  else if (tok.flag == 'A' || tok.flag == '#')
	    {
	      // push '%' token
	      //if (*pin)
	      //printf("\n push percent token..next char = %c", *pin);
	      //else printf("\n push percent token..next char = NULL");
	      tok.flag = '%';
	      tok.pos = pout;
	      tok.length = 0;
	      tok.wasString = stringMode;
	      sStack[is++] = tok;
	    }
	  else
	    {
	      printf ("\n**some string error5**");
	      exit (0);
	    }
	}
      //
      // sometimes we need string to use as constructor name or destructor name
      //
      else if (c == '@')	// get string from previous marker  upto here.

	{
	  pin++;
	  tok = sStack[is - 1];
	  c_str.flag = 'S';
	  c_str.pos = tok.pos;
	  c_str.length = pout - tok.pos;
	  c_str.wasString = stringMode;
	  *pout++ = ':';
	  *pout++ = ':';
	}
      //
      // we need to take care of parameter control sequence
      //
      else if (c == '$')	// need to precess template or parameter part

	{
	  pin++;
	  if (stringMode)
	    stringMode = StringExpands (&pin, &pout, &ps, &c_str);
	  else
	    {			// template parameter mode I guess  "$t"

	      if (is > 1)
		{
		  if (*pin == 't')
		    pin++;
		  else
		    {
		      printf ("\nMYGOODNESS1 %c", *pin);
		      exit (0);
		    }
		  //ps--;
		  //if (*ps == 't') *pout++ = '>';
		  //else { printf("\nMYGOODNESS2"); exit(0);}
		  *pout++ = ',';	//pin++; ..this almost blowed me....

		}
	      // real parameter mode I guess
	      // unexpected case is found ... humm what can I do...
	      else
		{
		  // this is newly found twist.. it really hurts.
		  if (ps <= pStack)
		    {
		      if (*pin == 'q')
			{
			  *ps++ = 'q';
			  *pout++ = '(';
			  pin++;
			}
		      else
			{
			  printf ("\n** I GIVEUP ***");
			  exit (0);
			}
		      continue;
		    }
		  ps--;
		  while (*ps != 'q')
		    {
		      if (*ps == '*')
			*pout++ = '*';
		      else if (*ps == '&')
			*pout++ = '&';
		      else if (*ps == 'p')
			{
			  *pout++ = '*';
			  *pout++ = '*';
			}
		      else if (*ps == 'r')
			{
			  *pout++ = '*';
			  *pout++ = '&';
			}
		      else
			{
			  printf ("\n*** SOMETHING IS WRONG1*** char= %c", *pin);
			  exit (0);
			}
		      ps--;
		    }
		  *pout++ = ')';
		  ps--;
		  while (*ps != 'q')
		    {
		      if (*ps == '*')
			*pout++ = '*';
		      else if (*ps == '&')
			*pout++ = '&';
		      else if (*ps == 'p')
			{
			  *pout++ = '*';
			  *pout++ = '*';
			}
		      else if (*ps == 'r')
			{
			  *pout++ = '*';
			  *pout++ = '&';
			}
		      else
			{
			  printf ("\n*** SOMETHING IS WRONG2***");
			  exit (0);
			}
		      ps--;
		    }
		  ps++;
		  *pout++ = ',';
		}
	    }
	}			// end of '$' processing

    }				// end of outer while loop
  //
  // need to process remaining parameter stack
  //

  while (ps > pStack)
    {
      ps--;
      switch (*ps)
	{
	case 't':
	  *pout++ = '>';
	  break;
	case 'q':
	  *pout++ = ')';
	  break;
	case 'x':
	  strcpy (pout, " const");
	  pout += 6;
	  break;
	case 'r':
	  strcpy (pout, "*&");
	  pout += 2;
	  break;
	case 'p':
	  strcpy (pout, "**");
	  pout += 2;
	  break;
	case '&':
	  *pout++ = '&';
	  break;
	case '*':
	  *pout++ = '*';
	  break;
	default:
	  strcpy (pout, "!4!");
	  pout += 3;
	  *pout++ = *ps;
	}
    }
  *pout = 0;
  return buff;
}



//
// This function is written by sang cho
//
//
/* get exported function names separated by null terminators, return count of functions */
int WINAPI
GetExportFunctionNames (
			 LPVOID lpFile,
			 char **pszFunctions)
{
  //PIMAGE_SECTION_HEADER      psh;
  PIMAGE_EXPORT_DIRECTORY ped;
  //DWORD                      dwBase;
  DWORD imageBase;		//===========================

  char *pfns[8192] =
  {NULL,};			// maximum number of functions
  //=============================

  char buff[256];		// enough for any string ??

  char *psz = NULL;			//===============================

  DWORD *pdwAddress;
  DWORD *pdw1;
  DWORD *pdwNames;
  WORD *pwOrd;
  int i, nCnt = 0, ntmp = 0;
  int enid = 0, ordBase = 1;	// usally ordBase is 1....

  int enames = 0;

  /* get section header and pointer to data directory for .edata section */
  ped = (PIMAGE_EXPORT_DIRECTORY)
    ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT);

  if (ped == NULL)
    return 0;

  //
  // sometimes there may be no section for idata or edata
  // instead rdata or data section may contain these sections ..
  // or even module names or function names are in different section.
  // so that's why we need to get actual address each time.
  //         ...................sang cho..................
  //
  //psh = (PIMAGE_SECTION_HEADER)
  //ImageDirectorySection(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT);

  //if (psh == NULL) return 0;

  //dwBase = (DWORD)((int)lpFile + psh->PointerToRawData - psh->VirtualAddress);


  /* determine the offset of the export function names */

  pdwAddress = (DWORD *) GetActualAddress (lpFile, (DWORD) ped->AddressOfFunctions);

  imageBase = (DWORD) GetImageBase (lpFile);

  ordBase = ped->Base;

  if (ped->NumberOfNames > 0)
    {
      pdwNames = (DWORD *)
	GetActualAddress (lpFile, (DWORD) ped->AddressOfNames);
      pwOrd = (WORD *)
	GetActualAddress (lpFile, (DWORD) ped->AddressOfNameOrdinals);
      pdw1 = pdwAddress;

      /* figure out how much memory to allocate for all strings */
      for (i = 0; i < (int) ped->NumberOfNames; i++)
	{
	  nCnt += strlen ((char *)
		    GetActualAddress (lpFile, *(DWORD *) pdwNames)) + 1 + 6;
	  pdwNames++;
	}
      // get the number of unnamed functions
      for (i = 0; i < (int) ped->NumberOfFunctions; i++)
	if (*pdw1++)
	  ntmp++;
      // add memory required to show unnamed functions.
      if (ntmp > (int) ped->NumberOfNames)
	nCnt += 18 * (ntmp - (int) ped->NumberOfNames);

      /* allocate memory  for function names */

      *pszFunctions = (char *) calloc (nCnt, 1);
      pdwNames = (DWORD *) GetActualAddress (lpFile, (DWORD) ped->AddressOfNames);

      /* copy string pointer to buffer */

      for (i = 0; i < (int) ped->NumberOfNames; i++)
	{
	  pfns[(int) (*pwOrd) + ordBase] =
	    (char *) GetActualAddress (lpFile, *(DWORD *) pdwNames);
	  pdwNames++;
	  pwOrd++;
	}

      psz = *pszFunctions;
    }

  for (i = ordBase; i < (int) ped->NumberOfFunctions + ordBase; i++)
    {
      if (*pdwAddress > 0)
	{
	  *(DWORD *) psz = imageBase + *pdwAddress;
	  psz += 4;
	  *(WORD *) psz = (WORD) (i);
	  psz += 2;
	  if (pfns[i])
	    {
	      strcpy (psz, pfns[i]);
	      psz += strlen (psz) + 1;
	    }
	  else
	    {
	      sprintf (buff, "ExpFn%04d()", enid++);
	      strcpy (psz, buff);
	      psz += 12;
	    }
	  enames++;
	}
      pdwAddress++;
    }

  return enames;

}


/* determine the total number of resources in the section */
int WINAPI
GetNumberOfResources (
		       LPVOID lpFile)
{
  PIMAGE_RESOURCE_DIRECTORY prdRoot, prdType;
  PIMAGE_RESOURCE_DIRECTORY_ENTRY prde;
  int nCnt = 0, i;


  /* get root directory of resource tree */
  if ((prdRoot = (PIMAGE_RESOURCE_DIRECTORY) ImageDirectoryOffset
       (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
    return 0;

  /* set pointer to first resource type entry */
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ((DWORD) prdRoot + sizeof (IMAGE_RESOURCE_DIRECTORY));

  /* loop through all resource directory entry types */
  for (i = 0; i < prdRoot->NumberOfIdEntries; i++)
    {
      /* locate directory or each resource type */
      prdType = (PIMAGE_RESOURCE_DIRECTORY) ((int) prdRoot + (int) prde->OffsetToData);

      /* mask off most significant bit of the data offset */
      prdType = (PIMAGE_RESOURCE_DIRECTORY) ((DWORD) prdType ^ 0x80000000);

      /* increment count of name'd and ID'd resources in directory */
      nCnt += prdType->NumberOfNamedEntries + prdType->NumberOfIdEntries;

      /* increment to next entry */
      prde++;
    }

  return nCnt;
}



//
// This function is rewritten by sang cho
//
//
/* name each type of resource in the section */
int WINAPI
GetListOfResourceTypes (
			 LPVOID lpFile,
			 char **pszResTypes)
{
  PIMAGE_RESOURCE_DIRECTORY prdRoot;
  PIMAGE_RESOURCE_DIRECTORY_ENTRY prde;
  char *pMem;
  char buff[32];
  int nCnt, i;
  DWORD prdeName;


  /* get root directory of resource tree */
  if ((prdRoot = (PIMAGE_RESOURCE_DIRECTORY) ImageDirectoryOffset
       (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
    return 0;

  /* allocate enuff space  to cover all types */
  nCnt = prdRoot->NumberOfIdEntries * (MAXRESOURCENAME + 1);
  *pszResTypes = (char *) calloc (nCnt, 1);
  if ((pMem = *pszResTypes) == NULL)
    return 0;

  /* set pointer to first resource type entry */
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ((DWORD) prdRoot + sizeof (IMAGE_RESOURCE_DIRECTORY));

  /* loop through all resource directory entry types */
  for (i = 0; i < prdRoot->NumberOfIdEntries; i++)
    {
      prdeName = prde->Name;

      //if (LoadString (hDll, prde->Name, pMem, MAXRESOURCENAME))
      //    pMem += strlen (pMem) + 1;
      //
      // modified by ...................................Sang Cho..
      // I can't user M/S provied funcitons here so I have to figure out
      // how to do above functions. But I can settle down with the following
      // code, which works pretty good for me.
      //
      if (prdeName == 1)
	{
	  strcpy (pMem, "RT_CURSOR");
	  pMem += 10;
	}
      else if (prdeName == 2)
	{
	  strcpy (pMem, "RT_BITMAP");
	  pMem += 10;
	}
      else if (prdeName == 3)
	{
	  strcpy (pMem, "RT_ICON  ");
	  pMem += 10;
	}
      else if (prdeName == 4)
	{
	  strcpy (pMem, "RT_MENU  ");
	  pMem += 10;
	}
      else if (prdeName == 5)
	{
	  strcpy (pMem, "RT_DIALOG");
	  pMem += 10;
	}
      else if (prdeName == 6)
	{
	  strcpy (pMem, "RT_STRING");
	  pMem += 10;
	}
      else if (prdeName == 7)
	{
	  strcpy (pMem, "RT_FONTDIR");
	  pMem += 11;
	}
      else if (prdeName == 8)
	{
	  strcpy (pMem, "RT_FONT  ");
	  pMem += 10;
	}
      else if (prdeName == 9)
	{
	  strcpy (pMem, "RT_ACCELERATORS");
	  pMem += 16;
	}
      else if (prdeName == 10)
	{
	  strcpy (pMem, "RT_RCDATA");
	  pMem += 10;
	}
      else if (prdeName == 11)
	{
	  strcpy (pMem, "RT_MESSAGETABLE");
	  pMem += 16;
	}
      else if (prdeName == 12)
	{
	  strcpy (pMem, "RT_GROUP_CURSOR");
	  pMem += 16;
	}
      else if (prdeName == 14)
	{
	  strcpy (pMem, "RT_GROUP_ICON  ");
	  pMem += 16;
	}
      else if (prdeName == 16)
	{
	  strcpy (pMem, "RT_VERSION");
	  pMem += 11;
	}
      else if (prdeName == 17)
	{
	  strcpy (pMem, "RT_DLGINCLUDE  ");
	  pMem += 16;
	}
      else if (prdeName == 19)
	{
	  strcpy (pMem, "RT_PLUGPLAY    ");
	  pMem += 16;
	}
      else if (prdeName == 20)
	{
	  strcpy (pMem, "RT_VXD   ");
	  pMem += 10;
	}
      else if (prdeName == 21)
	{
	  strcpy (pMem, "RT_ANICURSOR   ");
	  pMem += 16;
	}
      else if (prdeName == 22)
	{
	  strcpy (pMem, "RT_ANIICON");
	  pMem += 11;
	}
      else if (prdeName == 0x2002)
	{
	  strcpy (pMem, "RT_NEWBITMAP");
	  pMem += 13;
	}
      else if (prdeName == 0x2004)
	{
	  strcpy (pMem, "RT_NEWMENU");
	  pMem += 11;
	}
      else if (prdeName == 0x2005)
	{
	  strcpy (pMem, "RT_NEWDIALOG");
	  pMem += 13;
	}
      else if (prdeName == 0x7fff)
	{
	  strcpy (pMem, "RT_ERROR ");
	  pMem += 10;
	}
      else
	{
	  sprintf (buff, "RT_UNKNOWN:%08lX", prdeName);
	  strcpy (pMem, buff);
	  pMem += 20;
	}
      prde++;
    }

  return prdRoot->NumberOfIdEntries;
}



//
// This function is written by sang cho
//                                                         October 12, 1997
//
/* copy menu information */
void WINAPI
StrangeMenuFill (
		  char **psz,	// results
		   WORD ** pMenu,	// read-only
		   int size)
{
  WORD *pwd;
  WORD *ptr, *pmax;

  pwd = *pMenu;
  pmax = (WORD *) ((DWORD) pwd + size);
  ptr = (WORD *) (*psz);

  while (pwd < pmax)
    {
      *ptr++ = *pwd++;
    }
  *psz = (char *) ptr;
  *pMenu = pwd;
}



//
// This function is written by sang cho
//                                                         October 1, 1997
//
/* obtain menu information */
int WINAPI
MenuScan (
	   int *len,
	   WORD ** pMenu)
{
  //int num = 0;
  //int ndetails;
  WORD *pwd;
  WORD flag, flag1;
  WORD id, ispopup;


  pwd = *pMenu;

  flag = *pwd;			// so difficult to correctly code this so let's try this

  pwd++;
  (*len) += 2;			// flag store

  if ((flag & 0x0010) == 0)
    {
      ispopup = flag;
      id = *pwd;
      pwd++;
      (*len) += 2;		// id store

    }
  else
    {
      ispopup = flag;
    }

  while (*pwd)
    {
      (*len)++;
      pwd++;
    }
  (*len)++;			// name and null character

  pwd++;			// skip double null

  if ((flag & 0x0010) == 0)	// normal node: done

    {
      *pMenu = pwd;
      return (int) flag;
    }
  // popup node: need to go on...
  while (1)
    {
      *pMenu = pwd;
      flag1 = (WORD) MenuScan (len, pMenu);
      pwd = *pMenu;
      if (flag1 & 0x0080)
	break;
    }
//  fill # of details to num above
  //(*len) += 2;
  *pMenu = pwd;
  return flag;
}


//
// This function is written by sang cho
//                                                         October 2, 1997
//
/* copy menu information */
int WINAPI
MenuFill (
	   char **psz,
	   WORD ** pMenu)
{
  //int num = 0;
  //int ndetails;
  char *ptr/*, *pTemp*/;
  WORD *pwd;
  WORD flag, flag1;
  WORD id/*, ispopup*/;

  ptr = *psz;
  pwd = *pMenu;
  //flag = (*(PIMAGE_POPUP_MENU_ITEM *)pwd)->fItemFlags;
  flag = *pwd;			// so difficult to correctly code this so let's try this

  pwd++;
  if ((flag & 0x0010) == 0)
    {
      *(WORD *) ptr = flag;	// flag store

      ptr += 2;
      *(WORD *) ptr = id = *pwd;	// id store

      ptr += 2;
      pwd++;
    }
  else
    {
      *(WORD *) ptr = flag;	// flag store

      ptr += 2;
    }

  while (*pwd)			// name extract

    {
      *ptr = *(char *) pwd;
      ptr++;
      pwd++;
    }				//name and null character

  *ptr = 0;
  ptr++;
  pwd++;			// skip double null

  if ((flag & 0x0010) == 0)	// normal node: done

    {
      *pMenu = pwd;
      *psz = ptr;
      return (int) flag;
    }
  //pTemp = ptr;
  //ptr += 2;
  // popup node: need to go on...
  while (1)
    {
      //num++;
      *pMenu = pwd;
      *psz = ptr;
      flag1 = (WORD) MenuFill (psz, pMenu);
      pwd = *pMenu;
      ptr = *psz;
      if (flag1 & 0x0080)
	break;
    }
//  fill # of details to num above
  //*(WORD *)pTemp = (WORD)num;
  *pMenu = pwd;
  *psz = ptr;
  return flag;
}


//
//==============================================================================
// The following program is based on preorder-tree-traversal.
// once you understand how to traverse.....
// the rest is pretty straight forward.
// still we need to scan it first and fill it next time.
// and finally we can print it.
//
// This function is written by sang cho
//                                                         September 29, 1997
//                                                         revised october 2, 1997
//                             revised october 12, 1997
// ..............................................................................
// ------------------------------------------------------------------------------
// I use same structure - which is used in P.E. programs - for my reporting.
// So, my structure is as follows:
//        # of menu name is stored else where ( in directory I suppose )
//     supermenuname                    null terminated string, only ascii is considered.
//         flag                 tells : node is a leaf or a internal node.
//         popupname                    null terminated string
//
//              flag                normal menu flag (leaf node)
//                      id                                  normal menu id
//              name                    normal menu name
//         or                            or
//              flag                        popup menu flag (internal node)
//              popupname                   popup menu name
//
//                 flag                             it may folows
//                         id                                   normal menu id
//                 name                                 normal menu name
//             or                                 or
//                 flag                                 popup menu
//                 popupname                    popup menu name
//                                 .........
//                                it goes on like this,
//                                 but usually, it only goes a few steps,...
// ------------------------------------------------------------------------------
/* scan menu and copy menu */
int WINAPI
GetContentsOfMenu (
		    LPVOID lpFile,
		    char **pszResTypes)
{
  PIMAGE_RESOURCE_DIRECTORY prdType, prdName, prdLanguage;
  PIMAGE_RESOURCE_DIRECTORY_ENTRY prde, prde1;
  PIMAGE_RESOURCE_DIR_STRING_U pMenuName;
  PIMAGE_RESOURCE_DATA_ENTRY prData;
  //PIMAGE_SECTION_HEADER              psh = (PIMAGE_SECTION_HEADER)
  //ImageDirectorySection (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE);
  PIMAGE_MENU_HEADER pMenuHeader;
  //PIMAGE_POPUP_MENU_ITEM pPopup;
  WORD* pPopup;
  //PIMAGE_NORMAL_MENU_ITEM pNormal;
  char buff[32];
  int /*nCnt = 0,*/ i, j;
  //int num = 0;
  int size;
  int sLength, nMenus;
  WORD flag;
  WORD *pwd;
  //DWORD prdeName;
  //DWORD                   dwBase;    obsolete
  char *pMem/*, *pTemp*/;
  //BOOL isStrange = FALSE;


  /* get root directory of resource tree */
  if ((prdType = (PIMAGE_RESOURCE_DIRECTORY) ImageDirectoryOffset
       (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
    return 0;

  /* set pointer to first resource type entry */
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
    ((DWORD) prdType + sizeof (IMAGE_RESOURCE_DIRECTORY));

  for (i = 0; i < prdType->NumberOfIdEntries; i++)
    {
      if (prde->Name == RT_MENU)
	break;
      prde++;
    }
  if (prde->Name != RT_MENU)
    return 0;

  prdName = (PIMAGE_RESOURCE_DIRECTORY)
    ((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
  if (prdName == NULL)
    return 0;

  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
    ((DWORD) prdName + sizeof (IMAGE_RESOURCE_DIRECTORY));

  // sometimes previous code tells you lots of things hidden underneath
  // I wish I could save all the revisions I made ... but again .... sigh.
  //                                  october 12, 1997    sang
  //dwBase = (DWORD)((int)lpFile + psh->PointerToRawData - psh->VirtualAddress);

  nMenus = prdName->NumberOfNamedEntries + prdName->NumberOfIdEntries;
  sLength = 0;

  for (i = 0; i < prdName->NumberOfNamedEntries; i++)
    {
      pMenuName = (PIMAGE_RESOURCE_DIR_STRING_U)
	((DWORD) prdType + (prde->Name ^ 0x80000000));
      sLength += pMenuName->Length + 1;

      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      pMenuHeader = (PIMAGE_MENU_HEADER)
	GetActualAddress (lpFile, prData->OffsetToData);

      //
      // normally wVersion and cbHeaderSize should be zero
      // but if it is not then nothing is known to us...
      // so let's do our best ... namely guessing .... and trying ....
      //                      ... and suffering   ...
      // it gave me many sleepless (not exactly but I like to say this) nights.
      //

      // strange case
      if (pMenuHeader->wVersion | pMenuHeader->cbHeaderSize)
	{
	  //isStrange = TRUE;
	  pwd = (WORD *) ((DWORD) pMenuHeader + 16);
	  size = prData->Size;
	  // expect to return the length needed to report.
	  // sixteen more bytes to do something
	  sLength += 16 + size;
	  //StrangeMenuScan (&sLength, &pwd, size);
	}
      // normal case
      else
	{
	  pPopup = (WORD*)
	    ((DWORD) pMenuHeader + sizeof (IMAGE_MENU_HEADER));
	  while (1)
	    {
	      flag = (WORD) MenuScan (&sLength, (WORD **) (&pPopup));
	      if (flag & 0x0080)
		break;
	    }
	}
      prde++;
    }
  for (i = 0; i < prdName->NumberOfIdEntries; i++)
    {
      sLength += 12;

      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      pMenuHeader = (PIMAGE_MENU_HEADER)
	GetActualAddress (lpFile, prData->OffsetToData);
      // strange case
      if (pMenuHeader->wVersion | pMenuHeader->cbHeaderSize)
	{
	  pwd = (WORD *) ((DWORD) pMenuHeader + 16);
	  size = prData->Size;
	  // expect to return the length needed to report.
	  // sixteen more bytes to do something
	  sLength += 16 + size;
	  //StrangeMenuScan (&sLength, &pwd, size);
	}
      // normal case
      else
	{
	  pPopup = (WORD*)
	    ((DWORD) pMenuHeader + sizeof (IMAGE_MENU_HEADER));
	  while (1)
	    {
	      flag = (WORD) MenuScan (&sLength, (WORD **) (&pPopup));
	      if (flag & 0x0080)
		break;
	    }
	}
      prde++;
    }
  //
  // allocate memory for menu names
  //
  *pszResTypes = (char *) calloc (sLength, 1);

  pMem = *pszResTypes;
  //
  // and start all over again
  //
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
    ((DWORD) prdName + sizeof (IMAGE_RESOURCE_DIRECTORY));

  for (i = 0; i < prdName->NumberOfNamedEntries; i++)
    {
      pMenuName = (PIMAGE_RESOURCE_DIR_STRING_U)
	((DWORD) prdType + (prde->Name ^ 0x80000000));


      for (j = 0; j < pMenuName->Length; j++)
	*pMem++ = (char) (pMenuName->NameString[j]);
      *pMem = 0;
      pMem++;


      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      pMenuHeader = (PIMAGE_MENU_HEADER)
	GetActualAddress (lpFile, prData->OffsetToData);
      // strange case
      if (pMenuHeader->wVersion | pMenuHeader->cbHeaderSize)
	{
	  pwd = (WORD *) ((DWORD) pMenuHeader);
	  size = prData->Size;
	  strcpy (pMem, ":::::::::::");
	  pMem += 12;
	  *(int *) pMem = size;
	  pMem += 4;
	  StrangeMenuFill (&pMem, &pwd, size);
	}
      // normal case
      else
	{
	  pPopup = (WORD*)
	    ((DWORD) pMenuHeader + sizeof (IMAGE_MENU_HEADER));
	  while (1)
	    {
	      flag = (WORD) MenuFill (&pMem, (WORD **) (&pPopup));
	      if (flag & 0x0080)
		break;
	    }
	}
      prde++;
    }
  for (i = 0; i < prdName->NumberOfIdEntries; i++)
    {

      sprintf (buff, "MenuId_%04lX", (prde->Name));
      strcpy (pMem, buff);
      pMem += strlen (buff) + 1;

      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      pMenuHeader = (PIMAGE_MENU_HEADER)
	GetActualAddress (lpFile, prData->OffsetToData);
      // strange case
      if (pMenuHeader->wVersion | pMenuHeader->cbHeaderSize)
	{
	  pwd = (WORD *) ((DWORD) pMenuHeader);
	  size = prData->Size;
	  strcpy (pMem, ":::::::::::");
	  pMem += 12;
	  *(int *) pMem = size;
	  pMem += 4;
	  StrangeMenuFill (&pMem, &pwd, size);
	}
      // normal case
      else
	{
	  pPopup = (WORD*)
	    ((DWORD) pMenuHeader + sizeof (IMAGE_MENU_HEADER));
	  while (1)
	    {
	      flag = (WORD) MenuFill (&pMem, (WORD **) (&pPopup));
	      if (flag & 0x0080)
		break;
	    }
	}
      prde++;
    }

  return nMenus;
}


//
// This function is written by sang cho
//                                                         October 12, 1997
//
/* print contents of menu */
int WINAPI
PrintStrangeMenu (
		   char **psz)
{

  //int i, j, k, l;
  int num;
  //WORD flag1, flag2;
  //char buff[128];
  char *ptr, *pmax;

  //return dumpMenu (psz, size);

  ptr = *psz;

  if (strncmp (ptr, ":::::::::::", 11) != 0)
    {
      printf ("\n#### I don't know why!!!");
      dumpMenu (psz, 1024);
      exit (0);
    }

  ptr += 12;
  num = *(int *) ptr;
  ptr += 4;
  pmax = ptr + num;

  *psz = ptr;
  return dumpMenu (psz, num);

  // I will write some code later...

}




//
// This function is written by sang cho
//                                                         October 2, 1997
//
/* print contents of menu */
int WINAPI
PrintMenu (
	    int indent,
	    char **psz)
{

  int /*i, */ j, k, l;
  WORD id /*, num */ ;
  WORD flag;
  char buff[128];
  char *ptr;


  ptr = *psz;
  //num = *(WORD *)ptr;
  //ptr += 2;
  while (1)
    {
      flag = *(WORD *) ptr;
      if (flag & 0x0010)	// flag == popup

	{
	  printf ("\n\n");
	  for (j = 0; j < indent; j++)
	    printf (" ");
	  ptr += 2;
	  printf ("%s  {Popup}\n", ptr);
	  ptr += strlen (ptr) + 1;
	  *psz = ptr;
	  PrintMenu (indent + 5, psz);
	  ptr = *psz;
	}
      else			// ispopup == 0

	{
	  printf ("\n");
	  for (j = 0; j < indent; j++)
	    printf (" ");
	  ptr += 2;
	  id = *(WORD *) ptr;
	  ptr += 2;
	  strcpy (buff, ptr);
	  l = strlen (ptr);
	  ptr += l + 1;
	  if (strchr (buff, 0x09) != NULL)
	    {
	      for (k = 0; k < l; k++)
		if (buff[k] == 0x09)
		  break;
	      for (j = 0; j < l - k; j++)
		buff[31 - j] = buff[l - j];
	      for (j = k; j < 32 + k - l; j++)
		buff[j] = 32;
	    }
	  if (strchr (buff, 0x08) != NULL)
	    {
	      for (k = 0; k < l; k++)
		if (buff[k] == 0x08)
		  break;
	      for (j = 0; j < l - k; j++)
		buff[31 - j] = buff[l - j];
	      for (j = k; j < 32 + k - l; j++)
		buff[j] = 32;
	    }
	  printf ("%s", buff);
	  l = strlen (buff);
	  for (j = l; j < 32; j++)
	    printf (" ");
	  printf ("[ID=%04Xh]", id);
	  *psz = ptr;
	}
      if (flag & 0x0080)
	break;
    }
  return 0;
}


//
// This function is written by sang cho
//                                                         October 2, 1997
//
/* the format of menu is not known so I'll do my best */
int WINAPI
dumpMenu (
	   char **psz,
	   int size)
{

  int i, j, k, n, l, c;
  char buff[32];
  char *ptr, *pmax;

  ptr = *psz;
  pmax = ptr + size;
  for (i = 0; i < (size / 16) + 1; i++)
    {
      n = 0;
      for (j = 0; j < 16; j++)
	{
	  c = (int) (*ptr);
	  if (c < 0)
	    c += 256;
	  buff[j] = c;
	  printf ("%02X", c);
	  ptr++;
	  if (ptr >= pmax)
	    break;
	  n++;
	  if (n % 4 == 0)
	    printf (" ");
	}
      n++;
      if (n % 4 == 0)
	printf (" ");
      l = j;
      j++;
      for (; j < 16; j++)
	{
	  n++;
	  if (n % 4 == 0)
	    printf ("   ");
	  else
	    printf ("  ");
	}
      printf ("   ");
      for (k = 0; k < l; k++)
	if (isprint (c = buff[k]))
	  printf ("%c", c);
	else
	  printf (".");
      printf ("\n");
      if (ptr >= pmax)
	break;
    }

  *psz = ptr;
  return 0;
}




//
// This function is written by sang cho
//                                                         October 13, 1997
//
/* scan dialog box and copy dialog box */
int WINAPI
GetContentsOfDialog (
		      LPVOID lpFile,
		      char **pszResTypes)
{
  PIMAGE_RESOURCE_DIRECTORY prdType, prdName, prdLanguage;
  PIMAGE_RESOURCE_DIRECTORY_ENTRY prde, prde1;
  PIMAGE_RESOURCE_DIR_STRING_U pDialogName;
  PIMAGE_RESOURCE_DATA_ENTRY prData;
  PIMAGE_DIALOG_HEADER pDialogHeader;
  //PIMAGE_CONTROL_DATA pControlData;
  char buff[32];
  int /*nCnt = 0,*/ i, j;
  //int num = 0;
  int size;
  int sLength, nDialogs;
  //WORD flag;
  WORD *pwd;
  //DWORD prdeName;
  char *pMem/*, *pTemp*/;
  //BOOL isStrange = FALSE;


  /* get root directory of resource tree */
  if ((prdType = (PIMAGE_RESOURCE_DIRECTORY) ImageDirectoryOffset
       (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
    return 0;

  /* set pointer to first resource type entry */
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
    ((DWORD) prdType + sizeof (IMAGE_RESOURCE_DIRECTORY));

  for (i = 0; i < prdType->NumberOfIdEntries; i++)
    {
      if (prde->Name == RT_DIALOG)
	break;
      prde++;
    }
  if (prde->Name != RT_DIALOG)
    return 0;

  prdName = (PIMAGE_RESOURCE_DIRECTORY)
    ((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
  if (prdName == NULL)
    return 0;

  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
    ((DWORD) prdName + sizeof (IMAGE_RESOURCE_DIRECTORY));


  nDialogs = prdName->NumberOfNamedEntries + prdName->NumberOfIdEntries;
  sLength = 0;

  for (i = 0; i < prdName->NumberOfNamedEntries; i++)
    {
      pDialogName = (PIMAGE_RESOURCE_DIR_STRING_U)
	((DWORD) prdType + (prde->Name ^ 0x80000000));
      sLength += pDialogName->Length + 1;

      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      size = prData->Size;
      sLength += 4 + size;
      prde++;
    }
  for (i = 0; i < prdName->NumberOfIdEntries; i++)
    {
      sLength += 14;

      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      size = prData->Size;
      sLength += 4 + size;
      prde++;
    }
  //
  // allocate memory for menu names
  //
  *pszResTypes = (char *) calloc (sLength, 1);

  pMem = *pszResTypes;
  //
  // and start all over again
  //
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
    ((DWORD) prdName + sizeof (IMAGE_RESOURCE_DIRECTORY));

  for (i = 0; i < prdName->NumberOfNamedEntries; i++)
    {
      pDialogName = (PIMAGE_RESOURCE_DIR_STRING_U)
	((DWORD) prdType + (prde->Name ^ 0x80000000));


      for (j = 0; j < pDialogName->Length; j++)
	*pMem++ = (char) (pDialogName->NameString[j]);
      *pMem = 0;
      pMem++;


      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	continue;

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	continue;

      pDialogHeader = (PIMAGE_DIALOG_HEADER)
	GetActualAddress (lpFile, prData->OffsetToData);



      pwd = (WORD *) ((DWORD) pDialogHeader);
      size = prData->Size;
      *(int *) pMem = size;
      pMem += 4;
      StrangeMenuFill (&pMem, &pwd, size);

      prde++;
    }
  for (i = 0; i < prdName->NumberOfIdEntries; i++)
    {

      sprintf (buff, "DialogId_%04lX", (prde->Name));
      strcpy (pMem, buff);
      pMem += strlen (buff) + 1;

      prdLanguage = (PIMAGE_RESOURCE_DIRECTORY)
	((DWORD) prdType + (prde->OffsetToData ^ 0x80000000));
      if (prdLanguage == NULL)
	{
	  printf ("\nprdLanguage = NULL");
	  exit (0);
	}

      prde1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
	((DWORD) prdLanguage + sizeof (IMAGE_RESOURCE_DIRECTORY));

      prData = (PIMAGE_RESOURCE_DATA_ENTRY)
	((DWORD) prdType + prde1->OffsetToData);
      if (prData == NULL)
	{
	  printf ("\nprData = NULL");
	  exit (0);
	}

      pDialogHeader = (PIMAGE_DIALOG_HEADER)
	GetActualAddress (lpFile, prData->OffsetToData);


      pwd = (WORD *) ((DWORD) pDialogHeader);
      size = prData->Size;
      *(int *) pMem = size;
      pMem += 4;
      StrangeMenuFill (&pMem, &pwd, size);

      prde++;
    }

  return nDialogs;
}


//
// This function is written by sang cho
//                                                         October 14, 1997
//
/* print contents of dialog */
void WINAPI
PrintNameOrOrdinal (
		     char **psz)
{
  char *ptr;

  ptr = *psz;
  if (*(WORD *) ptr == 0xFFFF)
    {
      ptr += 2;
      printf ("%04X", *(WORD *) ptr);
      ptr += 2;
    }
  else
    {
      printf ("%c", '"');
      while (*(WORD *) ptr)
	{
	  printf ("%c", *ptr);
	  ptr += 2;
	}
      ptr += 2;
      printf ("%c", '"');
    }
  *psz = ptr;
}


//
// This function is written by sang cho
//                                                         October 14, 1997
//
/* print contents of dialog */
void WINAPI
PrintDialog (
	      char **psz)
{
  int i/*, j, k, l, n, c*/;
  int num, size;
  DWORD flag;
  WORD class;
  //char buff[32];
  char *ptr, *pmax;
  BOOL isStrange = FALSE;

  ptr = *psz;
  size = *(int *) ptr;
  ptr += 4;
  pmax = ptr + size;

  // IStype of Dialog Header
  flag = *(DWORD *) ptr;
  //
  // check if flag is right or not
  // it has been observed that some dialog information is strange
  // and extra work is needed to fix that ... so let's try something
  //

  if ((flag & 0xFFFF0000) == 0xFFFF0000)
    {
      flag = *(DWORD *) (ptr + 12);
      num = *(short *) (ptr + 16);
      isStrange = TRUE;
      ptr += 26;
    }
  else
    {
      num = *(short *) (ptr + 8);
      ptr += 18;
    }
  printf (", # of Controls=%03d, Caption:%c", num, '"');

  // Menu name
  if (*(WORD *) ptr == 0xFFFF)
    ptr += 4;			// ordinal

  else
    {
      while (*(WORD *) ptr)
	ptr += 2;
      ptr += 2;
    }				// name

  // Class name
  if (*(WORD *) ptr == 0xFFFF)
    ptr += 4;			// ordinal

  else
    {
      while (*(WORD *) ptr)
	ptr += 2;
      ptr += 2;
    }				// name

  // Caption
  while (*(WORD *) ptr)
    {
      printf ("%c", *ptr);
      ptr += 2;
    }
  ptr += 2;
  printf ("%c", '"');

  // FONT present
  if (flag & 0x00000040)
    {
      if (isStrange)
	ptr += 6;
      else
	ptr += 2;		// FONT size

      while (*(WORD *) ptr)
	ptr += 2;		// WCHARs

      ptr += 2;			// double null

    }

  // strange case adjust
  if (isStrange)
    ptr += 8;

  // DWORD padding
  if ((ptr - *psz) % 4)
    ptr += 4 - ((ptr - *psz) % 4);

  // start reporting .. finally
  for (i = 0; i < num; i++)
    {
      flag = *(DWORD *) ptr;
      if (isStrange)
	ptr += 14;
      else
	ptr += 16;
      printf ("\n     Control::%03d - ID:", i + 1);

      // Control ID
      printf ("%04X, Class:", *(WORD *) ptr);
      ptr += 2;

      // Control Class
      if (*(WORD *) ptr == 0xFFFF)
	{
	  ptr += 2;
	  class = *(WORD *) ptr;
	  ptr += 2;
	  switch (class)
	    {
	    case 0x80:
	      printf ("BUTTON   ");
	      break;
	    case 0x81:
	      printf ("EDIT     ");
	      break;
	    case 0x82:
	      printf ("STATIC   ");
	      break;
	    case 0x83:
	      printf ("LISTBOX  ");
	      break;
	    case 0x84:
	      printf ("SCROLLBAR");
	      break;
	    case 0x85:
	      printf ("COMBOBOX ");
	      break;
	    default:
	      printf ("%04X     ", class);
	      break;
	    }
	}
      else
	PrintNameOrOrdinal (&ptr);

      printf (" Text:");

      // Text
      PrintNameOrOrdinal (&ptr);

      // nExtraStuff
      ptr += 2;

      // strange case adjust
      if (isStrange)
	ptr += 8;

      // DWORD padding
      if ((ptr - *psz) % 4)
	ptr += 4 - ((ptr - *psz) % 4);
    }

  /*
     ptr = *psz;
     printf("\n");

     for (i=0; i<(size/16)+1; i++)
     {
     n = 0;
     for (j=0; j<16; j++)
     {
     c = (int)(*ptr);
     if (c<0) c+=256;
     buff[j] = c;
     printf ("%02X",c);
     ptr++;
     if (ptr >= pmax) break;
     n++;
     if (n%4 == 0) printf (" ");
     }
     n++; if (n%4 == 0) printf (" ");
     l = j;
     j++;
     for (; j<16; j++)
     { n++; if (n%4 == 0) printf ("   "); else printf ("  "); }
     printf ("   ");
     for (k=0; k<l; k++)
     if (isprint(c=buff[k])) printf("%c", c); else printf(".");
     printf ("\n");
     if (ptr >= pmax) break;
     }
   */

  *psz = pmax;

}






/* function indicates whether debug  info has been stripped from file */
BOOL WINAPI
IsDebugInfoStripped (
		      LPVOID lpFile)
{
  PIMAGE_FILE_HEADER pfh;

  pfh = (PIMAGE_FILE_HEADER) PEFHDROFFSET (lpFile);

  return (pfh->Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
}




/* retrieve the module name from the debug misc. structure */
int WINAPI
RetrieveModuleName (
		     LPVOID lpFile,
		     char **pszModule)
{

  PIMAGE_DEBUG_DIRECTORY pdd;
  PIMAGE_DEBUG_MISC pdm = NULL;
  int nCnt;

  if (!(pdd = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_DEBUG)))
    return 0;

  while (pdd->SizeOfData)
    {
      if (pdd->Type == IMAGE_DEBUG_TYPE_MISC)
	{
	  pdm = (PIMAGE_DEBUG_MISC) ((DWORD) pdd->PointerToRawData + (DWORD) lpFile);
	  *pszModule = (char *) calloc ((nCnt = (strlen ((char *)pdm->Data))) + 1, 1);
	  // may need some unicode business here...above
	  bcopy (pdm->Data, *pszModule, nCnt);

	  break;
	}

      pdd++;
    }

  if (pdm != NULL)
    return nCnt;
  else
    return 0;
}





/* determine if this is a valid debug file */
BOOL WINAPI
IsDebugFile (
	      LPVOID lpFile)
{
  PIMAGE_SEPARATE_DEBUG_HEADER psdh;

  psdh = (PIMAGE_SEPARATE_DEBUG_HEADER) lpFile;

  return (psdh->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE);
}




/* copy separate debug header structure from debug file */
BOOL WINAPI
GetSeparateDebugHeader (
			 LPVOID lpFile,
			 PIMAGE_SEPARATE_DEBUG_HEADER psdh)
{
  PIMAGE_SEPARATE_DEBUG_HEADER pdh;

  pdh = (PIMAGE_SEPARATE_DEBUG_HEADER) lpFile;

  if (pdh->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
    {
      bcopy ((LPVOID) pdh, (LPVOID) psdh, sizeof (IMAGE_SEPARATE_DEBUG_HEADER));
      return TRUE;
    }

  return FALSE;
}

//
// I tried to immitate the output of w32dasm disassembler.
// which is a pretty good program.
// but I am disappointed with this program and I myself
// am writting a disassembler.
// This PEdump program is a byproduct of that project.
// so enjoy this program and I hope we will have a little more
// knowledge on windows programming world.
//                                                        .... sang cho

#define  MAXSECTIONNUMBER 16
#define  MAXNAMESTRNUMBER 40
int
main (
       int argc,
       char **argv
)
{
  DWORD fileType;
  LPVOID lpFile;
  FILE *my_fp;
  IMAGE_DOS_HEADER dosHdr;
  PIMAGE_FILE_HEADER pfh;
  PIMAGE_OPTIONAL_HEADER poh;
  PIMAGE_SECTION_HEADER psh;
  //IMAGE_SECTION_HEADER idsh;
  IMAGE_SECTION_HEADER shdr[MAXSECTIONNUMBER];
  //PIMAGE_IMPORT_MODULE_DIRECTORY pid;

  int nSections;		// number of sections

  int nResources;		// number of resources

  int nMenus;			// number of menus

  int nDialogs;			// number of dialogs

  int nImportedModules;		// number of imported modules

  int nFunctions;		// number of functions in the imported module

  int nExportedFunctions;	// number of exported funcions

  int imageBase;
  int entryPoint;

  int i, j, /*k,*/ n;
  //int mnsize;
  //int nCnt;
  //int nSize;
  int fsize;
  char *pnstr;
  char *pst;
  char *piNameBuff;		// import module name buffer

  char *pfNameBuff;		// import functions in the module name buffer

  char *peNameBuff;		// export function name buffer

  char *pmNameBuff;		// menu name buffer

  char *pdNameBuff;		// dialog name buffer

  /*
   * Check user arguments.
   */
  if (2 == argc)
    {
      my_fp = fopen (argv[1], "rb");
      if (my_fp == NULL)
	{
	  printf (
		   "%s: can not open input file \"%s\".\n",
		   argv[0],
		   argv[1]
	    );
	  exit (0);
	}
    }
  else
    {
      printf (
	       "%s - PE/COFF file dumper\n"
	       "Copyright (c) 1993 Randy Kath (MSDN Technology Group)\n"
      "Copyright (c) 1997 Sang Cho (CS & Engineering - Chongju University)\n"
      "Copyright (c) 2000 Emanuele Aliberti (ReactOS Development Team)\n\n",
	       argv[0]
	);
      printf (
	       "usage: %s input_file_name\n",
	       argv[0]
	);
      exit (0);
    }
  /*
   * Get input file's size.
   */
  /* argv [0], */
  fseek (my_fp, 0L, SEEK_END);
  fsize = ftell (my_fp);
  rewind (my_fp);
  /*
   * Buffer the file in memory.
   */
  lpFile = (void *) calloc (fsize, 1);
  if (lpFile == NULL)
    {
      printf (
	       "%s: can not allocate memory.\n",
	       argv[0]
	);
      fclose(my_fp);
      exit (0);
    }
  /*
   * --- Start of report ---
   */
  printf ("\n\nDump of file: %s\n\n", argv[1]);

  n = fread (lpFile, fsize, 1, my_fp);
  fclose(my_fp);

  if (n == -1)
    {
      printf (
	       "%s: failed to read the file \"%s\".\n",
	       argv[0],
	       argv[1]
	);
      free(lpFile);
      exit (0);
    }

  GetDosHeader (lpFile, &dosHdr);

  if ((WORD) IMAGE_DOS_SIGNATURE == dosHdr.e_magic)
    {
      if ((dosHdr.e_lfanew > 4096)
	  || (dosHdr.e_lfanew < 64)
	)
	{
	  printf (
		   "%s: This file is not in PE format; it looks like in DOS format.\n",
		   argv[0]
	    );
      free(lpFile);
	  exit (0);
	}
    }
  else
    {
      printf (
	"%s: This doesn't look like an executable file (magic = 0x%04x).\n",
	       argv[0],
	       dosHdr.e_magic
	);
      free(lpFile);
      exit (0);
    }

  fileType = ImageFileType (lpFile);

  if (fileType != IMAGE_NT_SIGNATURE)
    {
      printf (
	       "%s: This file is not in PE format (magic = 0x%08lx).\n",
	       argv[0],
	       fileType
	);
      free(lpFile);
      exit (0);
    }

  //=====================================
  // now we can really start processing
  //=====================================

  pfh = (PIMAGE_FILE_HEADER) PEFHDROFFSET (lpFile);

  poh = (PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (lpFile);

  psh = (PIMAGE_SECTION_HEADER) SECHDROFFSET (lpFile);

  nSections = pfh->NumberOfSections;

  imageBase = poh->ImageBase;

  entryPoint = poh->AddressOfEntryPoint;

  if (psh == NULL)
  {
    free(lpFile);
    return 0;
  }

  /* store section headers */

  for (i = 0;
       i < nSections;
       i++
    )
    {
      shdr[i] = *psh++;
    }
  /*
   * Get Code offset and size,
   * Data offset and size.
   */
  for (i = 0;
       i < nSections;
       i++
    )
    {
      if (poh->BaseOfCode == shdr[i].VirtualAddress)
	{
	  printf (
		   "Code Offset = %08lX, Code Size = %08lX \n",
		   shdr[i].PointerToRawData,
		   shdr[i].SizeOfRawData
	    );
	}
      if (((shdr[i].Characteristics) & 0xC0000040) == 0xC0000040)
	{
	  printf (
		   "Data Offset = %08lX, Data Size = %08lX \n",
		   shdr[i].PointerToRawData,
		   shdr[i].SizeOfRawData
	    );
	  break;
	}
    }

  printf ("\n");

  printf (
	   "Number of Objects = %04d (dec), Imagebase = %08Xh \n",
	   nSections,
	   imageBase
    );
  /*
   * Object name alignment.
   */
  for (i = 0;
       i < nSections;
       i++
    )
    {
      for (j = 0;
	   j < 7;
	   j++
	)
	{
	  if (shdr[i].Name[j] == 0)
	    {
	      shdr[i].Name[j] = 32;
	    }
	}
      shdr[i].Name[7] = 0;
    }
  for (i = 0; i < nSections; i++)
    printf ("\n   Object%02d: %8s RVA: %08lX Offset: %08lX Size: %08lX Flags: %08lX ",
      i + 1, shdr[i].Name, shdr[i].VirtualAddress, shdr[i].PointerToRawData,
	    shdr[i].SizeOfRawData, shdr[i].Characteristics);
  /*
   * Get List of Resources.
   */
  nResources = GetListOfResourceTypes (lpFile, &pnstr);
  pst = pnstr;
  printf ("\n");
  printf ("\n+++++++++++++++++++ RESOURCE INFORMATION +++++++++++++++++++");
  printf ("\n");
  if (nResources == 0)
    printf ("\n        There are no Resources in This Application.\n");
  else
    {
      printf ("\nNumber of Resource Types = %4d (decimal)\n", nResources);
      for (i = 0; i < nResources; i++)
	{
	  printf ("\n   Resource Type %03d: %s", i + 1, pst);
	  pst += strlen ((char *) (pst)) + 1;
	}
      free ((void *) pnstr);

      printf ("\n");
      printf ("\n+++++++++++++++++++ MENU INFORMATION +++++++++++++++++++");
      printf ("\n");

      nMenus = GetContentsOfMenu (lpFile, &pmNameBuff);

      if (nMenus == 0)
	{
	  printf ("\n        There are no Menus in This Application.\n");
	}
      else
	{
	  pst = pmNameBuff;
	  printf ("\nNumber of Menus = %4d (decimal)", nMenus);

	  //dumpMenu(&pst, 8096);
	  for (i = 0; i < nMenus; i++)
	    {
	      // menu ID print
	      printf ("\n\n%s", pst);
	      pst += strlen (pst) + 1;
	      printf ("\n-------------");
	      if (strncmp (pst, ":::::::::::", 11) == 0)
		{
		  printf ("\n");
		  PrintStrangeMenu (&pst);
		}
	      else
		{
		  PrintMenu (6, &pst);
		}
	      //else PrintStrangeMenu(&pst);
	    }
	  free ((void *) pmNameBuff);
	  printf ("\n");
	}

      printf ("\n");
      printf ("\n+++++++++++++++++ DIALOG INFORMATION +++++++++++++++++++");
      printf ("\n");

      nDialogs = GetContentsOfDialog (lpFile, &pdNameBuff);

      if (nDialogs == 0)
	{
	  printf ("\n        There are no Dialogs in This Application.\n");
	}
      else
	{
	  pst = pdNameBuff;
	  printf ("\nNumber of Dialogs = %4d (decimal)", nDialogs);

	  printf ("\n");

	  for (i = 0; i < nDialogs; i++)
	    {
	      // Dialog ID print
	      printf ("\nName: %s", pst);
	      pst += strlen (pst) + 1;
	      PrintDialog (&pst);
	    }
	  free ((void *) pdNameBuff);
	  printf ("\n");
	}
    }

  printf ("\n+++++++++++++++++++ IMPORTED FUNCTIONS +++++++++++++++++++");

  nImportedModules = GetImportModuleNames (lpFile, &piNameBuff);
  if (nImportedModules == 0)
    {
      printf ("\n        There are no imported Functions in This Application.\n");
    }
  else
    {
      pnstr = piNameBuff;
      printf ("\nNumber of Imported Modules = %4d (decimal)\n", nImportedModules);
      for (i = 0; i < nImportedModules; i++)
	{
	  printf ("\n   Import Module %03d: %s", i + 1, pnstr);
	  pnstr += strlen ((char *) (pnstr)) + 1;
	}

      printf ("\n");
      printf ("\n+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++++");
      pnstr = piNameBuff;
      for (i = 0; i < nImportedModules; i++)
	{
	  printf ("\n\n   Import Module %03d: %s \n", i + 1, pnstr);
	  nFunctions = GetImportFunctionNamesByModule (lpFile, pnstr, &pfNameBuff);
	  pnstr += strlen ((char *) (pnstr)) + 1;
	  pst = pfNameBuff;
	  for (j = 0; j < nFunctions; j++)
	    {
	      printf ("\nAddr:%08X hint(%04X) Name: %s",
		      (*(int *) pst), (*(short *) (pst + 4)),
	      //(pst+6));
		      TranslateFunctionName (pst + 6));
	      pst += strlen ((char *) (pst + 6)) + 1 + 6;
	    }
	  free ((void *) pfNameBuff);
	}
      free ((void *) piNameBuff);
    }

  printf ("\n");
  printf ("\n+++++++++++++++++++ EXPORTED FUNCTIONS +++++++++++++++++++");

  nExportedFunctions = GetExportFunctionNames (lpFile, &peNameBuff);
  printf ("\nNumber of Exported Functions = %4d (decimal)\n", nExportedFunctions);

  if (nExportedFunctions > 0)
    {
      pst = peNameBuff;

      for (i = 0; i < nExportedFunctions; i++)
	{
	  printf ("\nAddr:%08X Ord:%4d (%04Xh) Name: %s",
	       (*(int *) pst), (*(WORD *) (pst + 4)), (*(WORD *) (pst + 4)),
	  //(pst+6));
		  TranslateFunctionName (pst + 6));
	  pst += strlen ((char *) (pst + 6)) + 6 + 1;
	}
      free ((void *) peNameBuff);
    }

  free ((void *) lpFile);

  return 0;
}


/* EOF */
