Announcement

Collapse

Forum Guidelines

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

Type Library (TLB) Data Dumper (without WinAPI)

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

    Type Library (TLB) Data Dumper (without WinAPI)

    TheirCorp's TypeLib (TLB) Data Dumper
    (without using WinAPI)


    "Type Library Dumper" displays detailed information about the
    contents of TypeLib data (TypeLib data is what tells an operating
    system how to link up COM objects).
    It was written to determine the TypeLib format so the format could be
    documented, and also to give "bep" (Bin Edit Plus) the ability to decompile
    TypeLib data.
    It is based largely on studies of code from the ReactOS project at:
    ReactOS is a free, opensource reimplementation of windows

    The primary source file used was:
    ..\reactos\dll\win32\oleaut32\typelib.c

    Features:
    • Extracts TypeLib data from the resource sections of PE format
      files (EXE, DLL, OCX, OCA...) and also from TLB files, of course.
    • Automatic handling of files based on internal format regardless
      of file extensions
    • Drag-and-drop operation (puts the file's path into the textbox)
    • Commandline operation
    • It can open EXE's even while they're running
    • A "Study Mode" to help learn more details of the TypeLib format
      (see below).


    The (64.8 KB) attached file is a zipped folder containing:
    1. The compiled EXE
    2. All source files
    3. A sample ODL file (Object Definition Language)
    4. A sample TLB file (TypeLib)
    5. A sample dump file (plain text)


    About the "Study Mode" Feature
    • Study Mode can be enabled with the "%Study" equate.
    • It provides for logging occurrences of any type of content encountered
    • It alerts the user of the first item of interest it finds with
      a messagebox.
    • Just add code as needed to identify values or flags bits that you want
      to research. Place the code between "#If %Def(%Study)" and "#EndIf"
      statements. Example:
      #If %Def(%Study)
      Note "3 Array(s) found"
      #EndIf
    • You can also set a minimum alert priority with the "%Priority" equate.
      It will only respond to log messages prefixed with a digit equal or above
      that priority. For example, in:
      Note "4(FuncRec.FKCCIC And &H040000) <> 0"
      ...the prefix "4" is the message's priority level.
    • It marks the output file with whatever is assigned to the "$StudyMark"
      equate to help locate any discovered items. The default value is "@@@: ".


    Notes on the Program:
    • The code retains many names and comments from the ReactOS code
      it was derived from which may be misleading.
    • Information about a few parts of the format was unavailable when
      this was written, resulting in some missing details.
    • Arrows ( ==> ) are used to indicate what offset values point to.
    • Almost all values are in hex format, including those with leading
      zeros, and those containing any non-decimal characters (A, B, C, D,
      E or F).
    • A double equals sign ( "==" ) is used to show decimal equivalents
      of hex values.
    • It only dumps the "MSFT" format files for now (no "SLTG")...
    • Values of "FFFFFFFF" ( -1 ) are generally invalid, but are often
      included in the dumps.
    • An EXE or DLL file can contain multiple TypeLib resources. This
      program only dumps the first one it finds.
    • A dump file is about five to ten times the size of the original
      TypeLib data.


    Notes on the Format:
    • Array descriptors only exist for arrays with element counts specified
    • Duplicate functions have duplicate names and IDs, plus (invalid)
      offsets of -1 for their parameter names. They are (presumably) expected
      to be copied from the other (identical) function.



    All the code and text of "TheirCorp's Type Library Dumper" is GPL
    licensed by TheirCorp 2008.



    • TheirCorp's SourceForge project
      includes:
    • API Helper --- a code generator for the Win32 API
    • BinEditPlus --- a decompiler and more
    • ComHelper --- a code generator for the COM programming
    • "Flex" --- an editor with novel features
    • GDI Debug --- catches programming errors that could lead
      to resource leaks
    • Import Monitor --- (an API hook) Intercepts and monitors
      calls to imported functions
    • Intricately Mergeable Templates
    • Jellyfish Pro enhancer plugin (adds drag-and-drop and more..)
    • TheirEdit --- an editor for PowerBASIC code
    • TheirNote --- a KeyNote clone
    • TheirSheet --- a spreadsheet
    • SrcFrmt --- a source code formatter
    • Tooltipper --- a tooltip code generator


    PowerBASIC article in Wikipedia
    Attached Files
    TheirCorp's projects at SourceForge

    TheirCorp's website

    sigpic

    #2
    Source Code for Type Library Dumper

    Code:
    [b]Save this as "DisTypeLib.bas"[/b]
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    '	"DisTypeLib.bas"
    
    'This code is based on code from the ReactOS
    'project at: http://www.reactos.org/en/index.html
    'The primary source file used was:
    '	...reactos\dll\win32\oleaut32\typelib.c
    
    'So far, it only disassembles data with the "MSFT"
    'magic value (not the "SLTG" type yet).
    
    'It is intended to be integrated into bep (Bin
    'Edit Plus) and perhaps other sub-projects
    
    'This should have a TypeLib "diff" feature
    'to help learn more about its format.
    
    'This file is GPL 2008, by TheirCorp
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    #Compile Exe "DisTypeLib.exe"
    #Dim All
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    '%Debug		= 1 'enable/disable debugging code
    '%Study		= 1 'enable/disable code to help study the format
    %Priority	= 0 'set minimum priority level for logging and alerts
    
    #If %Def(%Debug)
    #Tools On
    %ProfileOn		= 1
    
    Global dbg		As Long
    Global dbs		As String
    
    Sub zz()
    
    End Sub 'zz
    
    #Else
    	#Tools Off
    
    #EndIf
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    $Caption = "TheirCorp's Type Library Dumper"
    
    %GoBtn   = 1001
    %PathTxt = 1101
    %LogTxt  = 1102
    %FileLbl = 1103
    %MsgLbl  = 1104
    
    %LogLines = 8
    %fo  	  = 10 'output file's number
    
    Global ghDlg		As Dword
    Global LocalPath	As String   'local path
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    Declare Function GetDroppedFile(ByVal hDrop As Long, fs As String) As Long
    Declare Function ProcessFile(fs As String) As Long
    Declare CallBack Function ShowDlgProc()
    Declare Sub UpdateLog(ps As String)
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    #Include "TypeLib.bas"
    #Include "DisTypeLib.inc"
    #Include "GetTypeLibData.bas"
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    Declare Function GetResource( _
    	cs As String,       _
    	ByVal ird As IMAGE_RESOURCE_DIRECTORY Ptr, _
    	ByVal de As Dword,  _   'value to subtract from ".link" offsets's
    	ByVal ss As Dword,   _   'section size
    	ByVal Offset As Dword _   'offset to resource section
    	) As Long
    Declare Function GetTypeLibData(cs As String, fs As String) As Long
    
    Declare Function Locale(lcid As Long) As String
    Declare Function VarType(ByVal pn As Long) As String
    Declare Function tlName(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    Declare Function tlString(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    Declare Function DisSltg(cs As String) As Dword
    Declare Function DisFunction(cs As String, SegDir As MSFT_SegDir, ByVal pBase As Dword, ByVal nFunc As Long, ByVal nProp As Long) As Long
    Declare Function DisTypeLib(cs As String, ps As String) As Dword
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    Sub UpdateLog(ps As String)
    Static ct   As Long
    Static ls   As String
    Static ts   As String
    
    	If Len(Command$) Then
    		'MsgBox ps
    
    	Else
    		Incr ct
    
    		If Len(ps) Then
    			'Control Get Text ghDlg, %LogTxt To ls
    			'Dialog DoEvents
    			ps = ps & $CrLf
    		Else
    			ct = 1
    			ls = ""
    			ts = ""
    		End If
    
    		If ct > %LogLines Then ts = Remain$(ts, $CrLf) & ps
    		ls = ls & ps
    
    		If Left$(ps, 5) = "Ready" Then
    			Control Set Text ghDlg, %LogTxt, LTrim$(Left$(ls, 32000), Any $CrLf)
    			Dialog DoEvents
    			Control Send ghDlg, %LogTxt, %EM_SETSEL, 65536, 65536
    			Dialog DoEvents
    			Control Send ghDlg, %LogTxt, %EM_SCROLLCARET, 0, 0
    			Dialog DoEvents
    		Else
    			Control Set Text ghDlg, %LogTxt, ts
    		End If
    
    	End If
    
    End Sub 'UpdateLog
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    'returns %true, if any files were received
    Function GetDroppedFile(ByVal hDrop As Long, fs As String) As Long
    Local ct  As Dword
    Local az  As Asciiz * %MAX_PATH
    
    	ct = DragQueryFile(hDrop, &HFFFFFFFF&, "", ByVal 0&)
    
    	If ct > 0 Then
    		az = Space$(%MAX_PATH)
    		ct = DragQueryFile(hDrop, 0, az, Len(az) - 1)
    		fs = Left$(az, ct)
    		Function = %True
    	End If
    
    End Function
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    'expects "fs" to contain the path and name
    'of either a PE or TLB format file
    'It determines which type it is automatically
    Function ProcessFile(fs As String) As Long
    Local cs	As String
    
    	If Len(Dir$(fs)) Then
    
    		If GetTypeLibData(cs, fs) Then
    			UpdateLog "Processing..."
    			DisTypeLib(cs, fs)
    		End If
    
    	Else
    		UpdateLog "Couldn't find: " & fs
    	End If
    
    End Function 'ProcessFile
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    CallBack Function ShowDlgProc()
    Local  fs   As String
    
    #If %Def(%ProfileOn)
    	Profile "Profile.txt"
    #EndIf
    
    	Select Case As Long CbMsg
    
    		'Case %WM_INITDIALOG
    
    		Case %WM_NCACTIVATE
    			Static hWndSaveFocus  As Dword
    			If IsFalse CbWParam Then
    				hWndSaveFocus = GetFocus()
    			ElseIf hWndSaveFocus Then
    				SetFocus(hWndSaveFocus)
    				hWndSaveFocus = 0
    			End If
    
    		Case %WM_DROPFILES
    			If (GetDroppedFile(CbWParam, fs)) Then
    				Control Set Text ghDlg, %PathTxt, fs
    			End If
    			DragFinish CbWParam
    
    		Case %WM_COMMAND
    			Select Case As Long CbCtl
    				Case %GoBtn
    					If CbCtlMsg = %BN_CLICKED Or CbCtlMsg = 1 Then
    						Control Get Text ghDlg, %PathTxt To fs
    						UpdateLog ""
    						ProcessFile(fs)
    						UpdateLog "Ready..."
    					End If
    			End Select
    
    	End Select
    
    End Function
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    Function PBMain() As Long
    Local lRslt As Long
    
    #If %Def(%ProfileOn)
    	Profile "Profile.txt"
    #EndIf
    
    	'get and save the local path without a trailing backslash
    	LocalPath = String$(%MAX_PATH, $Nul)
    	GetModuleFileName(ByVal 0, ByVal StrPtr(LocalPath), %MAX_PATH)
    	LocalPath = Left$(LocalPath, InStr(-1, LocalPath, "\") - 1)
    
    	If Len(Command$) Then
    
    		ProcessFile(Command$)
    		MsgBox "Done"
    
    	Else
    
    		Dialog New %HWND_DESKTOP, $Caption, , , 256, 138, %WS_POPUP Or %WS_BORDER _
    			Or %WS_DLGFRAME Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX Or _
    			%WS_VISIBLE Or %DS_MODALFRAME Or %DS_SETFOREGROUND Or %DS_3DLOOK Or _
    			%DS_NOFAILCREATE Or %DS_SETFONT, %WS_EX_WINDOWEDGE Or _
    			%WS_EX_ACCEPTFILES Or %WS_EX_CONTROLPARENT Or %WS_EX_LEFT Or _
    			%WS_EX_LTRREADING Or %WS_EX_RIGHTSCROLLBAR, To ghDlg
    
    		Control Add Label,   ghDlg, %FileLbl, "&File:", 0, 4, 19, 10, %WS_CHILD Or _
    			%WS_VISIBLE Or %WS_TABSTOP Or %SS_RIGHT, %WS_EX_LEFT Or %WS_EX_LTRREADING
    
    		Control Add TextBox, ghDlg, %PathTxt, "", 20, 2, 233, 12
    
    		Control Add Button,  ghDlg, %GoBtn, "&Go", 220, 17, 32, 14, %WS_CHILD Or _
    			%WS_VISIBLE Or %WS_BORDER Or %WS_TABSTOP Or %BS_TEXT Or _
    			%BS_DEFPUSHBUTTON Or %BS_PUSHBUTTON Or %BS_CENTER Or %BS_VCENTER, _
    			%WS_EX_LEFT Or %WS_EX_LTRREADING
    
    		Control Add Label, ghDlg, %MsgLbl, "&Messages:", 2, 22, 39, 10
    
    		Control Add TextBox, ghDlg, %LogTxt, "", 2, 34, 252, 100, %WS_CHILD Or _
    			%WS_VISIBLE Or %WS_TABSTOP Or %WS_HSCROLL Or %WS_VSCROLL Or %ES_LEFT _
    			Or %ES_MULTILINE Or %ES_AUTOHSCROLL Or %ES_AUTOVSCROLL Or %ES_WANTRETURN, _
    			%WS_EX_CLIENTEDGE Or %WS_EX_LEFT Or %WS_EX_LTRREADING Or %WS_EX_RIGHTSCROLLBAR
    
    		Dialog Send ghDlg, %DM_SETDEFID, %GoBtn, 0
    		Control Set Focus ghDlg, %PathTxt
    
    		DragAcceptFiles ghDlg, %True 'Register window to accept dropped files.
    
    		Dialog Show Modal ghDlg, Call ShowDlgProc To lRslt
    
    		Function = lRslt
    
    	End If
    
    End Function
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    [b]Save this as "GetTypeLibData.bas"[/b]
    '**************************************
    '   "GetTypeLibData.bas"
    
    
    'This file is GPL 2008, by TheirCorp
    '**************************************
    
    
    
    '**************************************
    'this is a re-entrant procedure
    'ird must always arrive pointing to a resource directory
    
    'For now, this assumes all offsets are relative to the start
    'of the resource section (opinions seem to differ on this)
    Function GetResource( _
    	cs As String,       _
    	ByVal ird As IMAGE_RESOURCE_DIRECTORY Ptr, _
    	ByVal de As Dword,  _   'value to subtract from ".link" offsets's
    	ByVal ss As Dword,   _   'section size
    	ByVal Offset As Dword _   'offset to resource section
    	) As Long
    
    Local n			As Long
    Local p			As Dword
    Local pirde		As IMAGE_RESOURCE_DATA_ENTRY Ptr
    Local irde		As IMAGE_RESOURCE_DIRECTORY_ENTRY Ptr
    Local ids		As IMAGE_RESOURCE_DIRECTORY_STRING
    
    Static fResult	As Long
    Static lvl		As Long	  'recursion level
    Static rp		As Dword  'resource pointer
    Static rid		As Dword
    Static typ		As Dword
    Static ns		As String
    
    	If lvl = 0 Then rp = StrPtr(cs) '= ird 'save pointer to start of resource section
    	Incr lvl
    
    	irde = ird + SizeOf(IMAGE_RESOURCE_DIRECTORY)
    
    	' The named entries are case insensitive strings, sorted in ascending order.
    	' The entries with 16-bit IDs follow these and are also sorted in ascending order.
    	For n = 1 To @ird.NumberOfNamedEntries + @ird.NumberOfIdEntries
    
    		If (n <= @ird.NumberOfNamedEntries) And (@irde.NameID And %IMAGE_RESOURCE_NAME_IS_STRING) Then
    			'the name is a string
    			p = rp + (@irde.NameID And &H7FFFFFFF)  'offset is relative to start of resource section
    
    			rid = 0 'assign invalid value as a flag
    			ns = Remove$(Peek$(p + 2, CvWrd(Peek$(p, 2)) * 2), $Nul) 'unicode string
    			If UCase$(ns) = "TYPELIB" Then fResult = 1 'found TypeLib data
    
    		ElseIf (n > @ird.NumberOfNamedEntries) And (@irde.NameID And %IMAGE_RESOURCE_NAME_IS_STRING) = 0 Then
    
    			'it's a 16-bit ID number
    			p = LoWrd(@irde.NameID)
    			If lvl = 1 Then
    				typ = p
    			ElseIf lvl = 2 Then
    				ns = ""
    				rid = p
    			ElseIf lvl = 3 Then
    			End If
    
    		End If
    
    		p = (@irde.Offset And &H7FFFFFFF)
    
    		If (@irde.Offset And %IMAGE_RESOURCE_DATA_IS_DIRECTORY) Then 'it's a subdirectory
    			p = GetResource(cs, rp + p, de, ss, Offset)
    
    		Else    'it's actual resource data
    
    			'get offset in PE file to ImageResourceDirectoryEntry structure
    			pirde = rp + p
    
    			If fResult = 1 Then
    				Incr fResult
    				'@pirde.OffsetToData is the RVA to the resource data
    				cs = Mid$(cs, @pirde.OffsetToData - de - Offset + 1, @pirde.Size)
    			End If
    
    		End If
    
    		If fResult = 2 Then Exit For
    		irde = irde + SizeOf(IMAGE_RESOURCE_DIRECTORY_ENTRY)
    
    	Next n
    
    	Decr lvl
    	If lvl Then
    		Function = ird
    	Else
    		Function = fResult
    		fResult = 0
    	End If
    
    End Function 'GetResource
    
    '***************************************
    ' gets TypeLib data from a PE file's resource section
    Function GetTypeLibData(cs As String, fs As String) As Long
    #Register All
    Local ff   As Long	'file handle
    Local n	   As Long
    Local pDH  As DosHeader Ptr
    Local pPH  As PEHeader Ptr
    Local si   As SectionInfo
    
    
    	'--------------------------------------
    	'get the Typelib data
    	Try
    
    		ff = FreeFile
    		Open fs For Binary Access Read Lock Shared As #ff
    		Get$ #ff, 2048, cs
    
    		'----------------------------------
    		'get PE signature if present
    		pDH = StrPtr(cs)
    		If (@pDH.lfanew > 0) And (@pDH.lfanew < Len(cs)) Then
    			pDH = pDH + @pDH.lfanew
    			! mov eax, pDH
    			! mov eax, [eax]
    			! mov n, eax
    		End If
    
    		If Left$(cs, 4) = "MSFT" Then 'it's a "tlb" (TypeLib) file
    			Seek# ff, 1
    			Get$ #ff, Lof(ff), cs
    			Function = 1
    
    		ElseIf Left$(cs, 4) = "SLTG" Then
    			Function = DisSltg(cs)
    
    		ElseIf n = &H04550 Then    '&H04550  = "PE" & $Nul & $Nul
    
    			Local pOH   As OptHeader Ptr
    			Local pSH   As SectionHeader Ptr
    			Local pDD   As DataDir Ptr
    
    			pDH = StrPtr(cs)
    			pPH = pDH + @pDH.lfanew + 4
    			pOH = pPH + SizeOf(PEHeader)
    
    			'"pOH.NumberOfRvaAndSizes" is the number of entries, not the size of the array, as someone once wrote
    			If %ResourceSection > @pOH.NumberOfRvaAndSizes Then Exit Function
    
    			pDD = pOH + SizeOf(OptHeader) + ((%ResourceSection - 1) * SizeOf(DataDir))
    			si.dRVA = @pDD.RVA
    			si.dSize = @pDD.DirSize
    
    
    			'find the section which matches si.dRVA in the section table
    			pSH = pOH + SizeOf(OptHeader) + (@pOH.NumberOfRvaAndSizes * SizeOf(DataDir))
    			For n = 1 To @pPH.NumberOfSections
    
    				If (si.dRVA => @pSH.RVA) And (si.dRVA < @pSH.RVA + @pSH.SizeOfRawData) Then
    					si.SectName         = @pSH.SectName
    					si.VirtSize         = @pSH.VirtSize             'size of unpadded section
    					si.RVA              = @pSH.RVA                  '@pSH.RVA is the offset to section when loaded
    					si.RamAdd           = @pOH.ImageBase + @pSH.RVA 'section's RAM address (for example: &H401000)
    					si.SizeOfRawData    = @pSH.SizeOfRawData        'size after padding to section alignment
    					si.PtrToRawData     = @pSH.PtrToRawData         'zero-based file offset to section
    					si.StrPos           = @pSH.PtrToRawData + 1     'one-based file offset to section
    					si.EndPos           = si.StrPos + si.SizeOfRawData
    					si.Delta            = si.RVA - si.PtrToRawData  'value to subtract from RVAs to get file offsets
    					si.Characteristics  = @pSH.Characteristics
    
    					Exit For
    
    				End If
    
    				pSH = pSH + SizeOf(SectionHeader) 'advance pSH to next section header
    
    			Next n
    
    			'get TypeLib resource
    			Seek# ff, si.StrPos
    			Get$ #ff, si.SizeOfRawData, cs
    			If GetResource(cs, StrPtr(cs), si.Delta, si.SizeOfRawData, si.PtrToRawData) Then
    				Function = 1
    			Else
    				UpdateLog "No TypeLib data found in: " & fs
    			End If
    
    		End If
    
    		Close# ff
    
    	Catch
    		UpdateLog "Error opening input file: " & fs
    		Exit Function
    	End Try
    
    End Function 'GetTypeLibData
    
    '***************************************
    
    
    [b]Save this as "Typelib.bas"[/b]
    '****************************************
    '	"DisTypeLib.bas"
    
    'This code is based on code from the ReactOS
    'project at: http://www.reactos.org/en/index.html
    'The primary source file used was:
    '	...reactos\dll\win32\oleaut32\typelib.c
    
    'So far, it only disassembles data with the "MSFT"
    'magic value (not the "SLTG" type yet).
    
    'It is intended to be integrated into bep (Bin
    'Edit Plus) and perhaps other sub-projects
    
    'This should have a TypeLib "diff" feature
    'to help learn more about its format.
    
    'This file is GPL 2008, by TheirCorp
    '****************************************
    
    
    '****************************************
    '	"Study-Mode" Code
    '****************************************
    #If %Def(%Study)
    
    $StudyMark		= "@@@: " 'to help find items of interest
    Global CurFile		As String
    
    'you can set a string's priority by prefixing
    'it with a digit from 0 through 9. The minimum
    'priority is determined by the value of %Priority
    Sub Note(ps As String)
    Local n		As Long
    Static ff	As Long
    Static ct	As Long
    
    	If Len(ps) = 0 Then
    		'close it each time to make sure it's accessible to a text viewer
    		Close# ff
    		ff = 0 : ct = 0
    	Else
    
    		If ff = 0 Then
    			ff = FreeFile
    			Open "Study.txt" For Append Lock Write As #ff
    			Print# ff,
    			Print# ff, "****************************************"
    			Print# ff, "	New File: "; CurFile
    		End If
    
    		n = Val(Left$(ps, 1))
    		ps = LTrim$(ps, Any " 0123456789")
    
    		If ct = 0 Then 'alert the user, if the priority is high enough
    			If n => %Priority Then
    				MsgBox "Found something of interest" & $CrLf & ps
    				Incr ct 'disable any further alerts
    			End If
    		End If
    
    		'print marker in output file to help find items of interest
    		'(this assumes that the last file opened was the output file)
    		Print# %fo,
    		Print# %fo, $StudyMark; ps
    
    		'maintain a log of findings
    		Print# ff, ps
    
    	End If
    
    End Sub 'Note
    
    #EndIf
    
    
    
    
    '********************************************************************************
    '					TypeLib-Specific Equates and Data Types
    '********************************************************************************
    
    'Note:	OAIDL.h says hRefType is a DWORD
    
    %HELPDLLFLAG	= &H0100
    
    
    '****************************************
    '	"Magic" Values
    '****************************************
    %MSFT_SIGNATURE		= &H05446534D '  "MSFT"
    %SLTG_SIGNATURE		= &H047544C53 '  "SLTG"
    
    
    '****************************************
    '	Equates for Translating Flags
    '		and Codes to Text
    '****************************************
    $SysKind		= "Win16,Win32,Macintosh"
    $VarFlags		= "ReadOnly,Source,Bindable,RequestEdit,DisplayBind,DefaultBind,Hidden,Restricted,DefaultCollelem,UiDefault,NonBrowsable,Replaceable,ImmediateBind"
    $TKind			= "Enum,Record,Module,Interface,Dispatch,Coclass,Alias,Union,Max"
    $ParamFlags		= "In,Out,LCID,RetVal,Opt,HasDefault,HasCustData"
    $CallConv		= "FastCall,CDecl,Pascal,MacPascal,StdCall,FPFastCall,SysCall,MPWCDecl,MPWPascal,Max"
    $InvoKind		= "Func,PropertyGet,PropertyPut,PropertyPutRef"
    $FuncKind		= "Virtual,PureVirtual,NonVirtual,Static,Dispatch"
    
    
    '****************************************
    '	Variable-Type Codes, Masks and Flags
    '****************************************
    %VT_Empty			= 0??
    %VT_Null			= 1??
    %VT_I2				= 2??
    %VT_I4				= 3??
    %VT_R4				= 4??
    %VT_R8				= 5??
    %VT_Cy				= 6??
    %VT_Date			= 7??
    %VT_BStr			= 8??
    %VT_Dispatch		= 9??
    %VT_Error			= 10??
    %VT_Bool			= 11??
    %VT_Variant			= 12??
    %VT_Unknown			= 13??
    %VT_Decimal			= 14??
    %VT_I1				= 16??
    %VT_UI1				= 17??
    %VT_UI2				= 18??
    %VT_UI4				= 19??
    %VT_I8				= 20??
    %VT_UI8				= 21??
    %VT_Int				= 22??
    %VT_UInt			= 23??
    %VT_Void			= 24??
    %VT_HResult			= 25??
    %VT_Ptr				= 26??
    %VT_SafeArray		= 27??
    %VT_CArray			= 28??
    %VT_UserDefined		= 29??
    %VT_LPStr			= 30??
    %VT_LPWStr			= 31??
    %VT_Record			= 36??
    %VT_FileTime		= 64??
    %VT_Blob			= 65??
    %VT_Stream			= 66??
    %VT_Storage			= 67??
    %VT_Streamed_Object	= 68??
    %VT_Stored_Object	= 69??
    %VT_Blob_Object		= 70??
    %VT_CF				= 71??
    %VT_ClsID			= 72??
    
    '	flags
    %VT_Bstr_Blob		= &H00FFF??
    %VT_Vector			= &H01000??
    %VT_Array			= &H02000??
    %VT_ByRef			= &H04000??
    %VT_Reserved		= &H08000??
    
    '	masks
    %VT_Illegal			= &H0FFFF??
    %VT_IllegalMasked	= &H00FFF??
    %VT_TypeMask		= &H00FFF??
    
    
    '****************************************
    '	Calling Conventions
    '****************************************
    %CC_FASTCALL			= 0
    %CC_CDECL				= 1
    %CC_MSCPASCAL			= 2
    %CC_PASCAL				= 2
    %CC_MACPASCAL			= 3
    %CC_STDCALL				= 4
    %CC_FPFASTCALL			= 5
    %CC_SYSCALL				= 6
    %CC_MPWCDECL			= 7
    %CC_MPWPASCAL			= 8
    %CC_MAX					= 9
    
    
    '****************************************
    '	Function Types
    '****************************************
    %FUNC_VIRTUAL			= 0
    %FUNC_PUREVIRTUAL		= 1
    %FUNC_NONVIRTUAL		= 2
    %FUNC_STATIC			= 3
    %FUNC_DISPATCH			= 4
    
    
    '****************************************
    '	Function Flags
    '****************************************
    %FUNCFLAG_FRESTRICTED		= &H00001
    %FUNCFLAG_FSOURCE			= &H00002
    %FUNCFLAG_FBINDABLE			= &H00004
    %FUNCFLAG_FREQUESTEDIT		= &H00008
    %FUNCFLAG_FDISPLAYBIND		= &H00010
    %FUNCFLAG_FDEFAULTBIND		= &H00020
    %FUNCFLAG_FHIDDEN			= &H00040
    %FUNCFLAG_FUSESGETLASTERROR	= &H00080
    %FUNCFLAG_FDEFAULTCOLLELEM	= &H00100
    %FUNCFLAG_FUIDEFAULT		= &H00200
    %FUNCFLAG_FNONBROWSABLE		= &H00400
    %FUNCFLAG_FREPLACEABLE		= &H00800
    %FUNCFLAG_FIMMEDIATEBIND  	= &H01000
    #If %Def(%MAC)
    %FUNCFLAG_FORCELONG			= 2147483647
    #Endif
    
    
    '****************************************
    '	Invocation Kinds
    '****************************************
    %INVOKE_FUNC			= 1
    %INVOKE_PROPERTYGET		= 2
    %INVOKE_PROPERTYPUT		= 4
    %INVOKE_PROPERTYPUTREF	= 8
    
    
    '****************************************
    '	Parameter Flags
    '****************************************
    %PARAMFLAG_NONE			= &H000
    %PARAMFLAG_FIN			= &H001
    %PARAMFLAG_FOUT			= &H002
    %PARAMFLAG_FLCID		= &H004
    %PARAMFLAG_FRETVAL		= &H008
    %PARAMFLAG_FOPT			= &H010
    %PARAMFLAG_FHASDEFAULT	= &H020
    %PARAMFLAG_FHASCUSTDATA	= &H040
    
    
    '****************************************
    '	System Kind
    '****************************************
    'SYS_WIN16 --- The target operating system for the type library is 16-bit Windows systems.
    'By default, data members are packed.
    
    'SYS_WIN32 --- The target operating system for the type library is 32-bit Windows systems.
    'By default, data members are naturally aligned (for example, 2-byte integers are aligned
    'on even-byte boundaries; 4-byte integers are aligned on quad-word boundaries, and so on).
    
    'SYS_MAC --- The target operating system for the type library is Apple Macintosh. By default,
    'all data members are aligned on even-byte boundaries.
    %SYS_WIN16		= 0
    %SYS_WIN32		= 1
    %SYS_MAC		= 2
    
    
    '****************************************
    '	Type-Kinds
    '****************************************
    %TKIND_ENUM			= 0
    %TKIND_RECORD		= 1
    %TKIND_MODULE		= 2
    %TKIND_INTERFACE	= 3
    %TKIND_DISPATCH		= 4
    %TKIND_COCLASS		= 5
    %TKIND_ALIAS		= 6
    %TKIND_UNION		= 7
    %TKIND_MAX			= 8
    
    
    '****************************************
    '	Variable Kinds
    '****************************************
    'not sure if these are ever used in MSFT format data
    '%VAR_PERINSTANCE	= 0
    '%VAR_STATIC		= %VAR_PERINSTANCE + 1
    '%VAR_CONST			= %VAR_STATIC + 1
    '%VAR_DISPATCH		= %VAR_CONST + 1
    %VAR_PERINSTANCE	= 0
    %VAR_STATIC			= 1
    %VAR_CONST			= 2
    %VAR_DISPATCH		= 3
    
    
    '****************************************
    '	Variable Flags
    '****************************************
    %VARFLAG_FREADONLY			= &H00001
    %VARFLAG_FSOURCE			= &H00002
    %VARFLAG_FBINDABLE			= &H00004
    %VARFLAG_FREQUESTEDIT		= &H00008
    %VARFLAG_FDISPLAYBIND		= &H00010
    %VARFLAG_FDEFAULTBIND		= &H00020
    %VARFLAG_FHIDDEN			= &H00040
    %VARFLAG_FRESTRICTED		= &H00080
    %VARFLAG_FDEFAULTCOLLELEM	= &H00100
    %VARFLAG_FUIDEFAULT			= &H00200
    %VARFLAG_FNONBROWSABLE		= &H00400
    %VARFLAG_FREPLACEABLE		= &H00800
    %VARFLAG_FIMMEDIATEBIND		= &H01000
    
    
    
    
    '****************************************
    '	TypeLib UDTs
    '****************************************
    
    Union TYPEDESCUNION
    	lptdesc		As Dword Ptr 'TYPEDESC Ptr
    	lpadesc		As Dword Ptr 'ARRAYDESC Ptr
    	hRefType	As Long 'hRefType
    End Union 'TYPEDESCUNION
    
    
    Type tagTYPEDESC
    	u	As TYPEDESCUNION
    	vt	As Long 'VARTYPE
    End Type 'TYPEDESC
    
    
    Type TYPEDESC 'a simplified substitute for a tagTYPEDESC
    	v1	As Integer
    	v2	As Integer
    	v3	As Integer
    	v4	As Integer
    End Type 'TYPEDESC
    
    
    Type SAFEARRAYBOUND
    	cElements	As Dword
    	lLbound		As Long
    End Type 'SAFEARRAYBOUND
    
    
    Type ARRAYDESC
    	u			As TYPEDESCUNION
    	cDims		As Word
    	vt			As Word 'VARTYPE
    	rgbounds(0)	As SAFEARRAYBOUND
    End Type 'ARRAYDESC
    
    
    Type CArrayDesc
    	ard		As ARRAYDESC
    	sab		As SAFEARRAYBOUND
    End Type
    
    Type tagPARAMDESCEX
    	cBytes				As Dword 'ULONG
    	'varDefaultValue		As Variant 'VARIANTARG
    End Type 'tagPARAMDESCEX
    
    
    Type tagPARAMDESC
    	pParamDescEx	As tagPARAMDESCEX 'or a Ptr ?
    	wParamFlags		As Word '(USHORT)
    End Type 'tagPARAMDESC
    
    
    Type tagIDLDESC
    	dwReserved		As Dword
    	wIDLFlags		As Word 'USHORT
    End Type tagIDLDESC
    
    
    Union ELEMDESCUNION
    	idldesc		As tagIDLDESC	'info for remoting the element
    	ParamDesc	As tagPARAMDESC	'info about the parameter
    End Union
    
    
    #If 1 = 0 '(disable this first definition)
    ' the following is what MIDL knows how to remote
    Type tagELEMDESC
    	tdesc		As TYPEDESC
    	ParamDesc	As PARAMDESC
    End Type tagELEMDESC
    #Else
    Type tagELEMDESC
    	tdesc	As tagTYPEDESC 'the type of the element
    	u		As ELEMDESCUNION
    End Type 'tagELEMDESC
    #endif
    
    
    '	MSFT typelibs
    'These are TypeLibs created with ICreateTypeLib2 structure of the typelib type2 header
    'it is at the beginning of a type lib file
    Type MSFT_Header
    	Magic1				As Long '&H5446534D "MSFT"								00
    	Magic2				As Long '&H00010002 version number?
    	PosGuid				As Long 'position of libid in GUID table (should be,  else -1)
    	LCID				As Long 'locale id
    	LCID2				As Long '												10
    	VarFlags			As Long '(largely) unknown flags
    				  				'* the lower nibble is SysKind
    				  				'* bit 5 is set if a helpfile is defined
    				  				'* bit 8 is set if a help dll is defined
    
    	Version				As Long 'set with SetVersion()
    	Flags				As Long 'set with SetFlags()
    	nrTypeInfos			As Long 'number of TypeInfo's							20
    	HelpString			As Long 'offset to help string in string table
    	HelpStringContext	As Long
    	HelpContext			As Long
    	NameTableCount		As Long 'number of names in name table					30
    	NameTableChars		As Long 'characters in name table
    	NameOffset			As Long 'offset of name in string table
    	HelpFile			As Long 'offset of helpfile in string table
    	CustomDataOffset	As Long 'if -1 no custom data, else it is offset		40
    					 	 		'in custom data/GUID offset table
    	Res44				As Long 'unknown always: &H20 (GUID hash size?)
    	Res48				As Long 'unknown always: &H80 (name hash size?)
    	DispatchPos			As Long 'hRefType to IDispatch, or -1 if no IDispatch
    	nImpInfos			As Long 'number of ImpInfos								50
    	'FileName			As Long 'offset to typelib file name in string table
    End Type 'MSFT_Header
    
    
    'segments in the type lib file have a structure like this:
    Type MSFT_pSeg
    	Offset	As Long 'absolute offset in file
    	Length	As Long 'length of segment
    	Res08	As Long 'unknown always -1
    	Res0C	As Long 'unknown always &H0F in the header
    					 '&H03 in the TypeInfo_data
    End Type 'MSFT_pSeg
    
    
    '	segment directory
    Type MSFT_SegDir
    	pTypeInfoTab		As MSFT_pSeg '1 - TypeInfo table
    	pImpInfo			As MSFT_pSeg '2 - table with info for imported types
    	pImpFiles			As MSFT_pSeg '3 - import libaries
    	pRefTab				As MSFT_pSeg '4 - References table
    	pLibtab				As MSFT_pSeg '5 - always exists, alway same size (&H80)
    						  			 '  - hash table with offsets to GUID?????
    	pGuidTab			As MSFT_pSeg '6 - all GUIDs are stored here together with
    						  			 '  - offset in some table????
    	Res07				As MSFT_pSeg '7 - always created, always same size (&H0200)
    						  			 '  - contains offsets into the name table
    	pNametab			As MSFT_pSeg '8 - name table
    	pStringTab			As MSFT_pSeg '9 - string table
    	pTypdescTab			As MSFT_pSeg 'A - type description table
    	pArrayDescriptions	As MSFT_pSeg 'B - array descriptions
    	pCustData			As MSFT_pSeg 'C - data table, used for custom data and default
    				  					 '  - parameter values
    	pCDGuids			As MSFT_pSeg 'D - table with offsets for the GUIDs and into
    									 '  - the custom data table
    	Res0E				As MSFT_pSeg 'E - unknown
    	Res0F				As MSFT_pSeg 'F - unknown
    End Type 'MSFT_SegDir
    
    
    'base type info data
    'The definitions of some of these don't agree with actual results
    '(fixed the numbering: it started off with a hex count of bytes, then continued with decimal counts after "10")
    Type MSFT_TypeInfoBase
    	TypeKind			As Long	'00 - it is the TKIND_xxx, plus some byte alignment stuff
    	MemOffset			As Long '	- points past the file, if no elements
    	Res2				As Long '	- zero if no element, else = N * &H40
    	Res3				As Long '	- 1 if no element, (N-1) * &H38
    	Res4				As Long '10 - always? 3
    	Res5				As Long '	- always? zero
    	cFuncs				As Integer ' - count of functions
    	cProps				As Integer ' - count of properties
    	Res7				As Long '   - always? zero
    	Res8				As Long '20 - always? zero
    	Res9				As Long '   - always? zero
    	ResA				As Long '   - always? zero
    	PosGuid				As Long '   - position in GUID table
    	Flags				As Long '30 - Typeflags
    	NameOffset			As Long '   - offset in name table
    	Version				As Long '   - element version
    	DocStringOffs		As Long	'   - offset of docstring in string tab
    	HelpStringContext	As Long '40
    	HelpContext			As Long
    	oCustData			As Long	'   - offset in custom data table
    #If %Def(%WORDS_BIGENDIAN)		'
    	cbSizeVft	As Integer 'virtual table size, not including inherits
    	cImplTypes	As Integer 'number of implemented interfaces
    #Else
    	cImplTypes	As Integer 'number of implemented interfaces
    	cbSizeVft	As Integer 'virtual table size, not including inherits
    #endif
    	Size		As Long  '50 - size in bytes, at least for structures
    
    	DataType1	As Long  '	- position in type description table
    						 '	- or in base interfaces
    						 '	- if coclass: offset in reftable
    						 '	- if interface: reference to inherited if
    						 '	- if module: offset to dllname in name table
    	DataType2	As Long  '	- if &H8000, entry above is valid, else it is zero?
    	Res18		As Long  '	- always? 0
    	Res19		As Long  '60 - always? -1
    End Type 'MSFT_TypeInfoBase
    
    
    
    'information on imported types
    Type MSFT_ImpInfo
    	Flags		As Long 'bits 0 - 15:  count
    						'bit  16:	  if set oGUID is an offset to GUID
    						'			  if clear oGUID is a TypeInfo index in the specified typelib
    						'bits 24 - 31: TKIND of reference
    	oImpFile	As Long 'offset in the Import File table
    	oGuid		As Long 'offset in GUID table or TypeInfo index (see bit 16 of Res0)
    End Type 'MSFT_ImpInfo
    
    
    
    'Parameter info: one per argument
    Type MSFT_ParameterInfo
    	DataType	As Integer
    	Flags		As Integer
    	oName		As Long
    	ParamFlags	As Long
    End Type
    
    
    
    '	Function description data
    'SizeOf(MSFT_FuncRecord) = 24 (required fields only)
    'These exist in arrays along with zero or more "MSFT_PropRecord" 
    'elements. Each array is preceded by a Dword stating the total
    'size of the array.
    '...ArraySize		As Long
    Type MSFT_FuncRecord
    	RecSize	  			As Word 'record size, including optional fields and MSFT_ParameterInfo's
    	Unknown	  			As Word ' zero-based function number ?
    	DataType	 		As Integer 'data type returned by the function
    
    	'If the .Flags MSB = 1, then the low byte is valid. So far it seems
    	'to always be valid, except for pointers. When MSB = 1, the low byte
    	'is the code for a data type that's equivalent to or compatible with
    	'that in .DataType.
    	Flags				As Integer
    
    	Reserved			As Long 'always(?) zero
    
    #If %Def(%WORDS_BIGENDIAN)
    	FuncDescSize		As Integer 'size of reconstituted FUNCDESC and related structs
    	VtableOffset		As Integer 'offset in vtable
    #Else
    	VtableOffset		As Integer 'offset in vtable
    	FuncDescSize		As Integer 'size of reconstituted FUNCDESC and related structs
    #endif
    
    	'The bits in FKCCIC have the following meanings:
    	'0 - 2 = function kind (eg virtual)
    	'3 - 6 = Invocation kind
    	'7 means custom data is present
    	'8 - 11 = calling convention
    	'12 means one or more parameters have a default value
    	'+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    	'|               |               |               |               |
    	'| 15  14  13  12| 11  10  9   8 | 7   6   5   4 | 3   2   1   0 |
    	'+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    	'|   |   |   | D |   |   |   |   | C |   |   |   |   |   |   |   |
    	'|   |   |   | e |    Calling    | u |  Invocation   | Function  |
    	'|   |   |   | f |  Convention   | s |    Kind       |   Kind    |
    	'|   |   |   | V |               | t |               |           |
    	'|   |   |   | a |               | D |               |           |
    	'|   |   |   | l |               | a |               |           |
    	'|   |   |   | u |               | t |               |           |
    	'|   |   |   | e |   |   |   |   | a |   |   |   |   |   |   |   |
    	'+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    	FKCCIC				As Long
    
    	nParams				As Integer 'parameter count
    	Unknown2			As Integer
    
    '****** Optional attribute fields, the number of them is variable ******
    	'helpcontext		As Long '0
    	'oHelpString		As Long '1
    	'oEntry				As Long '2 either offset in string table or numeric as it is
    	'res9				As Long '3 unknown (-1)
    	'resA				As Long '4 unknown (-1)
    	'HelpStringContext	As Long '5
    	'****** these are present if bit 12 of FKCCIC is set ******
    	'oCustData			As Long '6 custom data for function
    	'oArgCustData(0)	As Long '7 custom data per argument
    End Type 'MSFT_FuncRecord
    
    
    
    '	Property description data
    ' The size of the required fields of the MSFT_PropRecord structure 
    'is 20 (= &H14)
    'These exist in arrays along with zero or more "MSFT_FuncRecord"
    'elements. Each array is preceded by a Dword stating the total
    'size of the array.
    Type MSFT_PropRecord
    	RecSize				As Word 'size of PropRecord
    	PropNum				As Word 'Property number?
    	DataType	 		As Integer 'data type of the variable
    	Flags				As Integer 'VarFlags
    #If %Def(%WORDS_BIGENDIAN)
    	VarDescSize			As Integer 'size of reconstituted VARDESC and related structs
    	VarKind	  			As Integer 'VarKind
    #Else
    	VarKind				As Integer 'VarKind --- %VAR and %VarFlags
    	VarDescSize			As Integer 'size of reconstituted VARDESC and related structs
    #endif
    	OffsValue			As Long 'value of the variable or the offset in the data structure
    	'***** End of required fields *****
    
    	'Optional attribute fields, the number of them is variable
    	'and are determined from the record size (if there's room
    	'for it, then it's there...)
    	Unknown2			As Long
    	HelpContext			As Long
    	oHelpString			As Long
    	Res9			 	As Long 'unknown (-1)
    	oCustData			As Long 'custom data for variable
    	HelpStringContext	As Long
    End Type 'MSFT_PropRecord
    
    
    
    'Structure of the reference data
    Type MSFT_RefRecord
    	'either offset in TypeInfo table, then it's a multiple of 4...
    	'or offset in the external reference table with an offset of 1
    	RefType				As Long
    
    	Flags				As Long '?
    	oCustData			As Long 'custom data
    	oNext				As Long 'next offset, -1 if last
    End Type
    
    
    
    'information on imported files
    Type TLBImpLib
    	oGUID	As Long
    	LCID	As Long
    	MajVer	As Word
    	MinVer	As Word
    	Size	As Word 'divide by 4 to get the length of the file name
    End Type 'TLBImpLib
    
    
    
    'this is how a GUID is stored
    Type MSFT_GuidEntry
    	Guid		As String * 16
    	' = -2 for a TypeLib GUID
    	'TypeInfo offset for TypeInfo GUID,
    	'Otherwise, the low two bits:
    	'	= 01 for an imported TypeInfo
    	'	= 10 for an imported TypeLib (used by imported TypeInfos)
    	hRefType	As Long
    	NextHash	As Long	'offset to next GUID in the hash bucket
    End Type 'MSFT_GuidEntry
    
    
    
    'some data preceding entries in the name table
    Type MSFT_NameIntro
    	'is -1 if name is for neither a TypeInfo,
    	'a variable, or a function (that is, name
    	'is for a typelib or a function parameter).
    	'otherwise is the offset of the first
    	'TypeInfo that this name refers to (either
    	'to the TypeInfo itself or to a member of
    	'the TypeInfo
    	hRefType	As Long
    
    	NextHash	As Long	'offset to next name in the hash bucket
    
    	'only lower 8 bits are valid,
    	'lower-middle 8 Bits are unknown (flags?),
    	'upper 16 Bits are hash code
    	NameLen		As Long
    End Type 'MSFT_NameIntro
    
    
    
    'Custom data table entries are Dword aligned by padding with (usually) "W"
    'Type MSFT_CUSTOMDATA
    '	nLen				As Word 'length of nLen plus bData in Words
    '	bData(nLen - 1)		As Word	'
    'End Type 'MSFT_CUSTOMDATA
    
    
    
    'the custom data/GUID table directory has entries like this
    Type MSFT_CDGuid
    	GuidOffset	As Long
    	DataOffset	As Long
    	oNext		As Long 'next offset in the table, -1 if it's the last
    End Type 'MSFT_CDGuid
    
    
    '****************************************
    
    'Declare Function Locale(lcid As Long) As String
    'Declare Function VarType(ByVal pn As Long) As String
    'Declare Function tlName(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    'Declare Function tlString(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    'Declare Function DisSltg(cs As String) As Dword
    'Declare Function DisFunction(cs As String, SegDir As MSFT_SegDir, ByVal pBase As Dword, ByVal nFunc As Long, ByVal nProp As Long) As Long
    'Declare Function DisTypeLib(cs As String, ps As String) As Dword
    
    '****************************************
    
    Function Locale(lcid As Long) As String
    
    Data &H0401, ARA, Arabic  Saudi Arabia
    Data &H0801, ARI, Arabic Iraq
    Data &H0C01, ARE, Arabic Egypt
    Data &H1001, ARL, Arabic Libya
    Data &H1401, ARG, Arabic Algeria
    Data &H1801, ARM, Arabic Morocco
    Data &H1C01, ART, Arabic Tunisia
    Data &H2001, ARO, Arabic Oman
    Data &H2401, ARY, Arabic Yemen
    Data &H2801, ARS, Arabic Syria
    Data &H2C01, ARJ, Arabic Jordan
    Data &H3001, ARB, Arabic Lebanon
    Data &H3401, ARK, Arabic Kuwait
    Data &H3801, ARU, Arabic U.A.E.
    Data &H3C01, ARH, Arabic Bahrain
    Data &H4001, ARQ, Arabic Qatar
    Data &H0402, "BGR", Bulgarian Bulgaria
    Data &H0403, CAT, Catalan Spain
    Data &H0404, CHT, Chinese  Taiwan
    Data &H0804, CHS, Chinese PRC
    Data &H0C04, ZHH, Chinese Hong Kong
    Data &H1004, ZHI, Chinese Singapore
    Data &H1404, ZHM, Chinese Macau
    Data &H0405, CSY, Czech Czech Republic
    Data &H0406, DAN, Danish Denmark
    Data &H0407, GERMANY, German Germany
    Data &H0807, DES, German Switzerland
    Data &H0C07, DEA, German Austria
    Data &H1007, DEL, German Luxembourg
    Data &H1407, DEC, German Liechtenstein
    Data &H0408, ELL, Greek Greece
    Data &H0409, USA, English United States
    Data &H0809, ENG, English United Kingdom
    Data &H0C09, ENA, English Australia
    Data &H1009, ENC, English Canada
    Data &H1409, ENZ, English New Zealand
    Data &H1809, ENI, English Ireland
    Data &H1C09, ENS, English South Africa
    Data &H2009, ENJ, English Jamaica
    Data &H2409, ENB, English Caribbean
    Data &H2809, ENL, English Belize
    Data &H2C09, ENT, English Trinidad
    Data &H3009, ENW, English Zimbabwe
    Data &H3409, ENP, English Philippines
    Data &H040A, SPAIN, Spanish Spain
    Data &H080A, ESM, Spanish Mexico
    Data &H0C0A, ESN, Spanish Spain (International Sort)
    Data &H100A, ESG, Spanish Guatemala
    Data &H140A, ESC, Spanish Costa Rica
    Data &H180A, ESA, Spanish Panama
    Data &H1C0A, ESD, Spanish Dominican Republic
    Data &H200A, ESV, Spanish Venezuela
    Data &H240A, ESO, Spanish Colombia
    Data &H280A, ESR, Spanish Peru
    Data &H2C0A, ESS, Spanish Argentina
    Data &H300A, ESF, Spanish Ecuador
    Data &H340A, ESL, Spanish Chile
    Data &H380A, ESY, Spanish Uruguay
    Data &H3C0A, ESZ, Spanish Paraguay
    Data &H400A, ESB, Spanish Bolivia
    Data &H440A, ESE, Spanish El Salvador
    Data &H480A, ESH, Spanish Honduras
    Data &H4C0A, ESI, Spanish Nicaragua
    Data &H500A, ESU, Spanish Puerto Rico
    Data &H040B, FIN, Finnish Finland
    Data &H040C, FRANCE, French France
    Data &H080C, FRB, French Belgium
    Data &H0C0C, FRC, French Canada
    Data &H100C, FRS, French Switzerland
    Data &H140C, FRL, French Luxembourg
    Data &H180C, FRM, French Monaco
    Data &H040D, HEB, Hebrew Israel
    Data &H040E, HUN, Hungarian Hungary
    Data &H040F, ISL, Icelandic Iceland
    Data &H0410, ITALY, Italian Italy
    Data &H0810, ITS, Italian Switzerland
    Data &H0411, JAPAN, Japanese  Japan
    Data &H0412, KOREA, Korean Korea
    Data &H0413, NLD, Dutch Netherlands
    Data &H0813, NLB, Dutch Belgium
    Data &H0414, NOR, Norwegian Norway (Bokmål)
    Data &H0814, NON, Norwegian Norway (Nynorsk)
    Data &H0415, PLK, Polish Poland
    Data &H0416, BRAZIL, Portuguese Brazil
    Data &H0816, PTG, Portuguese Portugal
    Data &H0418, ROM, Romanian Romania
    Data &H0419, RUS, Russian Russia
    Data &H041A, HRV, Croatian Croatia
    Data &H081A, SRL, Serbian Serbia (Latin)
    Data &H0C1A, SRB, Serbian Serbia (Cyrillic)
    Data &H041B, SKY, Slovak Slovakia
    Data &H041C, SQI, Albanian Albania
    Data &H041D, SVE, Swedish Sweden
    Data &H081D, SVF, Swedish Finland
    Data &H041E, THA, Thai Thailand
    Data &H041F, TRK, Turkish Turkey
    Data &H0420, URP, Urdu Pakistan
    Data &H0421, IND, Indonesian Indonesia
    Data &H0422, UKR, Ukrainian Ukraine
    Data &H0423, BEL, Belarusian Belarus
    Data &H0424, SLV, Slovene Slovenia
    Data &H0425, ETI, Estonian Estonia
    Data &H0426, LVI, Latvian Latvia
    Data &H0427, LTH, Lithuanian Lithuania
    Data &H0827, LTC, Classic Lithuanian Lithuania
    Data &H0429, FAR, Farsi Iran
    Data &H042A, VIT, Vietnamese Viet Nam
    Data &H042B, HYE, Armenian Armenia
    Data &H042C, AZE, Azeri Azerbaijan (Latin)
    Data &H082C, AZE, Azeri Azerbaijan (Cyrillic)
    Data &H042D, EUQ, Basque Spain
    Data &H042F, MKI, Macedonian Macedonia
    Data &H0436, AFK, Afrikaans South Africa
    Data &H0437, KAT, Georgian Georgia
    Data &H0438, FOS, Faeroese Faeroe Islands
    Data &H0439, HIN, Hindi India
    Data &H043E, MSL, Malay Malaysia
    Data &H083E, MSB, Malay Brunei Darussalam
    Data &H043F, KAZ, Kazak Kazakstan
    Data &H0441, SWK, Swahili Kenya
    Data &H0443, UZB, Uzbek Uzbekistan (Latin)
    Data &H0843, UZB, Uzbek Uzbekistan (Cyrillic)
    Data &H0444, TAT, Tatar Tatarstan
    Data &H0445, BEN, Bengali India
    Data &H0446, PAN, Punjabi India
    Data &H0447, GUJ, Gujarati India
    Data &H0448, ORI, Oriya India
    Data &H0449, TAM, Tamil India
    Data &H044A, TEL, Telugu India
    Data &H044B, KAN, Kannada India
    Data &H044C, MAL, Malayalam India
    Data &H044D, "ASM", Assamese India
    Data &H044E, MAR, Marathi India
    Data &H044F, SAN, Sanskrit India
    Data &H0457, KOK, Konkani India
    Data &H0000, Language-Neutral, Language-Neutral
    Data &H0400, Process Default Language, Process Default Language
    
    Local n		As Long
    
    	For n = 1 To DataCount Step 3
    		If lcid = Val(Read$(n)) Then
    			Function = Read$(n + 2)
    			Exit For
    		End If
    	Next n
    
    End Function 'Locale
    
    '****************************************
    
    Function VarType(ByVal pn As Long) As String
    Local n		As Long
    Local ls	As String
    
    Data "Empty=0"
    Data "Null=1"
    Data "I2=2"
    Data "I4=3"
    Data "R4=4"
    Data "R8=5"
    Data "Cy=6"
    Data "Date=7"
    Data "BStr=8"
    Data "Dispatch=9"
    Data "Error=10"
    Data "Bool=11"
    Data "Variant=12"
    Data "Unknown=13"
    Data "Decimal=14"
    Data
    Data "I1=16"
    Data "UI1=17"
    Data "UI2=18"
    Data "UI4=19"
    Data "I8=20"
    Data "UI8=21"
    Data "Int=22"
    Data "UInt=23"
    Data "Void=24"
    Data "HResult=25"
    Data "Ptr=26"
    Data "SafeArray=27"
    Data "CArray=28"
    Data "UserDefined=29"
    Data "LPStr=30"
    Data "LPWStr=31"
    Data , , ,
    Data "Record=36"
    '	end of continuous sequence
    Data "FileTime=64"
    Data "Blob=65"
    Data "Stream=66"
    Data "Storage=67"
    Data "Streamed_Object=68"
    Data "Stored_Object=69"
    Data "Blob_Object=70"
    Data "CF=71"
    Data "ClsID=72"
    'Data "Bstr_Blob=4095"
    
    	pn = pn And %VT_TypeMask
    	If pn <= 36 Then
    		n = pn + 1
    	Else
    		For n = 37 To DataCount
    			If Val(Remain$(Read$(n), "=")) = pn Then Exit For
    		Next n
    	End If
    
    	ls = Extract$(Read$(n), "=")
    	Function = IIf$(Len(ls), "VT_" & ls, "(Unknown)")
    
    End Function 'VarType
    
    '****************************************
    'offs = zero-based offset into the GUID table
    Function tlGuid(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    
    	If offs => 0 Then
    		Function = GuidTxt$(Mid$(cs, SegDir.pGuidTab.Offset + offs + 1, 16))
    	End If
    
    End Function 'tlGuid
    
    '****************************************
    'offs = zero-based offset into the name table
    Function tlName(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    Local NameIntro		As MSFT_NameIntro
    
    	If offs => 0 Then
    		offs = SegDir.pNameTab.Offset + offs + 1
    		LSet NameIntro = Mid$(cs, offs)
    		Function = $Dq & Mid$(cs, offs + SizeOf(MSFT_NameIntro), NameIntro.NameLen And &H0FF) & $Dq
    	End If
    
    End Function 'tlName
    
    '****************************************
    'offs = zero-based offset into the string table
    Function tlString(cs As String, SegDir As MSFT_SegDir, ByVal offs As Long) As String
    
    	If offs => 0 And offs < Len(cs) Then
    		offs = SegDir.pStringTab.Offset + offs + 1
    		Function = $Dq & Mid$(cs, offs + 2, CvWrd(cs, offs)) & $Dq
    	End If
    
    End Function 'tlString
    
    '****************************************
    
    Function DisSltg(cs As String) As Dword
    Local d			As Long
    Local i			As Long
    Local n			As Long
    Local p			As Long
    
    	UpdateLog "The SLTG format is not supported yet"
    
    	'Function =
    
    End Function 'DisSltg
    
    '****************************************
    'cs:		TypeLib data
    'SegDir:	the segment directory
    'pBase:		the zero-based offset to the FuncRec
    'nFunc:		number of functions
    'nProp:		number of properties
    'fo:		file handle
    Function DisFunction(cs As String, SegDir As MSFT_SegDir, ByVal pBase As Dword, ByVal nFunc As Long, ByVal nProp As Long) As Long
    Local d				As Long
    Local i				As Long
    Local j				As Long
    Local n				As Long
    Local ub			As Long
    Local p				As Dword
    Local pTmp			As Dword
    Local iElem			As Long
    Local nAttr			As Long
    Local ArraySize		As Long
    Local oParamInfo	As Long
    Local oDefValue		As Long
    
    Local ls			As String
    Local FuncRec		As MSFT_FuncRecord
    Local ParamInfo		As MSFT_ParameterInfo
    Local ElemDesc		As tagELEMDESC
    Local ParamDesc		As tagPARAMDESC
    Local NameIntro		As MSFT_NameIntro
    Local PropRec		As MSFT_PropRecord
    
    
    	p = pBase
    	ArraySize = CvDwd(cs, pBase + 1)
    	Print# %fo,
    	Print# %fo, "	Function record array size:	"; Hex$(ArraySize, 8)
    	p = p + 5 'advance past the "ArraySize" value
    
    	'----------------------------------------
    	'	Other function and property data
    	n = nFunc + nProp
    	If n > 0 Then
    		ub = n - 1
    		pTmp = StrPtr(cs) + pBase + ArraySize + 4
    		ReDim IdElem(ub)	As Long At pTmp
    
    		pTmp = pTmp + (4 * n)
    		ReDim oName(ub)		As Long At pTmp
    
    		pTmp = pTmp + (4 * n)
    		ReDim Refer(ub)		As Long At pTmp
    	End If
    
    
    	If nFunc Then
    
    		Print# %fo,
    		Print# %fo, "	----------------------------------------"
    		Print# %fo, "				Functions:"
    
    		For i = 1 To nFunc
    
    			LSet FuncRec = Mid$(cs, p)
    
    			Print# %fo, "	----------------------------------------"
    			Print# %fo, "	ID:			"; Hex$(IdElem(iElem), 8); " =="; Str$(IdElem(iElem))
    			Print# %fo, "	Name:		"; Hex$(oName(iElem), 8); " ==> "; tlName(cs, SegDir, oName(iElem))
    			Print# %fo, "	Reference:	"; Hex$(Refer(iElem), 8) 'offset to the corresponding function record
    			Incr iElem
    			Print# %fo, "	Record size:	"; Hex$(FuncRec.RecSize, 4)
    			Print# %fo, "	Unknown:		"; Hex$(FuncRec.Unknown, 4)
    			Print# %fo, "	Flags:			"; Hex$(FuncRec.Flags, 4); IIf$(FuncRec.Flags < 0, " = " & VarType(FuncRec.Flags), "")
    			Print# %fo, "	DataType:		"; Hex$(FuncRec.DataType, 4); " = " & VarType(FuncRec.DataType)
    
    #If %Def(%Study)
    			Print# %fo,
    			Print# %fo, "	Reserved:		"; Hex$(FuncRec.Reserved, 8)
    #EndIf
    
    			Print# %fo, "	Vtable offset:	"; Hex$(FuncRec.VtableOffset, 4)
    			Print# %fo, "	Func Desc Size:	"; Hex$(FuncRec.FuncDescSize, 4)
    
    
    			'	FKCCIC
    			'The bits in FKCCIC have the following meanings:
    			'0 - 2 = function kind (eg virtual)
    			'3 - 6 = Invocation kind
    			'7 means custom data is present
    			'8 - 11 = calling convention
    			'12 means one or more parameters have a default value
    			Print# %fo,
    			Print# %fo, "	FKCCIC (raw):	"; Hex$(FuncRec.FKCCIC, 8)
    			If (FuncRec.FKCCIC And &H01000) Then Print# %fo, "		Default value(s) present"
    			If (FuncRec.FKCCIC And &H040000) Then Print# %fo, "		oEntry is numeric"
    			If (FuncRec.FKCCIC And &H080) Then Print# %fo, "		Custom data present"
    
    			d = FuncRec.FKCCIC And &H0F00
    			Shift Right d, 8
    			Print# %fo, "		Calling convention:	"; Hex$(d, 2); " = " & Parse$($CallConv, d + 1)
    
    			d = FuncRec.FKCCIC And &H078 'this is a bit field
    			Shift Right d, 3
    			Print# %fo, "		Invocation kind:	"; Hex$(d, 2); " = ";
    			For n = 4 To 1 Step -1
    				If (d And %INVOKE_PROPERTYPUTREF) Then
    					Print# %fo, Parse$($InvoKind, n);
    					If (d And &H07) Then Print# %fo, ", ";
    				End If
    				Shift Left d, 1
    			Next n
    			Print# %fo,
    
    			d = FuncRec.FKCCIC And 7
    			Print# %fo, "		Function kind:		"; Hex$(d, 2); " = " & Parse$($FuncKind, d + 1)
    
    
    			'	Algorithm
    			'1) Dim the ParamInfo array at the end of the available space
    			'2) If (FKCCIC And &H1000) then Dim an array of default values just before the ParamInfo array
    			'3) Assume anything preceding the above arrays is the function's optional data
    			Print# %fo,
    			n = FuncRec.nParams
    			Print# %fo, "	Number of parameters:	"; Hex$(n, 4); " =="; Str$(n)
    
    			oParamInfo = p + FuncRec.RecSize - (n * SizeOf(MSFT_ParameterInfo)) 'must be one-based
    			oDefValue = oParamInfo
    
    			'If (FuncRec.FKCCIC And &H01000) Then 'there might be default values present
    			If (FuncRec.FKCCIC And &H01000) And (n > 0) Then 'there might be default values present
    				oDefValue = oDefValue - (n * 4)
    				ReDim DefVal(n - 1)		As Long At StrPtr(cs) + oDefValue - 1 'must be zero-based
    			End If
    
    
    			'Dim array for the function's optional data, if any
    			ub = (((oDefValue - SizeOf(MSFT_FuncRecord)) - p) \ 4) - 1
    			If ub => 0 Then
    
    				Print# %fo, "		----------------------------------------"
    				Print# %fo, "		Optional Data:"
    				ReDim OptData(ub)	As Long At StrPtr(cs) + p + SizeOf(MSFT_FuncRecord) - 1 'must be zero-based
    
    				Print# %fo, "		HelpContext:		"; Hex$(OptData(0), 8)
    				If ub < 1 Then Exit If
    
    				Print# %fo, "		HelpString:			"; Hex$(OptData(1), 8);
    				Print# %fo, " ==> " & tlString(cs, SegDir, OptData(1))
    				If ub < 2 Then Exit If
    
    				Print# %fo, "		Entry:				"; Hex$(OptData(2), 8)
    
    #If %Def(%Study)
    				If ub < 3 Then Exit If
    
    				Print# %fo, "		Reserved09:	"; Hex$(OptData(3), 8)
    				If ub < 4 Then Exit If
    
    				Print# %fo, "		Reserved0A:	"; Hex$(OptData(4), 8)
    #EndIf
    				If ub < 5 Then Exit If
    
    				Print# %fo, "		HelpStringContext:	"; Hex$(OptData(5), 8)
    				If ub < 6 Then Exit If
    
    				Print# %fo, "		Custom Data:		"; Hex$(OptData(6), 8)
    
    			End If
    			Print# %fo,
    
    
    			For j = 0 To n - 1
    
    				LSet ParamInfo = Mid$(cs, oParamInfo)
    				Print# %fo, "		----------------------------------------"
    				Print# %fo, "		Parameter number:	"; Str$(j + 1)
    				Print# %fo, "		DataType:			"; Hex$(ParamInfo.DataType, 4); IIf$(ParamInfo.DataType => 0, " = " & VarType(ParamInfo.DataType), "")
    				Print# %fo, "		Flags:				"; Hex$(ParamInfo.Flags, 4); " = "; VarType(ParamInfo.Flags)
    				Print# %fo, "		Name:				"; Hex$(ParamInfo.oName, 8); " ==> "; tlName(cs, SegDir, ParamInfo.oName)
    				Print# %fo, "		ParamFlags:			"; Hex$(ParamInfo.ParamFlags, 8); " =	";
    				If ParamInfo.ParamFlags Then
    					d = ParamInfo.ParamFlags
    					For n = 7 To 1 Step -1 ' 7 = ParseCount($ParamFlags)
    						If (d And %PARAMFLAG_FHASCUSTDATA) Then
    							Print# %fo, Parse$($ParamFlags, n);
    							If (d And &H03F) Then Print# %fo, ", ";
    						End If
    						Shift Left d, 1
    					Next n
    					Print# %fo,
    				Else
    					Print# %fo, "(none)"
    				End If
    
    				'If (ParamInfo.ParamFlags And %PARAMFLAG_FHASDEFAULT) Then
    				If (UBound(DefVal) => 0) And (ParamInfo.ParamFlags And %PARAMFLAG_FHASDEFAULT) Then
    
    					If DefVal(j) < 0 Then 'the default value is in the lower three bytes
    						DefVal(j) = DefVal(j) And &H0FFFFFF
    					Else 'it's an offset into the CustomData table
    						DefVal(j) = Cvl(cs, SegDir.pCustData.Offset + DefVal(j) + 3)
    					End If
    					Print# %fo, "		Default Value:		"; Hex$(DefVal(j), 8); " =="; Str$(DefVal(j))
    
    				End If
    
    				oParamInfo = oParamInfo + SizeOf(MSFT_ParameterInfo)
    
    			Next j
    
    			p = p + FuncRec.RecSize
    
    		Next i
    
    	End If 'nFunc
    
    
    
    	'do the properties
    	If nProp Then
    
    		Print# %fo,
    		Print# %fo, "	----------------------------------------"
    		Print# %fo, "		 Properties:"
    
    		For i = 1 To nProp
    
    			LSet PropRec = Mid$(cs, p)
    
    			Print# %fo, "	----------------------------------------"
    			Print# %fo, "	ID:			"; Hex$(IdElem(iElem), 8); " =="; Str$(IdElem(iElem))
    			Print# %fo, "	Name:		"; Hex$(oName(iElem), 8); " ==> "; tlName(cs, SegDir, oName(iElem))
    			Print# %fo, "	Reference:	"; Hex$(Refer(iElem), 8) 'offset to the corresponding function record
    			Incr iElem
    			Print# %fo, "	Record size (the low byte):	"; Hex$(PropRec.RecSize, 4)
    			Print# %fo, "	Property number?:			"; Hex$(PropRec.PropNum, 4)
    			Print# %fo, "	Flags:						"; Hex$(PropRec.Flags, 4); IIf$(PropRec.Flags < 0, " = " & VarType(PropRec.Flags), "")
    			Print# %fo, "	DataType:					"; Hex$(PropRec.DataType, 4); " = "; VarType(PropRec.DataType)
    
    			Print# %fo, "	Variable kind:				"; Hex$(PropRec.VarKind, 4); " = ";
    			d = PropRec.VarKind
    			For n = 13 To 1 Step -1 ' 13 = ParseCount($VarFlags)
    				If (d And %VARFLAG_FIMMEDIATEBIND) Then
    					Print# %fo, Parse$($VarFlags, n);
    					If (d And &H0FFF) Then Print# %fo, ", ";
    				End If
    				Shift Left d, 1
    			Next n
    			Print# %fo,
    
    			Print# %fo, "	Variable desc size:			"; Hex$(PropRec.VarDescSize, 4)
    			Print# %fo, "	Value/Offset:				"; Hex$(PropRec.OffsValue, 8)
    
    			If PropRec.RecSize > 20 Then '20 = (5 * SizeOf(Long))
    
    				Print# %fo, "	HelpContext:		"; Hex$(PropRec.HelpContext, 8)
    
    				If PropRec.RecSize > 24 Then '24 = (6 * SizeOf(Long))
    					Print# %fo, "	HelpString:			"; Hex$(PropRec.oHelpString, 8);
    					Print# %fo, " ==> "; tlString(cs, SegDir, PropRec.oHelpString)
    
    					If PropRec.RecSize > 32 Then '32 = (8 * SizeOf(Long))
    
    						If PropRec.RecSize > 36 Then '36 = (9 * SizeOf(Long))
    							Print# %fo, "	HelpStringContext:	"; Hex$(PropRec.HelpStringContext, 8)
    						End If
    
    					End If
    
    				End If
    
    			End If
    
    			Print# %fo,
    			p = p + PropRec.RecSize
    
    		Next i
    
    	End If 'nProp
    
    
    #If %Def(%Study)
    	'----------------------------------------
    	'	Dump arrays of function and property: IDs, names and references
    	'----------------------------------------
    	' This is redundant, since the information is printed along with the
    	'functions and properties they pertain to.
    	n = nFunc + nProp
    	If n > 0 Then
    	
    		iElem = 0
    	
    		If nFunc Then
    			Print# %fo,
    			Print# %fo, "	----------------------------------------"
    			Print# %fo, "		 Other Function Data:"
    		End If
    	
    		For iElem = 0 To ub Step 1
    	
    			If n = nProp Then 'the functions are done, so do the properties
    				Print# %fo,
    				Print# %fo, "	----------------------------------------"
    				Print# %fo, "		 Other Property Data:"
    			End If
    			Decr n
    	
    			'ID number of the function or property
    			Print# %fo, "	----------------------------------------"
    			Print# %fo, "	ID:			"; Hex$(IdElem(iElem), 8); " =="; Str$(IdElem(iElem))
    	
    			'offset to names in the name table
    			Print# %fo, "	Name:		"; Hex$(oName(iElem), 8);
    			Print# %fo, " ==> "; tlName(cs, SegDir, oName(iElem))
    	
    			'offset to the corresponding function record
    			Print# %fo, "	Reference:	"; Hex$(Refer(iElem), 8)
    			Print# %fo,
    	
    		Next iElem
    	
    	End If
    
    #EndIf
    
    	'Function =
    
    End Function 'DisFunction
    
    '****************************************
    'cs contains the TypeLib data
    'ls contains the name of the source file
    Function DisTypeLib(cs As String, ps As String) As Dword
    Local d			 As Long
    Local i			 As Long
    Local n			 As Long
    Local p			 As Long
    Local fName		 As Long 'TypeLib file name flag
    Local TlbHdr	 As MSFT_Header
    Local SegDir	 As MSFT_SegDir
    Local TypInfo	 As MSFT_TypeInfoBase
    Local ImpInfo	 As MSFT_ImpInfo
    Local IFileInfo	 As TLBImpLib
    Local RefRec	 As MSFT_RefRecord
    Local GuidEntry	 As MSFT_GuidEntry
    Local NameIntro	 As MSFT_NameIntro
    Local TypDsc	 As TYPEDESC 'a simplified substitute for a tagTYPEDESC
    Local AryDsc	 As ARRAYDESC
    Local SafBnd	 As SAFEARRAYBOUND
    
    Local ls		As String
    
    
    	'--------------------------------------
    	'open an output file for the disassembly
    	Try
    		#If %Def(%Study)
    			CurFile = ps
    			Note "" 'reset message counter
    		#EndIf
    		ls = Mid$(ps, InStr(-1, ps, "\") + 1)
    		ls = MCase$(Extract$(ls, ".")) & ".txt"
    		Open LocalPath & "\" & ls For Output As %fo
    		UpdateLog "Output file: " & ls
    	Catch
    		UpdateLog "Error opening output file: " & ls
    		Exit Function
    	End Try
    
    	'--------------------------------------
    	'print the TypeLib Header
    	LSet TlbHdr = cs
    	If TlbHdr.Magic1 = %SLTG_SIGNATURE Then
    		Function = DisSltg(cs)
    		Close# %fo
    		Exit Function
    	ElseIf TlbHdr.Magic1 <> %MSFT_SIGNATURE Then
    		Print# %fo, "Unrecognized magic value: " & Left$(cs, 4)
    		Exit Function
    	End If
    
    	'get the segment directory in advance
    	fName = IIf&((TlbHdr.VarFlags And %HELPDLLFLAG), 4, 0)
    	p = SizeOf(TlbHdr) + (4 * (TlbHdr.nrTypeInfos)) + fName + 1
    	LSet SegDir = Mid$(cs, p)
    
    
    	Print# %fo, "*************************"
    	Print# %fo, "TypeLib Header"
    	Print# %fo, "*************************"
    	Print# %fo, "Magic 1:		"; Hex$(TlbHdr.Magic1, 8); " = "; Left$(cs, 4)	'&H5446534D """MSFT"""
    	Print# %fo, "Magic 2:		"; Hex$(TlbHdr.Magic2, 8)	'&H00010002 version number?
    
    	'position of libid in guid table (should be, else -1)
    	Print# %fo, "GUID:			"; Hex$(TlbHdr.PosGuid, 8); " ==> "; tlGuid(cs, SegDir, TlbHdr.PosGuid)
    
    	Print# %fo, "Locale ID:		"; Hex$(TlbHdr.lcid, 8); " = "; Locale(TlbHdr.lcid) 'locale id
    	Print# %fo, "Locale ID 2:	"; Hex$(TlbHdr.lcid2, 8)
    
    	'VarFlags (largely unknown):
    	'	* the lower nibble is SysKind
    	'	* bit 5 is set if a helpfile is defined
    	'	* bit 8 is set if a help dll is defined
    	Print# %fo, "VarFlags:		"; Hex$(TlbHdr.VarFlags, 8)
    	Print# %fo, "	System:		"; Parse$($SysKind, (TlbHdr.VarFlags And 7) + 1)
    	Print# %fo, "	Help file"; IIf$((TlbHdr.VarFlags And 16), " ", " not "); "specified"
    	Print# %fo, "	Help file is"; IIf$((TlbHdr.VarFlags And 256), " ", " not "); "in a DLL"
    
    	Print# %fo, "Version:	"; Hex$(TlbHdr.version, 8)
    	Print# %fo, "Flags:		"; Hex$(TlbHdr.Flags, 8)
    
    	Print# %fo, "Number of TypeInfo's:	"; Hex$(TlbHdr.nrTypeInfos, 8); " =="; Str$(TlbHdr.nrTypeInfos)	'number of TypeInfo's
    
    	Print# %fo, "HelpString:			"; Hex$(TlbHdr.HelpString, 8);	'position of HelpString in stringtable
    	Print# %fo, " ==> "; tlString(cs, SegDir, TlbHdr.HelpString)
    
    	Print# %fo, "HelpStringContext:	"; Hex$(TlbHdr.HelpStringContext, 8)
    	Print# %fo, "HelpContext:		"; Hex$(TlbHdr.HelpContext, 8)
    
    	Print# %fo, "Name Table:"
    	Print# %fo, "	Names:		"; Hex$(TlbHdr.NameTableCount, 8); " =="; Str$(TlbHdr.NameTableCount)	'number of names in name table
    	Print# %fo, "	Characters:	"; Hex$(TlbHdr.NameTableChars, 8); " =="; Str$(TlbHdr.NameTableChars)	'number of characters in name table
    
    	Print# %fo,
    	Print# %fo, "Name:		"; Hex$(TlbHdr.NameOffset, 8); " ==> "; tlName(cs, SegDir, TlbHdr.NameOffset) 'offset of name in name table
    	Print# %fo, "Helpfile:	"; Hex$(TlbHdr.HelpFile, 8); " ==> "; tlString(cs, SegDir, TlbHdr.HelpFile) 'position of helpfile in stringtable
    
    	'if -1 no custom data, else it is offset in custom data/guid offset table
    	Print# %fo, "Custom data offset:			"; Hex$(TlbHdr.CustomDataOffset, 8)
    
    #If %Def(%Study)
    	Print# %fo, "Reserved44:	"; Hex$(TlbHdr.Res44, 8)		'unknown always: &H20 (guid hash size?)
    	Print# %fo, "Reserved48:	"; Hex$(TlbHdr.Res48, 8)		'unknown always: &H80 (name hash size?)
    #EndIf
    
    	Print# %fo, "hRefType to IDispatch:		"; Hex$(TlbHdr.dispatchpos, 8) 'hRefType to IDispatch, or -1 if no IDispatch
    	Print# %fo, "Number of Import Info's:	"; Hex$(TlbHdr.nImpInfos, 8); " =="; Str$(TlbHdr.nImpInfos) 'number of ImpInfos
    
    	p = SizeOf(TlbHdr) + 1
    	If fName Then
    		d = CvDwd(cs, p)
    		Print# %fo, "TypeLib file name:			"; Hex$(d, 8); " ==> "; tlString(cs, SegDir, d)
    	End If
    
    	'--------------------------------------
    	'print the (TypeInfo ?) offsets
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "Offsets to TypeInfo Data"
    	Print# %fo, "*************************"
    	p = p + fName
    	For n = 1 To TlbHdr.nrTypeInfos
    		Print# %fo, Hex$(CvDwd(cs, p), 8)
    		p = p + 4
    		If p => Len(cs) Then Exit For
    	Next n
    
    
    	'--------------------------------------
    	'print the segment directory contents
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "Segment Directory (Segment name: Offset, Length)..."
    	Print# %fo, "*************************"
    	Print# %fo, "Type Info Table:		"; Hex$(SegDir.pTypeInfoTab.Offset, 8); ", "; Hex$(SegDir.pTypeInfoTab.Length, 8)
    	Print# %fo, "Import Info:			"; Hex$(SegDir.pImpInfo.Offset, 8); ", "; Hex$(SegDir.pImpInfo.Length, 8)
    	Print# %fo, "Imported Libraries:		"; Hex$(SegDir.pImpFiles.Offset, 8); ", "; Hex$(SegDir.pImpFiles.Length, 8)
    	Print# %fo, "References Table:		"; Hex$(SegDir.pRefTab.Offset, 8); ", "; Hex$(SegDir.pRefTab.Length, 8)
    	Print# %fo, "Lib Table:				"; Hex$(SegDir.pLibtab.Offset, 8); ", "; Hex$(SegDir.pLibtab.Length, 8)
    	Print# %fo, "GUID Table:				"; Hex$(SegDir.pGuidTab.Offset, 8); ", "; Hex$(SegDir.pGuidTab.Length, 8)
    	Print# %fo, "Reserved 07:			"; Hex$(SegDir.Res07.Offset, 8); ", "; Hex$(SegDir.Res07.Length, 8)
    	Print# %fo, "Name Table:				"; Hex$(SegDir.pNameTab.Offset, 8); ", "; Hex$(SegDir.pNameTab.Length, 8)
    	Print# %fo, "String Table:			"; Hex$(SegDir.pStringtab.Offset, 8); ", "; Hex$(SegDir.pStringtab.Length, 8)
    	Print# %fo, "Type Descriptors:		"; Hex$(SegDir.pTypdescTab.Offset, 8); ", "; Hex$(SegDir.pTypdescTab.Length, 8)
    	Print# %fo, "Array Descriptors:		"; Hex$(SegDir.pArrayDescriptions.Offset, 8); ", "; Hex$(SegDir.pArrayDescriptions.Length, 8)
    	Print# %fo, "Custom Data:			"; Hex$(SegDir.pCustData.Offset, 8); ", "; Hex$(SegDir.pCustData.Length, 8)
    	Print# %fo, "Custom Data/GUID's:		"; Hex$(SegDir.pCDGuids.Offset, 8); ", "; Hex$(SegDir.pCDGuids.Length, 8)
    	Print# %fo, "Reserved 0E:			"; Hex$(SegDir.Res0E.Offset, 8); ", "; Hex$(SegDir.Res0E.Length, 8)
    	Print# %fo, "Reserved 0F:			"; Hex$(SegDir.Res0F.Offset, 8); ", "; Hex$(SegDir.Res0F.Length, 8)
    
    
    
    	'--------------------------------------
    	'check two entries to be sure we found it
    	If SegDir.pTypeInfoTab.Res0C <> &H0F Or SegDir.pImpInfo.Res0C <> &H0F Then
    		UpdateLog("Can't find the table directory")
    		Exit Function
    	End If
    
    
    
    	'**************************************
    	'	Print the data from the segments
    	'**************************************
    
    	'--------------------------------------
    	'print the TypeInfo structures
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "TypeInfo Data..."
    	Print# %fo, "*************************"
    	i = 0
    	p = SegDir.pTypeInfoTab.Offset + 1
    	n = p + SegDir.pTypeInfoTab.Length
    	Do Until p => n
    
    		Incr i
    		Print# %fo, "-------------------------"
    		Print# %fo, "TypeInfo number:	"; Format$(i)
    		LSet TypInfo = Mid$(cs, p)
    
    		Print# %fo, "Type kind:	"; Hex$(TypInfo.TypeKind, 8); " And &H0F = "; Parse$($TKind, (TypInfo.TypeKind And &H0F) + 1)
    		d = TypInfo.TypeKind : Shift Right d, 11
    		Print# %fo, "	Alignment: ("; Hex$(TypInfo.TypeKind, 8); "/0800) And &H1F = "; Hex$(d And &H1F, 4)
    
    		'"Memory offset" and function descriptors are printed at the end of the TypeInfo section
    
    #If %Def(%Study)
    		Print# %fo, "Reserved 02:	"; Hex$(TypInfo.Res2, 8)
    		Print# %fo, "Reserved 03:	"; Hex$(TypInfo.Res3, 8)
    
    		Print# %fo, "Reserved 04:	"; Hex$(TypInfo.Res4, 8)
    		Print# %fo, "Reserved 05:	"; Hex$(TypInfo.Res5, 8)
    #EndIf
    
    		'counts of functions and properties
    		Print# %fo,
    		Print# %fo, "Function count:	"; Hex$(TypInfo.cFuncs, 4); " =="; Str$(TypInfo.cFuncs)
    		Print# %fo, "Property count:	"; Hex$(TypInfo.cProps, 4); " =="; Str$(TypInfo.cProps)
    
    #If %Def(%Study)
    		Print# %fo, "Reserved 07:	"; Hex$(TypInfo.Res7, 8)
    		Print# %fo, "Reserved 08:	"; Hex$(TypInfo.Res8, 8)
    		Print# %fo, "Reserved 09:	"; Hex$(TypInfo.Res9, 8)
    		Print# %fo, "Reserved 0A:	"; Hex$(TypInfo.ResA, 8)
    #EndIf
    
    		Print# %fo, "GUID:	"; Hex$(TypInfo.PosGuid, 8); " ==> "; tlGuid(cs, SegDir, TypInfo.PosGuid)
    		Print# %fo, "Flags:	"; Hex$(TypInfo.Flags, 8)
    		Print# %fo, "Name:	"; Hex$(TypInfo.NameOffset, 8); " ==> "; tlName(cs, SegDir, TypInfo.NameOffset)
    		Print# %fo, "Version:	"; Hex$(TypInfo.version, 8)
    
    		Print# %fo, "Doc String Offset:	"; Hex$(TypInfo.docstringoffs, 8);
    		Print# %fo, " ==> "; tlString(cs, SegDir, TypInfo.docstringoffs)
    
    		Print# %fo, "HelpStringContext:	"; Hex$(TypInfo.HelpStringContext, 8)
    		Print# %fo, "HelpContext:		"; Hex$(TypInfo.HelpContext, 8)
    
    		Print# %fo,
    		Print# %fo, "Offset in custom data table:	"; Hex$(TypInfo.oCustData, 8)
    		Print# %fo, "Number of implemented types:	"; Hex$(TypInfo.cImplTypes, 4); " =="; Str$(TypInfo.cImplTypes)
    		Print# %fo, "Virtual table size:	"; Hex$(TypInfo.cbSizeVft, 4)
    		Print# %fo, "Size:	"; Hex$(TypInfo.Size, 8)
    
    		'position in type description table or in base interfaces
    		'if coclass:	offset in reftable
    		'if interface:	reference to inherited interface
    		'if module:		offset to DLL name in name table
    
    #If %Def(%Study)
    		Select Case (TypInfo.TypeKind And &H0F)
    			'Case %TKIND_ENUM
    			'Case %TKIND_RECORD
    			'Case %TKIND_MODULE 'offset to DLL name in string table
    			'Case %TKIND_INTERFACE 'reference to inherited interface?
    			'Case %TKIND_DISPATCH
    			'Case %TKIND_COCLASS 'offset in reftable
    			Case %TKIND_ALIAS
    				Note "TKIND_ALIAS"
    			Case %TKIND_UNION
    				Note "TKIND_UNION"
    			'Case %TKIND_MAX
    			'Case Else
    
    		End Select
    #EndIf
    
    		'Print# %fo, "DataType1:	"; Hex$(TypInfo.DataType1, 8)
    		Select Case (TypInfo.TypeKind And &H0F)
    
    			'Case %TKIND_ENUM
    
    			'Case %TKIND_RECORD
    
    			Case %TKIND_MODULE 'offset to DLL name in string table
    				Print# %fo, "DLL Name:	"; Hex$(TypInfo.DataType1, 8); " ==> ";
    				If TypInfo.DataType1 => 0 Then Print# %fo, tlName(cs, SegDir, TypInfo.DataType1)
    
    			Case %TKIND_INTERFACE 'reference to inherited interface?
    				Print# %fo, "Inherited interface?:	"; Hex$(TypInfo.DataType1, 8)
    
    			'Case %TKIND_DISPATCH
    
    			Case %TKIND_COCLASS 'offset in reftable
    				Print# %fo, "Reference table offset:	"; Hex$(TypInfo.DataType1, 8)
    
    			Case %TKIND_ALIAS 'the following is partly translated ReactOS code
    
    					If TypInfo.DataType1 < 0 Then
    						d = TypInfo.DataType1 And %VT_TYPEMASK
    					Else 'get index into Lib Table?
    						d = TypInfo.DataType1 \ 8 '?
    					End If
    
    					If TypInfo.DataType1 = %VT_UserDefined Then 'do RefType
    					End If
    
    			'Case %TKIND_UNION
    
    			'Case %TKIND_MAX
    
    			Case Else
    				Print# %fo, "DataType1:	"; Hex$(TypInfo.DataType1, 8)
    
    		End Select
    
    		'if &H8000, entry above is valid, else it is zero?
    		Print# %fo, "DataType2:	"; Hex$(TypInfo.DataType2, 8)
    
    #If %Def(%Study)
    		Print# %fo, "Reserved 18:	"; Hex$(TypInfo.Res18, 8)
    		Print# %fo, "Reserved 19:	"; Hex$(TypInfo.Res19, 8)
    #EndIf
    
    		Print# %fo,
    		Print# %fo, "Memory offset:	"; Hex$(TypInfo.MemOffset, 8)
    		If TypInfo.MemOffset < Len(cs) Then 'do function/property records
    			DisFunction(cs, SegDir, TypInfo.MemOffset, TypInfo.cFuncs, TypInfo.cProps)
    		End If
    
    		p = p + SizeOf(TypInfo)
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print ImportInfo ?
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "ImportInfo"
    	Print# %fo, "*************************"
    	i = 0
    	p = SegDir.pImpInfo.Offset + 1
    	n = p + SegDir.pImpInfo.Length
    	Do Until p => n
    
    		Incr i
    		LSet ImpInfo = Mid$(cs, p)
    		Print# %fo, "--------------------------------------------"
    		Print# %fo, "Import Info number:	"; Format$(i)
    		Print# %fo, "Count:				"; Format$(ImpInfo.Flags And &H0FFFF??)
    		Print# %fo, "Offset in import file table:	"; Hex$(ImpInfo.oImpFile, 8)
    
    		If (HiWrd(ImpInfo.Flags) And 1??) Then
    			Print# %fo, "GUID:	"; Hex$(ImpInfo.oGuid, 8); " ==> "; tlGuid(cs, SegDir, ImpInfo.oGuid)
    		Else
    			Print# %fo, "TypeInfo index:	"; Hex$(ImpInfo.oGuid, 8); " =="; Str$(ImpInfo.oGuid)
    		End If
    
    		Print# %fo, "Type:	"; Parse$($TKind, HiByt(HiWrd(ImpInfo.Flags)))
    
    		p = p + SizeOf(ImpInfo)
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print Imported Type Libs
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "Imported Type Libs"
    	Print# %fo, "*************************"
    	p = SegDir.pImpFiles.Offset + 1
    	n = p + SegDir.pImpFiles.Length
    	Do Until p => n
    		LSet IFileInfo = Mid$(cs, p)
    		Print# %fo, "--------------------------------------------"
    		Print# %fo, "GUID:			"; Hex$(IFileInfo.oGUID, 8); " ==> "; tlGuid(cs, SegDir, IFileInfo.oGuid)
    		Print# %fo, "Locale ID?:		"; Hex$(IFileInfo.LCID, 8); " = "; Locale(IFileInfo.LCID)
    		Print# %fo, "Major version:	"; Hex$(IFileInfo.MajVer, 4)
    		Print# %fo, "Minor version:	"; Hex$(IFileInfo.MinVer, 4)
    
    		d = IFileInfo.Size
    		Shift Right d, 2
    		Print# %fo, "Size = "; Hex$(IFileInfo.Size, 4); "/4 = "; Hex$(d, 4)
    		Print# %fo, "File name:	"; Mid$(cs, p + SizeOf(TLBImpLib), d)
    
    		p = p + ((SizeOf(TLBImpLib) + IFileInfo.Size + 3) And Not 3) 'advance to next one
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print References Table
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "References Table"
    	Print# %fo, "*************************"
    	p = SegDir.pRefTab.Offset + 1
    	n = p + SegDir.pRefTab.Length
    	Do Until p => n
    		LSet RefRec = Mid$(cs, p)
    		Print# %fo, "--------------------------------------------"
    
    		'if it's a multiple of 4, it's an offset in the TypeInfo table,
    		'otherwise it's an offset in the external reference table with
    		'an offset of 1
    		Print# %fo, "Reference type:	"; Hex$(RefRec.RefType, 8);
    		If (RefRec.RefType And &H03) Then
    			Print# %fo, "	==> (External Reference Table)"
    		Else
    			Print# %fo, "	==> (TypeInfo)"
    		End If
    
    		Print# %fo, "Flags:			"; Hex$(RefRec.Flags, 8)
    		If RefRec.oCustData => 0 Then Print# %fo, "Custom data:	"; Hex$(RefRec.oCustData, 8)
    		If RefRec.oNext => 0 Then Print# %fo, "Next offset:	"; Hex$(RefRec.oNext, 8)
    		p = p + SizeOf(MSFT_RefRecord)
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print "Lib Table"	(unknown format)
    	'always exists, always the same size (&H80)
    	'...hash table with offsets to GUID?
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "Lib Table (offsets into GUID table)"
    	Print# %fo, "*************************"
    	p = SegDir.pLibtab.Offset + 1
    	n = p + SegDir.pLibtab.Length
    	Do Until p => n
    		d = Cvl(cs, p)
    		If d => 0 Then Print# %fo, Hex$(d, 8)
    		p = p + 4
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print GUID table
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "GUID Table"
    	Print# %fo, "*************************"
    	p = SegDir.pGuidTab.Offset + 1
    	n = p + SegDir.pGuidTab.Length
    	Do Until p => n
    
    		LSet GuidEntry = Mid$(cs, p)
    		Print# %fo, "--------------------------------------------"
    		Print# %fo, "GUID:	"; GuidTxt$(GuidEntry.Guid)
    		'	The meaning of .hRefType:
    		' = -2 for a TypeLib GUID
    		'TypeInfo offset for TypeInfo GUID,
    		'Otherwise, the low two bits:
    		'	= 01 for an imported TypeInfo
    		'	= 10 for an imported TypeLib (used by imported TypeInfos)
    		Print# %fo, "Href Type:	"; Hex$(GuidEntry.hRefType, 8);
    		If GuidEntry.hRefType = -2 Then
    			Print# %fo, " = TypeLib GUID"
    		ElseIf (GuidEntry.hRefType And 3) = 1 Then
    			Print# %fo, " = Imported TypeInfo"
    		ElseIf (GuidEntry.hRefType And 3) = 2 Then
    			Print# %fo, " = Imported TypeLib"
    		Else
    			Print# %fo, " = Offset?"
    		End If
    
    		Print# %fo, "Next hash:	"; Hex$(GuidEntry.NextHash, 8)
    		p = p + SizeOf(MSFT_GuidEntry)
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print "Reserved 07" (length is "always" &H200)
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, " Table with Offsets into the Name Table (""Reserved 07"")"
    	Print# %fo, "*************************"
    	p = SegDir.Res07.Offset + 1
    	n = p + SegDir.Res07.Length
    	Do Until p => n
    		d = Cvl(cs, p)
    		If d => 0 Then Print# %fo, Hex$(d, 8)
    		p = p + 4
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print Name Table
    	'(this keeps p's value zero-based)
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "Name Table"
    	Print# %fo, "*************************"
    	p = SegDir.pNameTab.Offset
    	n = p + SegDir.pNameTab.Length
    	Do Until p => n
    
    		LSet NameIntro = Mid$(cs, p + 1)
    		Print# %fo, "--------------------------------------------"
    		If NameIntro.hRefType <> -1 Then Print# %fo, "Offset:			"; Hex$(NameIntro.hRefType, 8)
    		Print# %fo, "Next hash:		"; Hex$(NameIntro.NextHash, 8)
    		d = LoByt(NameIntro.NameLen)
    		Print# %fo, "Name length:	"; Hex$(d, 2); " =="; Str$(d)
    		Print# %fo, "Flags?...		"; Hex$(HiByt(LoWrd(NameIntro.NameLen)), 2)
    		Print# %fo, "Hash code:		"; Hex$(HiWrd(NameIntro.NameLen), 4)
    
    		p = p + SizeOf(NameIntro)
    		Print# %fo, $Dq; Mid$(cs, p + 1, d); $Dq
    		p = p + d
    		p = (p + 3) And &HFFFFFFFC 'advance to next DWord-aligned offset
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print String Table
    	'(this keeps p's value zero-based)
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "String Table"
    	Print# %fo, "*************************"
    	p = SegDir.pStringtab.Offset
    	n = p + SegDir.pStringtab.Length
    	i = 1 'string number
    	Do Until p => n
    		d = CvWrd(cs, p + 1)
    		Print# %fo, Format$(i); ")	"; Mid$(cs, p + 3, d)
    		p = p + Max&(d + 2, 8) 'every entry, length-plus-text, is a minimum of eight bytes
    		p = (p + 3) And &HFFFFFFFC 'advance to next Dword-aligned offset
    		Incr i
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print Type Descriptors
    	Print# %fo,
    	Print# %fo, "*************************"
    	Print# %fo, "Type Descriptors"
    	Print# %fo, "*************************"
    	p = SegDir.pTypdescTab.Offset + 1
    	n = p + SegDir.pTypdescTab.Length
    	Do Until p => n
    
    		Print# %fo, "-------------------------"
    		Print# %fo, "Raw:	"; Hex$(CvDwd(cs, p), 8), Hex$(CvDwd(cs, p + 4), 8)
    
    		LSet TypDsc = Mid$(cs, p)
    
    		Print# %fo, "Data type 1 = "; Hex$(TypDsc.v2, 4); Hex$(TypDsc.v1, 4);
    		If (TypDsc.v2 And &H7FFE) = &H7FFE Then
    			Print# %fo, " = ";
    		ElseIf (TypDsc.v2 And %VT_Vector) Then
    			Print# %fo, " = VT_Vector, ";
    		ElseIf (TypDsc.v2 And %VT_Array) Then
    			Print# %fo, " = VT_Array, ";
    		ElseIf (TypDsc.v2 And %VT_ByRef) Then
    			Print# %fo, " = VT_ByRef, ";
    		'ElseIf (TypDsc.v2 And %VT_Reserved) Then
    		Else
    			Print# %fo, " = ";
    		End If
    
    		Print# %fo, VarType(TypDsc.v1);
    
    		If (TypDsc.v2 And &H7FFE) = &H7FFE Then
    			Print# %fo,
    		Else
    			Print# %fo, " == base type: "; VarType(TypDsc.v2 And %VT_TypeMask)
    		End If
    
    
    		If LoByt(TypDsc.v1) = %VT_Ptr Or LoByt(TypDsc.v1) = %VT_SafeArray Then
    
    			If TypDsc.v4 < 0 Then  'offset into type descriptor table
    				Print# %fo, "Type descriptor table offset:	"; Hex$(TypDsc.v3 And &H07FF8, 4)
    			Else 'file offset to type descriptor
    				d = MakLng(TypDsc.v1, TypDsc.v2)
    				Print# %fo, "Type descriptor file offset:	"; Hex$(d And (TypDsc.v3\8), 8)
    			End If
    
    		ElseIf LoByt(TypDsc.v1) = %VT_CArray Then
    			Print# %fo, "Array descriptor offset:	"; Hex$(TypDsc.v3, 8)
    		ElseIf LoByt(TypDsc.v1) = %VT_UserDefined Then
    			'd = p + (MakLng(TypDsc.v3, TypDsc.v4) And &H0FFFFFFF8&)
    			Print# %fo, "Type descriptor offset:		"; Hex$(MakLng(TypDsc.v3, TypDsc.v4) And &H0FFFFFFF8&, 8)
    		End If
    
    		p = p + SizeOf(tagTYPEDESC)
    
    	Loop While p <= Len(cs)
    
    
    	'--------------------------------------
    	'Print Array Descriptors
    	If SegDir.pArrayDescriptions.Length Then
    
    #If %Def(%Study)
    	Note "Array(s) found"
    #EndIf
    
    		' What do the lower bits of td(1) mean (when td(1) < 0)?
    		' What is td(3) (it gets over-written when td(1) < 0) ?
    		Print# %fo,
    		Print# %fo, "*************************"
    		Print# %fo, "Array Descriptors"
    		Print# %fo, "*************************"
    		p = SegDir.pArrayDescriptions.Offset + 1
    		n = p + SegDir.pArrayDescriptions.Length
    		Do Until p => n
    
    			LSet AryDsc = Mid$(cs, p)
    			ReDim td(3)		As Integer At VarPtr(AryDsc)
    
    			Print# %fo, "--------------------------------------------"
    			Print# %fo, "Raw:	"; Hex$(CvDwd(cs, p), 8); ", "; Hex$(CvDwd(cs, p + 4), 8); ", "; Hex$(CvDwd(cs, p + 8), 8); ", "; Hex$(CvDwd(cs, p + 12), 8)
    
    			If AryDsc.u.hRefType => 0 Then 'a pointer to ANOTHER array descriptor?
    				AryDsc.u.lpadesc = (AryDsc.u.lpadesc And &H07FFF) \ 8
    				Print# %fo, "Offset to array descriptor:	"; Hex$(AryDsc.u.lpadesc, 8)
    			Else 'the low word contains the variable-type code
    				Print# %fo, "Href Type:	"; Hex$(AryDsc.u.hRefType, 8)
    				AryDsc.vt = td(0) And %VT_TypeMask
    			End If
    
    			If (AryDsc.vt And 255) = 0 Then d = HiByt(AryDsc.vt) Else d = AryDsc.vt
    			Print# %fo, "Variable type:	"; Hex$(AryDsc.vt, 4); " = "; VarType(d)
    			Print# %fo, "Number of dimensions:	"; Hex$(AryDsc.cDims, 4); " =="; Str$(AryDsc.cDims)
    
    			p = p + SizeOf(ARRAYDESC) - SizeOf(SAFEARRAYBOUND)
    			For i = 1 To AryDsc.cDims
    				LSet SafBnd = Mid$(cs, p)
    				Print# %fo, "("; Format$(i); ")	"; "Elements: "; Hex$(SafBnd.cElements, 8); " =="; Str$(SafBnd.cElements); "	Lower bound: "; Hex$(SafBnd.lLbound, 8); " =="; Str$(SafBnd.lLbound)
    				p = p + SizeOf(SAFEARRAYBOUND)
    				If p => Len(cs) Then Exit Do
    			Next i
    
    		Loop While p <= Len(cs)
    
    	End If
    
    	'--------------------------------------
    	'Print Custom Data
    	'a guess as to the storage format...
    	'Type CustomData
    	'	cWords				As Word
    	'	aData(cWords - 1)	As Word
    	'	sGUID				As Guid
    	'End Type
    	If SegDir.pCustData.Length Then
    
    #If %Def(%Study)
    	If SegDir.pCustData.Length > 16 Then
    		Note "More than 16 bytes of custom data"
    	End If
    #EndIf
    		'custom data and default parameter values
    		Print# %fo,
    		Print# %fo, "*************************"
    		Print# %fo, "Custom Data"
    		Print# %fo, "*************************"
    		p = SegDir.pCustData.Offset + 1
    		n = p + SegDir.pCustData.Length
    		Do Until p => n
    			Print# %fo, Hex$(CvDwd(cs, p), 8)
    			p = p + 4
    		Loop While p <= Len(cs)
    
    	End If
    
    
    	'--------------------------------------
    	'Print offsets of GUID's and into the
    	If SegDir.pCDGuids.Length Then
    		'custom data table
    		Print# %fo,
    		Print# %fo, "*************************"
    		Print# %fo, "Offsets of GUID's"
    		Print# %fo, "*************************"
    		p = SegDir.pCDGuids.Offset + 1
    		n = p + SegDir.pCDGuids.Length
    		Do Until p => n
    			Print# %fo, Hex$(CvDwd(cs, p), 8)
    			p = p + 4
    		Loop While p <= Len(cs)
    	End If
    
    	'--------------------------------------
    	'Print "Reserved &H0E"
    	If SegDir.Res0E.Length Then
    #If %Def(%Study)
    	Note "Reserved &H0E"
    #EndIf
    		Print# %fo,
    		Print# %fo, "*************************"
    		Print# %fo, "Reserved &H0E"
    		Print# %fo, "*************************"
    		p = SegDir.Res0E.Offset + 1
    		n = p + SegDir.Res0E.Length
    		Do Until p => n
    			Print# %fo, Hex$(CvDwd(cs, p), 8)
    			p = p + 4
    		Loop While p <= Len(cs)
    	End If
    
    
    	'--------------------------------------
    	'Print "Reserved &H0F"
    	If SegDir.Res0F.Length Then
    #If %Def(%Study)
    	Note "Reserved &H0F"
    #EndIf
    		Print# %fo,
    		Print# %fo, "*************************"
    		Print# %fo, "Reserved &H0F"
    		Print# %fo, "*************************"
    		p = SegDir.Res0F.Offset + 1
    		n = p + SegDir.Res0F.Length
    		Do Until p => n
    			Print# %fo, Hex$(CvDwd(cs, p), 8)
    			p = p + 4
    		Loop While p <= Len(cs)
    	End If
    
    	Close# %fo
    
    End Function
    
    '***************************************
    
    
    [b]Save this as "DisTypeLib.inc"[/b]
    
    '**************************************
    '	"DisTypeLib.inc"
    
    
    
    'This file is GPL 2008, by TheirCorp
    '**************************************
    
    
    $PeMZ			= "MZ"
    $PePE32			= "PE" & $Nul & $Nul	 'Chr$(&H50, &H45, &H00, &H00)
    
    %SizeOfShortName				   = 8
    %IMAGE_RESOURCE_NAME_IS_STRING	   = &H080000000???
    %IMAGE_RESOURCE_DATA_IS_DIRECTORY  = &H080000000???
    %ResourceSection				   = 3
    %NumberOfDirectoryEntries		   = 16	'IMAGE_NUMBEROF_DIRECTORY_ENTRIES
    %SizeOfShortName				   = 8
    %SectionHeaderSize				   = 40	 '%IMAGE_SIZEOF_SECTION_HEADER
    %MAXSTRING						   = 120
    
    %SUBDIR				   = 16
    %WINAPI				   = 1
    %WM_USER			   = &H400
    %TRUE				   = 1
    %FALSE				   = 0
    %LF_FACESIZE		   = 32
    %MAX_PATH			   = 260 ' max. length of full pathname
    %MAX_EXT			   = 256
    %ANSI_CHARSET		   = 0
    %FF_DONTCARE		   = 0 ' Don't care or don't know.
    %FW_DONTCARE		   = 0
    %FW_NORMAL			   = 400
    %LOGPIXELSY			   = 90 ' Logical pixels/inch in Y
    
    %WM_DESTROY			   = &H2
    %WM_SETFONT			   = &H30
    %WM_COMMAND			   = &H111
    %WM_DROPFILES		   = &H233
    %WM_NCACTIVATE		   = &H86
    %WM_INITDIALOG		   = &H110
    
    %WS_CHILD			   = &H40000000
    %WS_TABSTOP			   = &H00010000
    %WS_MINIMIZEBOX		   = &H00020000
    %WS_POPUP			   = &H80000000
    %WS_VISIBLE			   = &H10000000
    %WS_CLIPSIBLINGS	   = &H04000000
    %WS_CAPTION			   = &H00C00000 ' WS_BORDER OR WS_DLGFRAME
    %WS_BORDER			   = &H00800000
    %WS_DLGFRAME		   = &H00400000
    %WS_SYSMENU			   = &H00080000
    %WS_VSCROLL			   = &H00200000
    %WS_HSCROLL			   = &H00100000
    
    %WS_EX_LEFT			   = &H00000000
    %WS_EX_LTRREADING	   = &H00000000
    %WS_EX_RIGHTSCROLLBAR  = &H00000000
    %WS_EX_CONTROLPARENT   = &H00010000
    %WS_EX_WINDOWEDGE	   = &H00000100
    %WS_EX_CLIENTEDGE	   = &H00000200
    %WS_EX_ACCEPTFILES	   = &H00000010
    %WS_EX_TOOLWINDOW	   = &H00000080
    
    %HWND_DESKTOP			   = 0
    
    %BN_CLICKED				   = 0
    %BS_TEXT				   = &H0&
    %BS_PUSHBUTTON			   = &H0&
    %BS_GROUPBOX			   = &H7&
    %BS_CENTER				   = &H300&
    %BS_TOP					   = &H400&
    %BS_VCENTER				   = &HC00&
    %BS_DEFPUSHBUTTON		   = &H1&
    %BS_ICON				   = &H40&
    %BS_BITMAP				   = &H80&
    
    %DM_SETDEFID			   = %WM_USER + 1
    
    %DS_3DLOOK				   = &H0004&
    %DS_MODALFRAME			   = &H0080& ' Can be combined with WS_CAPTION
    %DS_NOFAILCREATE		   = &H0010&
    %DS_SETFONT				   = &H0040& ' User specified font for Dlg controls
    %DS_SETFOREGROUND		   = &H0200& ' not in win3.1
    
    %ES_LEFT		 = &H0&
    %ES_MULTILINE	 = &H4&
    %ES_AUTOVSCROLL  = &H40&
    %ES_AUTOHSCROLL  = &H80&
    %ES_WANTRETURN   = &H1000&
    
    %EM_SCROLL		 = &HB5
    %SB_LINEDOWN	 = 1
    %EM_SCROLLCARET  = &HB7
    %EM_SETSEL		 = &HB1
    
    %SBS_HORZ					  = &H0&
    %SBS_VERT					  = &H1&
    %SBS_TOPALIGN				  = &H2&
    %SBS_LEFTALIGN				  = &H2&
    %SBS_BOTTOMALIGN			  = &H4&
    %SBS_RIGHTALIGN				  = &H4&
    %SBS_SIZEBOXTOPLEFTALIGN	  = &H2&
    %SBS_SIZEBOXBOTTOMRIGHTALIGN  = &H4&
    %SBS_SIZEBOX				  = &H8&
    %SBS_SIZEGRIP				  = &H10&
    
    %SS_CENTER					  = &H00000001
    %SS_RIGHT					  = &H00000002
    
    %MB_OK						  = &H00000000&
    %MB_OKCANCEL				  = &H00000001&
    %MB_ABORTRETRYIGNORE		  = &H00000002&
    %MB_YESNOCANCEL				  = &H00000003&
    %MB_YESNO					  = &H00000004&
    %MB_RETRYCANCEL				  = &H00000005&
    %MB_CANCELTRYCONTINUE		  = &H00000006&
    
    %IDOK						  = 1
    %IDCANCEL					  = 2
    %IDABORT					  = 3
    %IDRETRY					  = 4
    %IDIGNORE					  = 5
    %IDYES						  = 6
    %IDNO						  = 7
    %IDCLOSE					  = 8
    %IDHELP						  = 9
    %IDTRYAGAIN					  = 10
    %IDCONTINUE					  = 11
    %SW_SHOW					  = 5
    
    '-----------------------------------------------------------------
    %LOAD_LIBRARY_AS_DATAFILE  = &H00000002
    %RT_CURSOR				   = 1
    %RT_BITMAP				   = 2
    %RT_ICON				   = 3
    %RT_MENU				   = 4
    %RT_DIALOG				   = 5
    %RT_STRING				   = 6
    %RT_FONTDIR				   = 7
    %RT_FONT				   = 8
    %RT_ACCELERATOR			   = 9
    %RT_RCDATA				   = 10
    %RT_MESSAGETABLE		   = 11
    %RT_GROUP_CURSOR		   = 12
    %RT_GROUP_ICON			   = 14
    %RT_VERSION				   = 16
    %RT_DLGINCLUDE			   = 17
    %RT_PLUGPLAY			   = 19
    %RT_VXD					   = 20
    %RT_ANICURSOR			   = 21
    %RT_ANIICON				   = 22
    %RT_HTML				   = 23
    %RT_MANIFEST			   = 24
    
    %READ_CONTROL				 = &H00020000
    %SYNCHRONIZE				 = &H00100000
    %STANDARD_RIGHTS_READ		 = %READ_CONTROL
    %KEY_QUERY_VALUE			 = &H1
    %KEY_ENUMERATE_SUB_KEYS		 = &H8
    %KEY_NOTIFY					 = &H10
    %KEY_READ					 = %STANDARD_RIGHTS_READ Or %KEY_QUERY_VALUE Or %KEY_ENUMERATE_SUB_KEYS Or %KEY_NOTIFY And (Not %SYNCHRONIZE)
    %HKEY_CURRENT_USER			 = &H80000001
    %ERROR_SUCCESS				 = 0&
    
    
    '**************************************
    
    Type LOGFONT
    	lfHeight As Long
    	lfWidth As Long
    	lfEscapement As Long
    	lfOrientation As Long
    	lfWeight As Long
    	lfItalic As Byte
    	lfUnderline As Byte
    	lfStrikeOut As Byte
    	lfCharSet As Byte
    	lfOutPrecision As Byte
    	lfClipPrecision As Byte
    	lfQuality As Byte
    	lfPitchAndFamily As Byte
    	lfFaceName As Asciiz * %LF_FACESIZE
    End Type
    
    
    
    '**************************************
    '	PE format UDTs
    '**************************************
    
    ' 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.
    
    Type IMAGE_RESOURCE_DIRECTORY_STRING
    	Length		As Word
    	NameString  As Byte 'ASCII string
    End Type
    
    Type IMAGE_RESOURCE_DIRECTORY_ENTRY
    	NameID  As Dword	'if bit 31 is set, the name is a string
    	Offset  As Dword	'if bit 31 is set, the data is a directory
    End Type
    
    Type IMAGE_RESOURCE_DIRECTORY
    	Characteristics		As Dword
    	TimeDateStamp		As Dword
    	MajorVersion		As Word
    	MinorVersion		As Word
    	NumberOfNamedEntries As Word
    	NumberOfIdEntries   As Word
    	'DirectoryEntries(0) As IMAGE_RESOURCE_DIRECTORY_ENTRY
    End Type
    
    Type IMAGE_RESOURCE_DATA_ENTRY
    	OffsetToData	As Dword
    	Size			As Dword
    	CodePage		As Dword
    	Reserved		As Dword
    End Type
    
    
    Type SectionInfo
    	SectName			As String * %SizeOfShortName
    	VirtSize			As Dword
    	dRVA				As Dword	'RVA to specific data within section
    	dSize				As Dword	'size of specific data within section
    	RVA					As Dword
    	RamAdd				As Dword
    	SizeOfRawData		As Dword
    	PtrToRawData		As Dword
    	StrPos				As Dword
    	EndPos				As Dword
    	Delta				As Dword
    	Characteristics		As Dword
    End Type 'SectionHeader
    
    
    Type DosHeader Byte			'DOS stub in EXE file
    	Magic		As Word		'Magic number
    	cBlp		As Word		'Bytes on last page of file
    	cP			As Word		'Pages in file
    	cRlc		As Word		'Relocations
    	cParHdr		As Word		'Size of header in paragraphs
    	MinAlloc	As Word		'Minimum extra paragraphs needed
    	MaxAlloc	As Word		'Maximum extra paragraphs needed
    	ss			As Word		'Initial (relative) SS value
    	sp			As Word		'Initial SP value
    	csum		As Word		'Checksum
    	ip			As Word		'Initial IP value
    	cs			As Word		'Initial (relative) CS value
    	lfaRlc		As Word		'File address of relocation table
    	OvNo		As Word		'Overlay number
    	Res4		As Asciz * 8 '4 Reserved words
    	OemId		As Word		'OEM identifier (for oeminfo)
    	OemInfo		As Word		'OEM information oemid specific
    	Res10		As Asciz * 20 '10 Reserved words
    	lfaNew		As Long  'always at &H3C and contains the offset of PE signature
    
    End Type 'DosHeader
    
    
    Type PEHeader Byte  'officially "IMAGEFILEHEADER"
    	Machine					As Word  'machine type
    	NumberOfSections		As Word
    	TimeDateStamp			As Dword 'Number of seconds since December 31st, 1969, at 4:00 P.M
    	PointerToSymbolTable	As Dword
    	NumberOfSymbols			As Dword
    	SizeOfOptionalHeader	As Word
    	Characteristics			As Word
    End Type 'PEHeader
    
    
    Type DataDir			Byte	'IMAGE_DATA_DIRECTORY
    	RVA					As Dword
    	DirSize				As Dword
    End Type 'DataDir
    
    
    'Optional header format ("IMAGE_OPTIONAL_HEADER32").
    'this is not as "optional" as its name suggests
    Type OptHeader			Byte
    	'Standard fields.
    	Magic				As Word  '"Magic number": &H10B = PE32, &H20B = PE32+, &H107 = ROM image
    	MajLinkerVer		As Byte
    	MinLinkerVer		As Byte
    	SizeOfCode			As Dword
    	SizeOfInitData		As Dword
    	SizeOfUninitData	As Dword
    	AddrOfEntryPoint	As Dword
    	BaseOfCode			As Dword
    	BaseOfData			As Dword
    
    	'NT additional fields.
    	ImageBase			As Dword 'defaults: DLL = &H10000000, EXE = &H400000
    	SectionAlign		As Dword 'must be => file alignment
    	FileAlign			As Dword 'alignment of raw data of sections. value should be a power of 2, => 512 and <= 64K ( default = 512)
    	MajOSVer			As Word
    	MinOSVer			As Word
    	MajImageVer			As Word
    	MinImageVer			As Word
    	MajSubsysVer		As Word
    	MinSubsysVer		As Word
    	Win32VerValue		As Dword
    	SizeOfImage			As Dword 'size of image, including headers. must be a multiple of SectionAlign
    	SizeOfHeaders		As Dword 'size of: stub + PE Header + section headers rounded up to multiple of FileAlign
    	CheckSum			As Dword
    	Subsystem			As Word
    	DllCharacteristics  As Word
    	SizeOfStackReserve  As Dword
    	SizeOfStackCommit   As Dword
    	SizeOfHeapReserve   As Dword
    	SizeOfHeapCommit	As Dword
    	LoaderFlags			As Dword 'obsolete
    	NumberOfRvaAndSizes As Dword 'Number of data-directory entries in the remainder of Optional Header
    	'DataDirectory( %NumberOfDirectoryEntries ) As DataDir
    
    End Type 'OptionalHeader
    
    
    'Section header format.
    'Borland calls its code sections "CODE", rather than ".text".
    Type SectionHeader		Byte	 ' _IMAGE_SECTION_HEADER
    	SectName			As String * %SizeOfShortName
    	VirtSize			As Dword
    	'VirtualAddress		 As Dword	 'changed from "RVA"
    	RVA					As Dword
    	SizeOfRawData		As Dword
    	PtrToRawData		As Dword
    	PtrToRelocations	As Dword
    	PtrToLineNums		As Dword
    	NumberOfRelocations As Word
    	NumberOfLineNums	As Word
    	Characteristics		As Dword
    End Type 'SectionHeader
    
    
    '**************************************
    '	Declares
    '**************************************
    Declare Function CreateFontIndirect Lib "GDI32.DLL" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Dword
    Declare Function DeleteObject Lib "GDI32.DLL" Alias "DeleteObject" (ByVal hObject As Dword) As Long
    Declare Function GetDeviceCaps Lib "GDI32.DLL" Alias "GetDeviceCaps" (ByVal hdc As Dword, ByVal nIndex As Long) As Long
    
    Declare Function GetLastError Lib "KERNEL32.DLL" Alias "GetLastError" () As Long
    Declare Function GetModuleFileName Lib "KERNEL32.DLL" Alias "GetModuleFileNameA" (ByVal hModule As Dword, lpFileName As Asciiz, ByVal nSize As Dword) As Dword
    
    Declare Sub DragAcceptFiles Lib "SHELL32.DLL" Alias "DragAcceptFiles" (ByVal hwnd As Dword, ByVal fAccept As Long)
    Declare Sub DragFinish Lib "SHELL32.DLL" Alias "DragFinish" (ByVal hDrop As Dword)
    Declare Function DragQueryFile Lib "SHELL32.DLL" Alias "DragQueryFileA" (ByVal hDrop As Dword, ByVal uiFile As Dword, lpStr As Asciiz, ByVal cch As Dword) As Dword
    Declare Function SetMenu Lib "USER32.DLL" Alias "SetMenu" (ByVal hWnd As Dword, ByVal hMenu As Dword) As Long
    
    Declare Function GetDC Lib "USER32.DLL" Alias "GetDC" (ByVal hWnd As Dword) As Dword
    Declare Function GetFocus Lib "USER32.DLL" Alias "GetFocus" () As Dword
    Declare Function ReleaseDC Lib "USER32.DLL" Alias "ReleaseDC" (ByVal hWnd As Dword, ByVal hDC As Dword) As Long
    Declare Function SetFocus Lib "USER32.DLL" Alias "SetFocus" (ByVal hWnd As Dword) As Long
    
    '**************************************
    TheirCorp's projects at SourceForge

    TheirCorp's website

    sigpic

    Comment


      #3
      Sample ODL (Object Definition Language) File and its Dump

      Here's a sample ODL (Object Definition Language) file:
      Code:
      #include <olectl.h>
      #include <idispids.h>
      
      
      [uuid(A74CD7DD-EA6F-11D4-ABF3-000102378429), version(1.0),
        helpfile("Sample.hlp"),
        helpstring("Sample ActiveX Control module"),
        control]
      
      library SampleLib
      {
      	importlib(STDOLE_TLB);
      	importlib(STDTYPE_TLB);
      
      	[uuid(A74CD7DE-EA6F-11D4-ABF3-000102378429), hidden]
      		[helpstringcontext(103), version(1.0)]
      		[helpstring("Event interface for Sample Control")]
      	dispinterface _Sample
      	{
      		properties:
      			[id(DISPID_BACKCOLOR), bindable, requestedit] OLE_COLOR BackColor;
      			[id(DISPID_FORECOLOR), bindable, requestedit] OLE_COLOR ForeColor;
      			[id(1)] boolean ShowGrid;
      			[id(2)] boolean XLog;
      			[id(3)] int UsesArray;
      
      			[id(4), helpstring("A custom data type to help reverse this file format.")]
      			struct SampleType {
      				int cbStructSize;
      				int hWndOwner;
      				int x;
      				int y;
      				unsigned long lpszCaption;
      				unsigned long cObjects;
      				unsigned long **lplpUnk;
      				unsigned long cPages;
      				float floats[40];
      				char lpPages[80];
      			} Sample[5];
      
      			[id(20), bindable, requestedit] int Param[12];
      
      		methods:
      			// some "void" methods (they don't return values)
      			[id(21), helpstring("An int parameter (= PowerBASIC's Long)")]
      			void Method1(int integer);
      
      			[id(22), helpstring("An array with no element count specified")]
      			void Method2(int array[]);
      
      			[id(23), helpstring("A SafeArray")]
      			void Method3(SAFEARRAY(int)); // a SafeArray
      
      
      			// the same one's as above, but these do return values
      			[id(24), helpstring("Another int parameter (= PowerBASIC's Long)")]
      			int Method4(int integer);
      
      			[id(25), helpstring("Another array with no element count specified")]
      			VARIANT Method5(int array[]);
      
      			[id(26), helpstring("Another SafeArray")]
      			double Method6(SAFEARRAY(int)); // a SafeArray
      
        	};
      
      	[uuid(A74CD7E0-EA6F-11D4-ABF3-000102378429),
      	  helpstring("Sample Control"), control]
      	coclass Sample
      	{
      		[default] dispinterface _Sample;
      	};
      
      };
      Here's the corresponding dump file:
      Code:
      *************************
      TypeLib Header
      *************************
      Magic 1:		5446534D = MSFT
      Magic 2:		00010002
      GUID:			00000000 ==> {A74CD7DD-EA6F-11D4-ABF3-000102378429}
      Locale ID:		00000409 = English United States
      Locale ID 2:	00000000
      VarFlags:		00000051
      	System:		Win32
      	Help file specified
      	Help file is not in a DLL
      Version:	00000001
      Flags:		00000002
      Number of TypeInfo's:	00000003 == 3
      HelpString:			0000000C ==> "Sample ActiveX Control module"
      HelpStringContext:	00000000
      HelpContext:		00000000
      Name Table:
      	Names:		0000001E == 30
      	Characters:	000000DC == 220
      
      Name:		00000000 ==> "SampleLib"
      Helpfile:	00000000 ==> "Sample.hlp"
      Custom data offset:			0000000C
      hRefType to IDispatch:		00000001
      Number of Import Info's:	00000002 == 2
      
      *************************
      Offsets to TypeInfo Data
      *************************
      00000000
      00000064
      000000C8
      
      *************************
      Segment Directory (Segment name: Offset, Length)...
      *************************
      Type Info Table:		00000150, 0000012C
      Import Info:			000003CC, 00000018
      Imported Libraries:		000003E4, 0000001C
      References Table:		000003BC, 00000010
      Lib Table:				0000027C, 00000080
      GUID Table:				000002FC, 000000C0
      Reserved 07:			00000400, 00000200
      Name Table:				00000600, 00000274
      String Table:			00000874, 00000170
      Type Descriptors:		000009E4, 00000050
      Array Descriptors:		00000A34, 00000040
      Custom Data:			00000A74, 00000010
      Custom Data/GUID's:		00000A84, 00000018
      Reserved 0E:			FFFFFFFF, 00000000
      Reserved 0F:			FFFFFFFF, 00000000
      
      *************************
      TypeInfo Data...
      *************************
      -------------------------
      TypeInfo number:	1
      Type kind:	00002124 And &H0F = Dispatch
      	Alignment: (00002124/0800) And &H1F = 0004
      
      Function count:	0006 == 6
      Property count:	0007 == 7
      GUID:	00000048 ==> {A74CD7DE-EA6F-11D4-ABF3-000102378429}
      Flags:	00001010
      Name:	00000018 ==> "_Sample"
      Version:	00000001
      Doc String Offset:	0000002C ==> "Event interface for Sample Control"
      HelpStringContext:	00000067
      HelpContext:		00000000
      
      Offset in custom data table:	FFFFFFFF
      Number of implemented types:	0001 == 1
      Virtual table size:	0018
      Size:	00000004
      DataType1:	FFFFFFFF
      DataType2:	00000000
      
      Memory offset:	00000A9C
      
      	Function record array size:	0000019C
      
      	----------------------------------------
      				Functions:
      	----------------------------------------
      	ID:			00000015 == 21
      	Name:		000001A4 ==> "Method1"
      	Reference:	00000000
      	Record size:	002C
      	Unknown:		0000
      	Flags:			8000 = VT_Empty
      	DataType:		0018 = VT_Void
      	Vtable offset:	0000
      	Func Desc Size:	0044
      
      	FKCCIC (raw):	0000040C
      		Calling convention:	04 = StdCall
      		Invocation kind:	01 = Func
      		Function kind:		04 = Dispatch
      
      	Number of parameters:	0001 == 1
      		----------------------------------------
      		Optional Data:
      		HelpContext:		00000000
      		HelpString:			00000088 ==> "An int parameter (= PowerBASIC's Long)"
      
      		----------------------------------------
      		Parameter number:	 1
      		DataType:			0016 = VT_Int
      		Flags:				8003 = VT_I4
      		Name:				000001B8 ==> "integer"
      		ParamFlags:			00000000 =	(none)
      	----------------------------------------
      	ID:			00000016 == 22
      	Name:		000001CC ==> "Method2"
      	Reference:	0000002C
      	Record size:	002C
      	Unknown:		0001
      	Flags:			8000 = VT_Empty
      	DataType:		0018 = VT_Void
      	Vtable offset:	0004
      	Func Desc Size:	004C
      
      	FKCCIC (raw):	0001040C
      		Calling convention:	04 = StdCall
      		Invocation kind:	01 = Func
      		Function kind:		04 = Dispatch
      
      	Number of parameters:	0001 == 1
      		----------------------------------------
      		Optional Data:
      		HelpContext:		00000000
      		HelpString:			000000B0 ==> "An array with no element count specified"
      
      		----------------------------------------
      		Parameter number:	 1
      		DataType:			0040 = VT_FileTime
      		Flags:				0000 = VT_Empty
      		Name:				000001E0 ==> "array"
      		ParamFlags:			00000000 =	(none)
      	----------------------------------------
      	ID:			00000017 == 23
      	Name:		000001F4 ==> "Method3"
      	Reference:	00000058
      	Record size:	002C
      	Unknown:		0002
      	Flags:			8000 = VT_Empty
      	DataType:		0018 = VT_Void
      	Vtable offset:	0008
      	Func Desc Size:	004C
      
      	FKCCIC (raw):	0002040C
      		Calling convention:	04 = StdCall
      		Invocation kind:	01 = Func
      		Function kind:		04 = Dispatch
      
      	Number of parameters:	0001 == 1
      		----------------------------------------
      		Optional Data:
      		HelpContext:		00000000
      		HelpString:			000000DC ==> "A SafeArray"
      
      		----------------------------------------
      		Parameter number:	 1
      		DataType:			0048 = VT_ClsID
      		Flags:				0000 = VT_Empty
      		Name:				00000208 ==> "__MIDL_0014"
      		ParamFlags:			00000000 =	(none)
      	----------------------------------------
      	ID:			00000018 == 24
      	Name:		00000220 ==> "Method4"
      	Reference:	00000084
      	Record size:	002C
      	Unknown:		0003
      	Flags:			8003 = VT_I4
      	DataType:		0016 = VT_Int
      	Vtable offset:	000C
      	Func Desc Size:	0044
      
      	FKCCIC (raw):	0003040C
      		Calling convention:	04 = StdCall
      		Invocation kind:	01 = Func
      		Function kind:		04 = Dispatch
      
      	Number of parameters:	0001 == 1
      		----------------------------------------
      		Optional Data:
      		HelpContext:		00000000
      		HelpString:			000000EC ==> "Another int parameter (= PowerBASIC's Long)"
      
      		----------------------------------------
      		Parameter number:	 1
      		DataType:			0016 = VT_Int
      		Flags:				8003 = VT_I4
      		Name:				000001B8 ==> "integer"
      		ParamFlags:			00000000 =	(none)
      	----------------------------------------
      	ID:			00000019 == 25
      	Name:		00000234 ==> "Method5"
      	Reference:	000000B0
      	Record size:	002C
      	Unknown:		0004
      	Flags:			800C = VT_Variant
      	DataType:		000C = VT_Variant
      	Vtable offset:	0010
      	Func Desc Size:	004C
      
      	FKCCIC (raw):	0004040C
      		oEntry is numeric
      		Calling convention:	04 = StdCall
      		Invocation kind:	01 = Func
      		Function kind:		04 = Dispatch
      
      	Number of parameters:	0001 == 1
      		----------------------------------------
      		Optional Data:
      		HelpContext:		00000000
      		HelpString:			0000011C ==> "Another array with no element count specified"
      
      		----------------------------------------
      		Parameter number:	 1
      		DataType:			0040 = VT_FileTime
      		Flags:				0000 = VT_Empty
      		Name:				000001E0 ==> "array"
      		ParamFlags:			00000000 =	(none)
      	----------------------------------------
      	ID:			0000001A == 26
      	Name:		00000248 ==> "Method6"
      	Reference:	000000DC
      	Record size:	002C
      	Unknown:		0005
      	Flags:			8005 = VT_R8
      	DataType:		0005 = VT_R8
      	Vtable offset:	0014
      	Func Desc Size:	004C
      
      	FKCCIC (raw):	0005040C
      		oEntry is numeric
      		Calling convention:	04 = StdCall
      		Invocation kind:	01 = Func
      		Function kind:		04 = Dispatch
      
      	Number of parameters:	0001 == 1
      		----------------------------------------
      		Optional Data:
      		HelpContext:		00000000
      		HelpString:			0000014C ==> "Another SafeArray"
      
      		----------------------------------------
      		Parameter number:	 1
      		DataType:			0048 = VT_ClsID
      		Flags:				0000 = VT_Empty
      		Name:				0000025C ==> "__MIDL_0015"
      		ParamFlags:			00000000 =	(none)
      
      	----------------------------------------
      		 Properties:
      	----------------------------------------
      	ID:			FFFFFE0B ==-501
      	Name:		0000002C ==> "BackColor"
      	Reference:	00000108
      	Record size (the low byte):	0014
      	Property number?:			0006
      	Flags:						0000
      	DataType:					0000 = VT_Empty
      	Variable kind:				000C = RequestEdit, Bindable
      	Variable desc size:			0000
      	Value/Offset:				00240003
      
      	----------------------------------------
      	ID:			FFFFFDFF ==-513
      	Name:		00000044 ==> "ForeColor"
      	Reference:	0000011C
      	Record size (the low byte):	0014
      	Property number?:			0007
      	Flags:						0000
      	DataType:					0000 = VT_Empty
      	Variable kind:				000C = RequestEdit, Bindable
      	Variable desc size:			0000
      	Value/Offset:				00240003
      
      	----------------------------------------
      	ID:			00000001 == 1
      	Name:		0000005C ==> "ShowGrid"
      	Reference:	00000130
      	Record size (the low byte):	0014
      	Property number?:			0008
      	Flags:						8010 = VT_I1
      	DataType:					0010 = VT_I1
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240003
      
      	----------------------------------------
      	ID:			00000002 == 2
      	Name:		00000070 ==> "XLog"
      	Reference:	00000144
      	Record size (the low byte):	0014
      	Property number?:			0009
      	Flags:						8010 = VT_I1
      	DataType:					0010 = VT_I1
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240003
      
      	----------------------------------------
      	ID:			00000003 == 3
      	Name:		00000080 ==> "UsesArray"
      	Reference:	00000158
      	Record size (the low byte):	0014
      	Property number?:			000A
      	Flags:						8003 = VT_I4
      	DataType:					0016 = VT_Int
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240003
      
      	----------------------------------------
      	ID:			00000004 == 4
      	Name:		0000017C ==> "Sample"
      	Reference:	0000016C
      	Record size (the low byte):	001C
      	Property number?:			000B
      	Flags:						0000
      	DataType:					0030 = (Unknown)
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00380003
      	HelpContext:		00000000
      	HelpString:			00000050 ==> "A custom data type to help reverse this file format."
      
      	----------------------------------------
      	ID:			00000014 == 20
      	Name:		00000190 ==> "Param"
      	Reference:	00000188
      	Record size (the low byte):	0014
      	Property number?:			000C
      	Flags:						0000
      	DataType:					0038 = (Unknown)
      	Variable kind:				000C = RequestEdit, Bindable
      	Variable desc size:			0000
      	Value/Offset:				00380003
      
      -------------------------
      TypeInfo number:	2
      Type kind:	00012121 And &H0F = Record
      	Alignment: (00012121/0800) And &H1F = 0004
      
      Function count:	0000 == 0
      Property count:	000A == 10
      GUID:	FFFFFFFF ==> 
      Flags:	00000000
      Name:	00000098 ==> "SampleType"
      Version:	00000000
      Doc String Offset:	FFFFFFFF ==> 
      HelpStringContext:	00000000
      HelpContext:		00000000
      
      Offset in custom data table:	FFFFFFFF
      Number of implemented types:	0000 == 0
      Virtual table size:	0000
      Size:	00000110
      DataType1:	FFFFFFFF
      DataType2:	00000000
      
      Memory offset:	00000CD8
      
      	Function record array size:	000000C8
      
      	----------------------------------------
      		 Properties:
      	----------------------------------------
      	ID:			40000000 == 1073741824
      	Name:		000000B0 ==> "cbStructSize"
      	Reference:	00000000
      	Record size (the low byte):	0014
      	Property number?:			0000
      	Flags:						8003 = VT_I4
      	DataType:					0016 = VT_Int
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000001 == 1073741825
      	Name:		000000C8 ==> "hWndOwner"
      	Reference:	00000014
      	Record size (the low byte):	0014
      	Property number?:			0001
      	Flags:						8003 = VT_I4
      	DataType:					0016 = VT_Int
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000002 == 1073741826
      	Name:		000000E0 ==> "x"
      	Reference:	00000028
      	Record size (the low byte):	0014
      	Property number?:			0002
      	Flags:						8003 = VT_I4
      	DataType:					0016 = VT_Int
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000003 == 1073741827
      	Name:		000000F0 ==> "y"
      	Reference:	0000003C
      	Record size (the low byte):	0014
      	Property number?:			0003
      	Flags:						8003 = VT_I4
      	DataType:					0016 = VT_Int
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000004 == 1073741828
      	Name:		00000100 ==> "lpszCaption"
      	Reference:	00000050
      	Record size (the low byte):	0014
      	Property number?:			0004
      	Flags:						8013 = VT_UI4
      	DataType:					0013 = VT_UI4
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000005 == 1073741829
      	Name:		00000118 ==> "cObjects"
      	Reference:	00000064
      	Record size (the low byte):	0014
      	Property number?:			0005
      	Flags:						8013 = VT_UI4
      	DataType:					0013 = VT_UI4
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000006 == 1073741830
      	Name:		0000012C ==> "lplpUnk"
      	Reference:	00000078
      	Record size (the low byte):	0014
      	Property number?:			0006
      	Flags:						0000
      	DataType:					0010 = VT_I1
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00340000
      
      	----------------------------------------
      	ID:			40000007 == 1073741831
      	Name:		00000140 ==> "cPages"
      	Reference:	0000008C
      	Record size (the low byte):	0014
      	Property number?:			0007
      	Flags:						8013 = VT_UI4
      	DataType:					0013 = VT_UI4
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00240000
      
      	----------------------------------------
      	ID:			40000008 == 1073741832
      	Name:		00000154 ==> "floats"
      	Reference:	000000A0
      	Record size (the low byte):	0014
      	Property number?:			0008
      	Flags:						0000
      	DataType:					0018 = VT_Void
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00380000
      
      	----------------------------------------
      	ID:			40000009 == 1073741833
      	Name:		00000168 ==> "lpPages"
      	Reference:	000000B4
      	Record size (the low byte):	0014
      	Property number?:			0009
      	Flags:						0000
      	DataType:					0020 = (Unknown)
      	Variable kind:				0000 = 
      	Variable desc size:			0000
      	Value/Offset:				00380000
      
      -------------------------
      TypeInfo number:	3
      Type kind:	00022225 And &H0F = Coclass
      	Alignment: (00022225/0800) And &H1F = 0004
      
      Function count:	0000 == 0
      Property count:	0000 == 0
      GUID:	000000A8 ==> {A74CD7E0-EA6F-11D4-ABF3-000102378429}
      Flags:	00000022
      Name:	0000017C ==> "Sample"
      Version:	00000000
      Doc String Offset:	00000160 ==> "Sample Control"
      HelpStringContext:	00000000
      HelpContext:		00000000
      
      Offset in custom data table:	FFFFFFFF
      Number of implemented types:	0001 == 1
      Virtual table size:	0000
      Size:	00000004
      Reference table offset:	00000000
      DataType2:	00000000
      
      Memory offset:	00000E1C
      
      *************************
      ImportInfo
      *************************
      --------------------------------------------
      Import Info number:	1
      Count:				0
      Offset in import file table:	00000000
      GUID:	00000078 ==> {00020400-0000-0000-C000-000000000046}
      Type:	Module
      --------------------------------------------
      Import Info number:	2
      Count:				1
      Offset in import file table:	00000000
      GUID:	00000090 ==> {66504301-BE0F-101A-8BBB-00AA00300CAB}
      Type:	Coclass
      
      *************************
      Imported Type Libs
      *************************
      --------------------------------------------
      GUID:			00000060 ==> {00020430-0000-0000-C000-000000000046}
      Locale ID?:		00000000 = Language-Neutral
      Major version:	0002
      Minor version:	0000
      Size = 002D/4 = 000B
      File name:	stdole2.tlb
      
      *************************
      References Table
      *************************
      --------------------------------------------
      Reference type:	00000000	==> (TypeInfo)
      Flags:			00000001
      
      *************************
      Lib Table (offsets into GUID table)
      *************************
      00000078
      00000090
      00000048
      00000000
      00000060
      00000030
      000000A8
      00000018
      
      *************************
      GUID Table
      *************************
      --------------------------------------------
      GUID:	{A74CD7DD-EA6F-11D4-ABF3-000102378429}
      Href Type:	FFFFFFFE = TypeLib GUID
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{DE77BA63-517C-11D1-A2DA-0000F8773CE9}
      Href Type:	FFFFFFFF = Offset?
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{DE77BA64-517C-11D1-A2DA-0000F8773CE9}
      Href Type:	FFFFFFFF = Offset?
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{A74CD7DE-EA6F-11D4-ABF3-000102378429}
      Href Type:	00000000 = Offset?
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{00020430-0000-0000-C000-000000000046}
      Href Type:	00000002 = Imported TypeLib
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{00020400-0000-0000-C000-000000000046}
      Href Type:	00000001 = Imported TypeInfo
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{66504301-BE0F-101A-8BBB-00AA00300CAB}
      Href Type:	0000000D = Imported TypeInfo
      Next hash:	FFFFFFFF
      --------------------------------------------
      GUID:	{A74CD7E0-EA6F-11D4-ABF3-000102378429}
      Href Type:	000000C8 = Offset?
      Next hash:	FFFFFFFF
      
      *************************
       Table with Offsets into the Name Table ("Reserved 07")
      *************************
      000001E0
      000001B8
      00000044
      00000080
      00000140
      0000012C
      000000C8
      00000208
      0000025C
      00000118
      0000017C
      00000070
      000001A4
      000001CC
      000001F4
      00000220
      00000234
      00000248
      00000018
      00000190
      00000098
      0000002C
      00000100
      000000F0
      0000005C
      000000E0
      000000B0
      00000000
      00000168
      
      *************************
      Name Table
      *************************
      --------------------------------------------
      Next hash:		FFFFFFFF
      Name length:	09 == 9
      Flags?...		00
      Hash code:		787A
      "SampleLib"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		38
      Hash code:		FC49
      "_Sample"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	09 == 9
      Flags?...		00
      Hash code:		83DE
      "BackColor"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	09 == 9
      Flags?...		00
      Hash code:		1313
      "ForeColor"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	08 == 8
      Flags?...		00
      Hash code:		5BED
      "ShowGrid"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	04 == 4
      Flags?...		00
      Hash code:		E6B9
      "XLog"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	09 == 9
      Flags?...		00
      Hash code:		629D
      "UsesArray"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	0A == 10
      Flags?...		38
      Hash code:		C5D7
      "SampleType"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	0C == 12
      Flags?...		10
      Hash code:		3770
      "cbStructSize"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	09 == 9
      Flags?...		10
      Hash code:		FEAC
      "hWndOwner"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	01 == 1
      Flags?...		10
      Hash code:		106F
      "x"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	01 == 1
      Flags?...		10
      Hash code:		106C
      "y"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	0B == 11
      Flags?...		10
      Hash code:		936A
      "lpszCaption"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	08 == 8
      Flags?...		10
      Hash code:		3FB4
      "cObjects"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		10
      Hash code:		D4A7
      "lplpUnk"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	06 == 6
      Flags?...		10
      Hash code:		3125
      "cPages"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	06 == 6
      Flags?...		10
      Hash code:		DF46
      "floats"
      --------------------------------------------
      Offset:			00000064
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		10
      Hash code:		3AFC
      "lpPages"
      --------------------------------------------
      Offset:			000000C8
      Next hash:		FFFFFFFF
      Name length:	06 == 6
      Flags?...		28
      Hash code:		84B6
      "Sample"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	05 == 5
      Flags?...		00
      Hash code:		FDCC
      "Param"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		00
      Hash code:		5341
      "Method1"
      --------------------------------------------
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		00
      Hash code:		B48A
      "integer"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		00
      Hash code:		5342
      "Method2"
      --------------------------------------------
      Next hash:		FFFFFFFF
      Name length:	05 == 5
      Flags?...		00
      Hash code:		9183
      "array"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		00
      Hash code:		5343
      "Method3"
      --------------------------------------------
      Next hash:		FFFFFFFF
      Name length:	0B == 11
      Flags?...		00
      Hash code:		A4B2
      "__MIDL_0014"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		00
      Hash code:		5344
      "Method4"
      --------------------------------------------
      Offset:			00000000
      Next hash:		FFFFFFFF
      Name length:	07 == 7
      Flags?...		00
      Hash code:		5345
      "Method5"
      --------------------------------------------
      Offset:			00000000
      Next hash:		00000154
      Name length:	07 == 7
      Flags?...		00
      Hash code:		5346
      "Method6"
      --------------------------------------------
      Next hash:		FFFFFFFF
      Name length:	0B == 11
      Flags?...		00
      Hash code:		A4B3
      "__MIDL_0015"
      
      *************************
      String Table
      *************************
      1)	Sample.hlp
      2)	Sample ActiveX Control module
      3)	Event interface for Sample Control
      4)	A custom data type to help reverse this file format.
      5)	An int parameter (= PowerBASIC's Long)
      6)	An array with no element count specified
      7)	A SafeArray
      8)	Another int parameter (= PowerBASIC's Long)
      9)	Another array with no element count specified
      10)	Another SafeArray
      11)	Sample Control
      
      *************************
      Type Descriptors
      *************************
      -------------------------
      Raw:	7FFF001D 0000000D
      Data type 1 = 7FFF001D = VT_UserDefined
      Type descriptor offset:		00000008
      -------------------------
      Raw:	4013001A 80130013
      Data type 1 = 4013001A = VT_ByRef, VT_Ptr == base type: VT_UI4
      Type descriptor table offset:	0010
      -------------------------
      Raw:	7FFE001A 00000008
      Data type 1 = 7FFE001A = VT_Ptr
      Type descriptor file offset:	00000000
      -------------------------
      Raw:	7FFE001C 00000000
      Data type 1 = 7FFE001C = VT_CArray
      Array descriptor offset:	00000000
      -------------------------
      Raw:	7FFE001C 00000010
      Data type 1 = 7FFE001C = VT_CArray
      Array descriptor offset:	00000010
      -------------------------
      Raw:	7FFF001D 00000064
      Data type 1 = 7FFF001D = VT_UserDefined
      Type descriptor offset:		00000060
      -------------------------
      Raw:	7FFE001C 00000020
      Data type 1 = 7FFE001C = VT_CArray
      Array descriptor offset:	00000020
      -------------------------
      Raw:	7FFE001C 00000030
      Data type 1 = 7FFE001C = VT_CArray
      Array descriptor offset:	00000030
      -------------------------
      Raw:	4003001A 80030016
      Data type 1 = 4003001A = VT_ByRef, VT_Ptr == base type: VT_I4
      Type descriptor table offset:	0010
      -------------------------
      Raw:	2003001B 80030016
      Data type 1 = 2003001B = VT_Array, VT_SafeArray == base type: VT_I4
      Type descriptor table offset:	0010
      
      *************************
      Array Descriptors
      *************************
      --------------------------------------------
      Raw:	80040004, 00080001, 00000028, 00000000
      Href Type:	80040004
      Variable type:	0004 = VT_R4
      Number of dimensions:	0001 == 1
      (1)	Elements: 00000028 == 40	Lower bound: 00000000 == 0
      --------------------------------------------
      Raw:	80100010, 00080001, 00000050, 00000000
      Href Type:	80100010
      Variable type:	0010 = VT_I1
      Number of dimensions:	0001 == 1
      (1)	Elements: 00000050 == 80	Lower bound: 00000000 == 0
      --------------------------------------------
      Raw:	00000028, 00080001, 00000005, 00000000
      Offset to array descriptor:	00000005
      Variable type:	0008 = VT_BStr
      Number of dimensions:	0001 == 1
      (1)	Elements: 00000005 == 5	Lower bound: 00000000 == 0
      --------------------------------------------
      Raw:	80030016, 00080001, 0000000C, 00000000
      Href Type:	80030016
      Variable type:	0016 = VT_Int
      Number of dimensions:	0001 == 1
      (1)	Elements: 0000000C == 12	Lower bound: 00000000 == 0
      
      *************************
      Custom Data
      *************************
      9C330013
      575748B4
      00A40013
      57570501
      
      *************************
      Offsets of GUID's
      *************************
      00000018
      00000000
      FFFFFFFF
      00000030
      00000008
      00000000
      TheirCorp's projects at SourceForge

      TheirCorp's website

      sigpic

      Comment


        #4
        Typo Correction for the above Code

        There's a typo in the above code.

        You need to change:
        Code:
        Else 'file offset to type descriptor
        	d = MakLng(TypDsc.v1, TypDsc.v2)
        	Print# %fo, "Type descriptor file offset:	"; Hex$(d And (TypDsc.v3\8), 8)
        End If
        To
        Code:
        Else 'file offset to type descriptor
        	d = MakLng(TypDsc.v2, TypDsc.v3)
        	Print# %fo, "Type descriptor file offset:	"; Hex$(d And (TypDsc.v3\8), 8)
        End If
        A new version is currently being prepared to conform to the "Unofficial TypeLib Data
        Format Specification" (which almost ready to be posted). The new code might not
        be ready for a few days.
        TheirCorp's projects at SourceForge

        TheirCorp's website

        sigpic

        Comment


          #5
          First Draft of &quot;The Unofficial TypeLib Data Format Specification&quot; Online

          The first draft of "The Unofficial TypeLib Data Format Specification" is now
          online. It is plain text, but has many illustrations. Zip and 7-Zip files are also available.
          The file sizes range from 14.4 KB to 88.1 KB

          It mostly complete, but a few more details are planned to be added for the
          "official" release. It has many illustrations.
          It is fairly DOS-friendly --- the lines are wrapped at a width of 80.
          Last edited by Tony Burcham; 11 Sep 2008, 05:37 PM. Reason: Replaced direct links with link to a web page, plus updated information.
          TheirCorp's projects at SourceForge

          TheirCorp's website

          sigpic

          Comment


            #6
            This Thread Should be Deleted

            The code above is outdated and obsolete, you should use the new version:
            Type Library (TLB) Data Dumper (without WinAPI) version 1.0
            This entire thread should be deleted.
            TheirCorp's projects at SourceForge

            TheirCorp's website

            sigpic

            Comment

            Working...
            X
            😀
            🥰
            🤢
            😎
            😡
            👍
            👎