Despite the timing, this is not related just to the new release.
FF will warn you if you try to compile a project if the executable for said project is currently running. It doesn't, however check to see if the running executable is in the projects release folder. When the executable is not in the projects release folder, FF incorrectly states that the compile will fail. So, projects I have created for aiding in my programming have to be shut down for compiling a new version (mildly annoying). My request would be to have FF make that check to see if the running executable is indeed in the release folder before warning.
Additionally, I have often wondered why FF doesn't have an option to terminate the current executable and continue with the compile. See attachment.(http://abortmsg.jpg)
If implemented, this should have an environment setting to make it an automatic operation if the user chooses.
David
Either that... or have the Firefly ide execute a renamed executable everytime. This error should never happen that way.
I remember working on this code for a very long time. I was implementing stuff to look at Process ID's, etc and trying to determine what process was running to determine the exe and launch location, blah blah blah. It all got very complicated very quickly. :)
In the end, I settled on the most basic approach:
Function IsEXERunning( ByVal sClassName As String ) As Long
Local zClassName As Asciiz * %MAX_PATH
Local hWindow As Dword
hWindow = GetForegroundWindow()
Do
hWindow = GetWindow(hWindow, %GW_HWNDNEXT)
If (IsWindowVisible(hWindow)) And (GetParent(hWindow) = %HWND_DESKTOP) Then
GetClassName hWindow, zClassName, %MAX_PATH
If Instr(LCase$(zClassName), LCase$(sClassName)) Then
Function = %TRUE
Exit Function
End If
End If
Loop Until hWindow = 0
End Function
Paul, if you want to do it that way, a simple way to do so would be to execute the produced exe in a thread using CreateProcess(), you can then WaitForSingleObject() until the process ends. The main process would know about this by reading a variable in a timer (use critical sections!) and have the thread modify a variable with a pointer. :) I hope i explained myself correctly.
This way the Firefly IDE continues to work as usual and at the same time you check if the produced exe already finished.
As an extra idea, you can then add a feature to force close the running app using TerminateProcess() and CloseHandle() in case of accidental endless loop, from within the firefly IDE without having to use the task manager (as i usually end up closing unresponsive apps when i make a mistake :D ).
I put this together today. The skeleton is from Jose's Corner on PB in the form of a PSAPI demo.
It's all in Form1. Sloppy, but shows how it can be done.
'--------------------------------------------------------------------------------
Function FORM1_WM_CREATE ( _
hWndForm As Dword, _ ' handle of Form
ByVal UserData As Long _ ' optional user defined Long value
) As Long
gCompletePath = "C:\!FF\!FF37\Sample ListView\release\Sample ListView.exe"
Terminate
MsgBox "Closed " & Str$(gCount) & " instances."
Function = 0 ' change according to your needs
End Function
Global gPID As Dword
Global gCompletePath As String
Global gCount As Integer
Sub Terminate
Dim aProcesses(1024) As Dword
Local cbNeeded As Dword
Local cProcesses As Dword
Local i As Long
If IsFalse EnumProcesses(aProcesses(LBound(aProcesses)), _
(UBound(aProcesses) - LBound(aProcesses) + 1) * 4, cbNeeded) Then Exit Sub
cProcesses = cbNeeded \ 4
For i = 0 To cProcesses - 1
EnumAllProcesses aProcesses(i)
Next
End Sub
Function EnumAllProcesses (ByVal processID As Dword) As Integer
Dim hMods(0 To 1023) As Dword
Local hProcess As Dword
Local cbNeeded As Dword
Local i As Long
Local szModName As Asciiz * %MAX_PATH
hProcess = OpenProcess (%PROCESS_QUERY_INFORMATION Or _
%PROCESS_VM_READ, %FALSE, processID)
If hProcess = 0 Then Exit Function
If IsFalse EnumProcessModules(hProcess, hMods(LBound(hMods)), _
(UBound(hMods) - LBound(hMods) + 1) * 4, cbNeeded) Then Exit Function
GetModuleFileNameEx(hProcess, hMods(i), szModName, SizeOf(szModName))
If szModName = gCompletePath Then
gPID = ProcessID
EnumWindows(CodePtr(EnumTopWindows), 0&)
End If
CloseHandle hProcess
End Function
' Can't get a window handle directly from a PID. Have to enumerate top windows looking for the right PID
Function EnumTopWindows (ByVal hWndChild As Long, lRaram As Long) As Long
Local PID As Dword
GetWindowThreadProcessId (hWndChild,PID)
If PID = gPID Then
PostMessage hWndChild, %WM_SysCommand, %SC_Close, 0
Incr gCount
Function = 0 'Can't be more than one with a given PID
Else
Function = 1
End If
End Function
Have to include "PSAPI.INC".
It will "politely" stop every occurrence of the running project. As Elias pointed out, sometimes you might need to force them closed, but that's easy also. Just didn't include that because then I'd have to make some examples of hung projects on purpose. ???
Should work all the way back to Windows XP when PSAPI was created.
Thanks David, your code worked very well :)
I did add a UCASE check to ensure that the path was matched:
If UCase$(szModName) = UCase$(gCompletePath) Then
I am not sure about the closing of already running processes Is that a good idea? The PBEDIT editor simply displays a warning message and aborts the compile:
Error 613 in (0:000): Cannot compile - the program is now running
FireFly's approach is the same. Rather than go through a possible lengthy code generation and compile, it checks first to see if the running. FireFly's problem is that it does not differentiate between exe's running from the Release folder and the same application running from a different folder. That's why I like your code - you can specifically test for the exe's path.
Attached is a new FireFly.exe (PowerBASIC) that has David's code included. It does not terminate a running exe but it does do a better job of now determining if the correct exe/path is running. Give it a test and see if it is okay.
Thanks Paul, I will check it out.
Quote from: TechSupport on June 06, 2015, 08:54:06 AM
I am not sure about the closing of already running processes Is that a good idea?
That's why I said it "politely" asks the program to close. It's exactly the same as if the user hit the sys_close button. The program can intercept it (if programmed to) and do housekeeping before shutting down, notify the user that files aren't saved and ask if they want them saved, block the shutdown request, etc.
The programmer knows his code best and can make an informed decision whether the program should be stopped. All I asked is for the choice. :)
David
It works great. Even if you don't add code to terminate, this is a much welcome addition.
Thanks!