3 Ways to Check... Running in IDE or EXE?

Mathimagics
11-13-2003, 11:21 AM
Here are 3 different methods of testing whether a program is running in the IDE or as an EXE. We define a function IsEXE which returns True if running as EXE, False if running in IDE.

Method #1Private Function IsEXE() As Boolean
On Error GoTo IDE
Debug.Print 1 / 0
IsEXE = True
IDE: Exit Function
End Function


This uses the fact that the Debug.Print statement will not be executed in a compiled program, so the "Divide by Zero" error is not triggered.

It's concise, and almost a perfect solution.

It has one minor drawback - sometimes you want to run a program in the IDE with the "Break on ALL errors" option. You'll obviously get the error triggered when you call this function.

A very minor deficiency, really, so this function should suit MOST requirements.

I rate it a 99% solution, losing 1 mark for the minor deficiency.



Method #2Private Function IsEXE() As Boolean
IsEXE = App.EXEName <> App.Title
End Function


This is another simple but effective method, and it avoids using error traps.

It DOES require you to ensure that you compile to an EXE name that is different to the Project name.

The EXE name can be established the first time you compile, and thereafter no further intervention should be required.

But this restriction, however minor, still costs 1 mark, so this solution also scores just 99%


For purists, or obsessive-compulsive types like the author, I also present the 100% solution:

Method #3Private Function IsEXE() As Boolean
Dim AppEXEpath As String
AppEXEpath = App.Path & "\" & App.Exename & ".exe"
IsEXE = StrComp(AppEXEpath, ExePathFromWindow(Me.hWnd), 1) = 0
End Function


The EXEpathFromWindow function is from another demo I posted somewhere, its method is well-known. I'll post it below, but for now just assume it does what it says - given any window handle, it returns the full pathname of the executable file from which the window was created.

If we are in the IDE, that file will be VB6.exe (in whichever folder VB was installed).

If we are in the EXE, it should of course match the App object's Path & EXEname (minus the .exe extension). The use of StrComp avoids any problems caused by compiling to ".EXE" or ".Exe" or ".exe".

Mathimagics
11-13-2003, 11:30 AM
Here is a self-contained module with the EXEpathFromWindow function

Option Explicit
'======================================================
'
' Dr Memory's EXEpathFromWindow function.
' -----------------
'
' Should work on all Win32 platforms NT/2000/XP/98
'
'======================================================

Private Const MAX_PATHLEN = &H104
Private Type PROCESSENTRY32
dwSize As Long
cntUsage As Long
th32ProcessID As Long
th32DefaultHeapID As Long
th32ModuleID As Long
cntThreads As Long
th32ParentProcessID As Long
pcPriClassBase As Long
dwFlags As Long
exeFilename(1 To MAX_PATHLEN) As Byte
End Type

Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" _
(ByVal dwFlags As Long, ByVal dprocess As Long) As Long

Private Declare Function Process32First Lib "kernel32" _
(ByVal hSnapshot As Long, pProcessEntry As PROCESSENTRY32) As Long

Private Declare Function Process32Next Lib "kernel32" _
(ByVal hSnapshot As Long, pProcessEntry As PROCESSENTRY32) As Long

Private Const TH32CS_SNAPPROCESS = &H2&
Private Declare Function CloseHandle Lib "kernel32" _
(ByVal hObject As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long

'
' NT specific
' Note that some returned parameters (ProcessId, hModule)
' are actually arrays but as we call with one request at
' a time a single Long var reference is sufficient.
'
Private Declare Function EnumProcesses Lib "psapi" (ProcessId As Long, _
ByVal cbSize As Long, cbReturned As Long) As Long
Private Declare Function EnumProcessModules Lib "psapi" _
(ByVal ProcessId As Long, hModule As Long, ByVal cbSize As Long, _
cbReturned As Long) As Long
Private Declare Function GetModuleBaseName Lib "psapi" _
Alias "GetModuleBaseNameA" (ByVal hProcess As Long, _
ByVal hModule As Long, ByVal lpFileName As String, _
ByVal nSize As Long) As Long
Private Declare Function GetModuleFileNameEx Lib "psapi" _
Alias "GetModuleFileNameExA" (ByVal hProcess As Long, _
ByVal hModule As Long, ByVal lpFileName As String, _
ByVal nSize As Long) As Long
'
' Version, ProcessId detection
'
Private Declare Function GetWindowThreadProcessId Lib "user32" _
(ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetVersionEx Lib "kernel32" _
Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) _
As Long

Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type

Private Const PROCESS_QUERY_INFORMATION = &H400& ' for OpenProcess
Private Const PROCESS_VM_READ = &H10& ' for OpenProcess

Function ExePathFromWindow(ByVal hWindow As Long) As String
Dim ProcessId As Long, hProcess As Long
'
' The only thing Nt and 95/98 have in common is this!
Call GetWindowThreadProcessId(hWindow, ProcessId)
ExePathFromWindow = ExePathFromProcessId(ProcessId)
End Function

Function ExePathFromProcessId(ByVal ProcessId As Long) As String
Dim hProcess As Long
'
If Not IsWindowsNT Then ' Win2000 is included
Dim Process As PROCESSENTRY32, hSnap As Long, f As Long, Exename$
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0&)
If hSnap = -1 Then Exit Function
Process.dwSize = Len(Process)
f = Process32First(hSnap, Process)
Do While f <> 0
If Process.th32ProcessID = ProcessId Then
GoSub GetExeName
ExePathFromProcessId = Exename ' strZtoStr(process.exeFilename)
Call CloseHandle(hSnap)
Exit Function
End If
Process.dwSize = Len(Process)
f = Process32Next(hSnap, Process)
Loop
Else
Dim s As String, c As Long, hModule As Long
Const cMaxPath = 1023
s = String$(cMaxPath, 0)
hProcess = ProcessHandleFromProcessId(ProcessId)
hModule = BaseModuleHandleFromProcessId(ProcessId)
c = GetModuleFileNameEx(hProcess, hModule, s, cMaxPath)
If c Then ExePathFromProcessId = Left$(s, c)
End If
Exit Function

GetExeName:
Dim i&, cb As Byte
Exename = ""
Do While i < MAX_PATHLEN
i = i + 1
cb = Process.exeFilename(i)
If cb = 0 Then Return
Exename = Exename & Chr$(cb)
Loop
Return
End Function

Private Function IsWindowsNT() As Boolean
Dim verinfo As OSVERSIONINFO
verinfo.dwOSVersionInfoSize = Len(verinfo)
If (GetVersionEx(verinfo)) = 0 Then Exit Function
If verinfo.dwPlatformId = 2 Then IsWindowsNT = True
End Function

Function ProcessHandleFromProcessId(ProcessId As Long)
ProcessHandleFromProcessId = _
OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, ProcessId)
End Function

Function BaseModuleHandleFromProcessId(ProcessId As Long)
Dim hModule As Long, hProcess As Long, bReturned As Long
hProcess = ProcessHandleFromProcessId(ProcessId)
Call EnumProcessModules(hProcess, hModule, 4&, bReturned)
BaseModuleHandleFromProcessId = hModule
End Function

Mathimagics
11-17-2003, 03:55 PM
Here's a very neat 100%-er contributed by step76. This is the best so far, IMHO


Private Function IsEXE() As Boolean
Static bEXE As Boolean

If Not bEXE Then
bEXE = True
Debug.Assert IsEXE() Or True
IsEXE = bEXE
End If
bEXE = False
End Function

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum