July 1, 1995
When programming in Microsoft® Visual Basic®, you use the functions stored in dynamic-link library (DLL) files to add greater scope to your applications. You must, however, use the correct DLL file (16-bit or 32-bit) in your program. This article presents a function that tells you what type of file you are dealing with.
The Microsoft® Windows® application programming interface (API) allows you to perform tasks in your Microsoft Visual Basic® applications that the Basic language itself cannot do. To perform such a task, you must call a function stored in a dynamic-link library (DLL) file.
However, you must take into consideration whether you are programming in a 16-bit or 32-bit environment. If you're running in a 16-bit environment, then you can only use 16-bit DLL functions. However, if you're running in a 32-bit environment, you may be able to make calls to 16-bit and 32-bit functions, depending on the environment in question.
Because your application may be run on many different operating systems (Windows version 3.1, Windows 95, OS/2®, Windows NT™, and so on), you need to find out whether files are 16-bit or 32-bit. Then you can determine which API functions can be used in your Visual Basic program.
In the example program below, you can type the full path of a file you want to check. When you click the command button, the program reads data from the header block of the file and reports its file type.
Each time an operating system saves a file on disk, the operating system prefixes the file with a header block as the first data stored in the file. This header block contains information that can be used to identify the file's type. For example, an MS-DOS® file has a header containing the two characters "MZ". When you run the ExeType function on this file, you would know that it is either a .COM, .CMD, .PIF, or .BAT file if the file contains the "MZ" signature in its header block.
This program shows how you can identify individual file types.
Option Explicit
Const ordMSDOS = 1
Const ordWindows = 2
Const ordOS2_1 = 3
Const ordNTWin = 4
Const ordNTChar = 5
Const ordDOSUnknown = 7
Const ordNotExe = 0
Const errNoFile = -1
Const errOS2_2 = -2
Const errWinOS2DLL = -3
Const errNEUnknown = -4
Const errNTNonIntel = -5
Const errNTDLL = -6
Private Sub Form_Load()
Text1.TEXT = ""
End Sub
Private Sub Command1_Click()
If Text1.TEXT = "" Then
Exit Sub
End If
Dim X As Integer
Dim FileToCheck As String
FileToCheck = Text1.TEXT
X = ExeType(FileToCheck)
If X = errNoFile Then
MsgBox "File does not exist", 16, "Error"
Exit Sub
End If
Select Case X
Case ordMSDOS
MsgBox "File is MSDOS EXE file", 16, "OK"
Case ordWindows
MsgBox "File is a Windows file", 16, "OK"
Case ordOS2_1
MsgBox "File is OS/2 1.x file", 16, "OK"
Case ordNTWin
MsgBox "File is NT Windows file", 16, "OK"
Case ordNTChar
MsgBox "File is NT character file", 16, "OK"
Case ordDOSUnknown
MsgBox "File is probably DOS extended file", 16, "OK"
Case ordNotExe
MsgBox "File is not MSDOS EXE file", 16, "OK"
Case errOS2_2
MsgBox "File is OS/2 LE file", 16, "OK"
Case errWinOS2DLL
MsgBox "File is a DLL executable but not by us", 16, "OK"
Case errNEUnknown
MsgBox "File is unknown NE system", 16, "OK"
Case errNTNonIntel
MsgBox "File is unknown type - perhaps a RISC file", 16, "OK"
Case errNTDLL
MsgBox "File is executable, but not by us", 16, "OK"
End Select
End Sub
Function ExeType(sSpec As String) As Integer
'Check specified file to see if it is an
'executable file. If it is, what kind is it?
Dim sNullChr As String
sNullChr = Chr$(0)
Dim hFile As Integer
hFile = FreeFile
'Make sure the file exists on disk
Dim F As String
F = Dir$(sSpec)
If F = "" Then
ExeType = errNoFile
Exit Function
Else
Open sSpec For Binary Access Read Shared As hFile
End If
Dim sHeader As String * 128
Get hFile, 1, sHeader
'MSDOS headers start with magic header "MZ"
Dim sMagic As String * 2
sMagic = Mid$(sHeader, 1, 2)
If sMagic <> "MZ" Then
'Could still be a .BAT, .CMD, .PIF, or .COM file
'but that's not our problem here
ExeType = ordNotExe
Exit Function
End If
'Make an integer (Long to prevent overflows) out
'of offset &H18 and &H19 and then see if offset
'points beyond DOS header. If not, file is MSDOS
'EXE. Since Basic strings are 1-based rather than
'0-based, all hex offsets into file must be
'incremented by one.
Dim iData As Long
iData = Asc(Mid$(sHeader, &H20, 1)) * 256
iData = iData + Asc(Mid$(sHeader, &H19, 1)) + 1
If iData < &H40 Then
ExeType = ordMSDOS
Exit Function
End If
'Get the offset of new .EXE header
iData = Asc(Mid$(sHeader, &H3E, 1)) * 256
iData = iData + Asc(Mid$(sHeader, &H3D, 1)) + 1
Get hFile, iData, sHeader
Close hFile
'New .EXE headers start with magic header "NE"
Dim sMagic2 As String * 2
Dim sZero As String * 2
sMagic = Mid$(sHeader, 1, 2)
sMagic2 = Mid$(sHeader, 3, 2)
sZero = sNullChr & sNullChr
'Check for Windows/OS2 format
If sMagic = "NE" Then
'Get the executable file flags to check for DLL
iData = Asc(Mid$(sHeader, &HE, 1))
If iData And &H80 Then
'This is a DLL (executable but not by us)
ExeType = errWinOS2DLL
Else
'Get the operating system flags (byte, not word)
iData = Asc(Mid$(sHeader, &H37, 1))
If iData And &H2 Then
ExeType ordWindows 'Windows
ElseIf iData And &H1 Then
ExeType = ordOS2_1 'OS2 1.x
Else
ExeType = errNEUnknown 'Unknown NE system
End If
End If
'Check for OS/2 2.x format (cannot execute from Windows or NT)
ElseIf sMagic = "LE" Then
ExeType = errOS2_2 'OS/2 LE
'Check for NT format
ElseIf sMagic = "PE" And sMagic2 = sZero Then
'Get processor flags
iData = Asc(Mid$(sHeader, &H5, 1))
Select Case iData
Case &H4C, &H4D, &H4E, &H4F 'NT for intel 386, 486, 586, 686
ExeType = ordNTWin 'NT Windows
Case Else
ExeType = errNTNonIntel 'Some sort of RISC or other
Exit Function
End Select
'Get the EXE type flags
iData = Asc(Mid$(sHeader, &H18, 1))
If iData And &H20 Then
ExeType = errNTDLL 'executable, but not by us
Exit Function
End If
'Get the subsystem flags to identify NT character
iData = Asc(Mid$(sHeader, &H5D, 1))
If iData = 3 Then ExeType = ordNTChar
'Could also identify Posix files here
Else
'This is an MSDOS file with a header, but it's not
'an NE file. Many 16-bit DOS-extended executables fall
'through here. It could also be a non-EXE file that
'just happens to have "MZ" as its first two bytes.
ExeType = ordDOSUnknown 'probably DOS extended
End If
End Function
Run the example program by pressing F5. Type the name of a file in the Text Box and click the command button. A message box will identify what type of file it is.