Compile Abort

Started by David Kenny, June 04, 2015, 06:12:52 PM

Previous topic - Next topic

David Kenny

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.
If implemented, this should have an environment setting to make it an automatic operation if the user chooses.

David

Elias Montoya


Either that... or have the Firefly ide execute a renamed executable everytime. This error should never happen that way.
Win7, iMac x64 Retina display 5K, i7-5820K 4.4 ghz, 32GB RAM, All updates applied. - Firefly 3.70.

Paul Squires

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 Squires
PlanetSquires Software

Elias Montoya

 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 ).



Win7, iMac x64 Retina display 5K, i7-5820K 4.4 ghz, 32GB RAM, All updates applied. - Firefly 3.70.

David Kenny

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.

Paul Squires

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.
Paul Squires
PlanetSquires Software

Paul Squires

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.
Paul Squires
PlanetSquires Software

David Kenny

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

David Kenny

It works great.  Even if you don't add code to terminate, this is a much welcome addition.

Thanks!