What code would you recommend to determine if a program is already and switch to the running program instead of starting it up again? I can see examples of using CreateMutex on the PowerBasic forums but wonder how best to implement this with FireFly.
Sadly, I'm not a FireFly user, but still, here is the same Mutex & GW_HWNDNEXT approach I had in PowerBASIC...
#Define JumpCompiler "<D:\Free\64\fbc.exe>" 'Compiler to use "< = left delimiter, >" = right delimiter
#Define JumpCompilerCmd "<-s gui -w pedantic "D:\Free\bas\~~Default.rc">" 'Command line to send to compiler (gui or console)
#define UniCode
#Include Once "windows.bi"
#Include Once "win\shellapi.bi"
#Define AppName "Mutex demo"
#Define StaticInfo 101
#Define CrLf Chr(13, 10)
#Define dwMutex 1901310955 '[YYMMDDHHMM] - 10 digits - Max is 4,294,967,295, I use current time
Dim Shared As HINSTANCE hInstance : hInstance = GetModuleHandle(NULL)
'_____________________________________________________________________________
Function WndProc(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As Integer
Dim hStaticInfo As HWND
Static hWindowDefaultFont As HFONT
Function = 0
Select Case (uMsg)
Case WM_CREATE
Dim As NONCLIENTMETRICS NotClientMetrics
NotClientMetrics.cbSize = SizeOf(NONCLIENTMETRICS)
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, NotClientMetrics.cbSize, @NotClientMetrics, 0)
hWindowDefaultFont = CreateFontIndirect(@NotClientMetrics.lfMessageFont)
hStaticInfo = CreateWindowEx(0, "Static", "Try to run another self instance" & CRLF & "(Minimize me before)", _
WS_CHILD Or WS_VISIBLE Or SS_CENTER Or SS_NOTIFY, _
10, 30, 200, 30, _
hWnd, Cast(HMENU, StaticInfo), _
hInstance, NULL)
SendMessage(hStaticInfo, WM_SETFONT, Cast(UInteger, hWindowDefaultFont), TRUE)
Case WM_DESTROY
DeleteObject(hWindowDefaultFont) 'Clean up
PostQuitMessage(0) 'Ask message loop to end
Exit Function
End Select
Function = DefWindowProc(hWnd, uMsg, wParam, lParam)
End Function
'_____________________________________________________________________________
Function WinMain(ByVal hInstance As HINSTANCE, ByVal hPrevInst As HINSTANCE, _
ByVal CmdLine As WString Ptr, ByVal CmdShow As Integer) As UINT
Dim WinClass As WNDCLASS
Dim wMsg As MSG
Dim hWnd As HWND
Dim hIco As HICON
Dim WindowSize As SIZEL
Dim wsAppName As WString * 128
wsAppName = AppName
WindowSize.cx = 230
WindowSize.cy = 120
hIco = ExtractIcon(GETMODULEHANDLE(""), "Shell32.dll", 294) 'o
WinClass.style = CS_HREDRAW Or CS_VREDRAW
WinClass.lpfnWndProc = ProcPtr(WndProc)
WinClass.cbClsExtra = 0
WinClass.cbWndExtra = 0
WinClass.hInstance = hInstance
WinClass.hIcon = hIco
WinClass.hCursor = LoadCursor(NULL, IDC_ARROW)
WinClass.hbrBackground = Cast(HGDIOBJ, COLOR_BTNFACE + 1) 'Default color
WinClass.lpszMenuName = NULL
WinClass.lpszClassName = @wsAppName
Dim hTry As HWND
Dim hMutex As HWND
Dim zMutex As ZString * 16
zMutex = "MyUniqueMutex" 'MaxStringLen is %MAX_PATH, no "\", case sensitive
hMutex = CreateMutex(ByVal NULL, 0, zMutex)
If GetLastError = ERROR_ALREADY_EXISTS Then
Beep()
'Optionnal: MessageBox(HWND_DESKTOP, AppName & " is already running!", AppName, MB_TOPMOST Or MB_OK)
hTry = GetForegroundWindow()
Do While hTry
If GetWindowLongPtr(hTry, GWLP_USERDATA) = dwMutex Then
If IsIconic(hTry) Then ShowWindow(hTry, SW_RESTORE) 'Unminimize exe
SetForegroundWindow(hTry)
Exit Do
End If
hTry = GetWindow(hTry, GW_HWNDNEXT)
Loop
If hTry = 0 Then 'Can't find it!!!
MessageBox(HWND_DESKTOP, AppName & " is running hidden in background!", AppName, MB_TOPMOST Or MB_OK)
End IF
End
End If
If (RegisterClass(@WinClass)) Then
hWnd = CreateWindowEx(WS_EX_WINDOWEDGE, _
wsAppName, wsAppName, _
WS_OVERLAPPED OR WS_CLIPCHILDREN Or WS_DLGFRAME Or WS_BORDER Or WS_VISIBLE Or WS_CAPTION Or _
WS_MAXIMIZEBOX Or WS_MINIMIZEBOX Or WS_SYSMENU , _
(GetSystemMetrics(SM_CXSCREEN) - WindowSize.cx) / 2, _ 'PosX
(GetSystemMetrics(SM_CYSCREEN) - WindowSize.cy) / 2, _ 'PosY
WindowSize.cx, WindowSize.cy, _ 'Width, height
NULL, NULL, hInstance, NULL)
SetWindowLongPtr(hWnd, GWLP_USERDATA, dwMutex) 'Set window mutex
ShowWindow(hWnd, SW_SHOW)
UpdateWindow(hWnd)
While GetMessage(@wMsg, ByVal NULL, 0, 0) > 0
If IsDialogMessage(hWnd, @wMsg) = 0 Then
TranslateMessage(@wMsg)
DispatchMessage(@wMsg)
End If
Wend
End If
DestroyIcon(hIco)
CloseHandle(hMutex)
Function = wMsg.message
End Function
'_____________________________________________________________________________
End WinMain(hInstance, NULL, Command(), SW_NORMAL) 'Call main() and return the error code to the OS
'_____________________________________________________________________________
'
Pierre,
Firefly uses PowerBasic, not Freebasic.
This was my impression, so I double checked with a quick search and got FireFly for FreeBASIC v3.78 uploaded... (https://www.planetsquires.com/protect/forum/index.php?topic=3643.msg27712#msg27712) by Paul and then because the PowerBASIC's answers where quite explicit I thought Richard was adapting code, I guess that it was kind of a redundant variant of the same question.
In any case, for easy find, the PB equivalent of the above code is at Mutex and GWL_USERDATA (https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/51587-mutex-question-bringing-existing-app-to-forefront)
Sorry, I forgot that there was a version of Firefly for FreeBasic. I wonder why somebody will want to use it, since it was deprecated long time ago.
I do use FireFly for FreeBasic and I am pleased with it.
That was my way to learn FreeBasic.
Now I am waiting for WinFBE to become as good and easy as FireFly.
@José, I also use Firefly for freebasic and with the extension i have done arround , it is totally usable,
i use it still with freebasic from 0.24 to 1.06 on 32bits and 1.05 or 1.06 on 64bits
in my understanding it is a vey interresting tool to create simple windowed app , I even can make windowed dll with it.
Even COM app using my old axsuite3 adaptation...
until the new Paul's visual editor is not totally done it is a very simple solution for people not wanting to write all sdk stuff.
As a nostalgic of vb6, it was the closest i've found, and hope to find the same simplicity with the new Paul's visual editor (sorry still not tested)
I take here alse the opportunity to thank you again Paul and you José for the great features of your contributions
kind regards
Marc
Paul: i did not make the evolution on the French translation for your last ide version, (was travelling in your countrie in Montréal)
is it some changes in the existing I have to check or just adding new translations?
Dick,
This code is the entire FF_WinMain in one of my old programs. You can get to FF_WinMain from the Firefly Workspace dialog (F9 to activate the dialog). On the Explorer tab, under Special Functions.
Function FF_WINMAIN(ByVal hInstance As Dword, _
ByVal hPrevInstance As Dword, _
ByVal lpCmdLine As Asciiz Ptr, _
ByVal iCmdShow As Long) As Long
Local hWin As Dword
Local ProgName As String
'If this function returns TRUE (non-zero) then the actual WinMain will exit
'thus ending the program. You can do program initialization in this function.
Dim DrSelFlag(5)
ProgName="User Copy"
If FF_PrevInstance Then
hWin = FindWindow(ByVal %Null, ByVal StrPtr(ProgName))
OpenIcon hWin '-- Activate the first instance
SetForegroundWindow hWin
Function = %True 'return %TRUE if you want the program to end.
Else
Function = %False
End If
End Function
Just change the ProgramName from "User Copy" to your program name. The mutex is handled by the FF routine FF_PrevInstance (in the Functions Library - Hit F8 - in the General branch). The rest I got from the PB forums.
It does exactly what you are asking for.
David
This is the FreeBasic version
Function FF_WINMAIN ( ByVal hInstance as HINSTANCE, _
ByVal hPrevInstance as HINSTANCE, _
ByRef lpCmdLine as String, _
ByVal iCmdShow as Long ) as Long
If FF_PrevInstance Then
Dim hWin as Long = FindWindow(gFLY_AppID, ByVal 0)
OpenIcon hWin '-- Activate the first instance
SetForegroundWindow hWin
Function = True
Else
Function = False 'return TRUE if you want the program to end.
End If
End Function
Hi, I doubt if this actually works. See : https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-winmain (https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-winmain)
QuoteType: HINSTANCE
A handle to the previous instance of the application. This parameter is always NULL. If you need to detect whether another instance already exists, create a uniquely named mutex using the CreateMutex function.
So I think this code does not work for modern Windows versions. It should have worked under older versions. See https://stackoverflow.com/questions/7458436/why-does-previnstance-exist-in-winmain-and-wwinmain-if-it-is-always-null (https://stackoverflow.com/questions/7458436/why-does-previnstance-exist-in-winmain-and-wwinmain-if-it-is-always-null)
Sorry for spoiling...
The FindWindow / OpenIcon / SetForeGroundWindow is still a useful suggestion (did not test).
Wilko
I suggest that you reread the post. It is not checking the hPrevInstance parameter, but calling the FF_PrevInstance function, that in turn calls FindWindow.
You are right, of course. I overlooked the difference between hPrevInstance and FF_PrevInstance. Sorry for the confusion.