[Poiché penso che questo forum non debba contenere soltanto richieste di aiuto, ma che possa anche ospitare soluzioni non richieste,] vorrei portare a conoscenza e, quindi, a beneficio :coder: di tutti gli utenti del forum, la soluzione data all'argomento in oggetto da un utente, Jussi Lahtinen, della mailing-list internazionale di Gambas:
Public Sub Form_Open()
Dim sOutput As String
Exec ["pgrep", "-f", "-l", "NameOfYourProgram.gambas"] Wait To sOutput
If Split(Trim$(sOutput), gb.NewLine).Count > 1 Then
Quit
Endif
End
Insomma, può impedire, per esempio, che cliccando per errore più volte partano contemporaneamente due o più processi del medesimo programma.
Se magari avete anche voi delle soluzioni da aggiungere.... :coder:
Io, per esempio, avevo ipotizzato una possibile soluzione (che a me funziona) con comandi diversi, ma che rispetto alla soluzione di Lahtinen è più lunga, contorta e complessa :danger: .
La riporto :-[ solo per mera curiosità:
Public Sub Form_Open()
Dim index As String
Dim plura As String[]
Dim a, b As Integer
' Otteniamo il PID dei processi (programmi) aperti, aventi il medesimo "nome_programma.gambas":
Shell "ps -aux | grep " & "nome_programma.gambas" To index
plura = Split(index, " ")
For a = 0 To plura.Max
' Cerca il riferimento al 1° programma aperto (cioè a quello con identico nome al proprio):
If Right(plura[a], 20) Like "*.gambas*" Then
' Così può passare a "Kill" la stringa, contenuta da ciascuna variabile "plura"
' "successiva" alle stringhe che si riferiscono al 1° processo (che resta così protetto),
' sino a quando non passerà la stringa contenente il PID del 2° processo
' (se è stato aperto il 2° programma), cioè... se stesso !
For b = a To plura.Max
' Non appena viene passato il PID del 2° processo, questo viene terminato.
' Quindi il programma (se è il 2°) si auto-elimina e non si apre:
Try Shell "kill " & plura[b]
Next
Endif
Next
End
...una sorta di trattore tagliaerba ! ✄ ☠
....e amen !
io invece direi che è assolutamente inutile scomodare shell quando si pu avere:
public sub form_open
DIM P AS NEW Pointer[]
P = Desktop.find(Application.Name)
IF p.count = 1 THEN
message.info("applicazione non ancora avviata")
ELSE IF p.count > 1 THEN
message.info("applicazione già avviata")
fmain.close
END IF
:P
Volevo dirti, fsurfing, che ho provato questa soluzione, ma mi si apre il programma due volte ! :-X
Allora... poiché non era possibile (♫...sviolinata ;D ) che il tuo suggerimento non funzionasse (mi si apriva due volte), mi ci sono applicato . L'ho aggiustato semplicemente così :
Public Sub Form_Open()
Dim P As New Pointer[]
P = Desktop.FindWindow(Application.Name)
If P.count = 0 Then
message.info("applicazione non ancora avviata")
Else If P.count > 0 Then
message.info("applicazione già avviata !")
FMain.Close
End If
End
...ora a me funziona.
Comunque, fsurfing, ottimo suggerimento il tuo: hai eliminato l'uso di "Shell" !
:-\
La più sicura resta questa:
Public Sub Form_Open()
If settings[Application.Name & "_scn/ctrapp"] = "1" Then
If Message.Warning("Il programma è già aperto", "forza apertura", "non aprire di nuovo") = 1 Then
Else
Me.Close
Endif
Endif
settings[Application.Name & "_scn/ctrapp"] = "1"
End
Public Sub Form_Close()
settings[Application.Name & "_scn/ctrapp"] = "0"
End
Ho provato quest'altra soluzione (però torniamo alla Shell !):
Public Sub Form_Open()
Dim risultato As String
Dim iRis As Byte
Shell "ps aux | grep " & "nome_programma.gambas" & " | grep -wv grep | wc -l" To risultato
iRis = CByte(Trim(risultato))
If iRis > 1 Then
FMain.Close
Endif
End
...e funziona.
No, ci ho riprovato, funziona anche aprendo la terza istanza. la logica è giusta, è setting che secondo me non fa quello che pensavo dovrebbe fare.
Invece di usare setting ho provato a usare un file esterno, certo non è un buon metodo ma almeno ho potuto vedere che la mia logica era giusta.
Private Sub scrivi(valore As String)
Dim myfile As String
Dim hfile As File
myfile = User.Home & "/prova.txt"
If myfile Then
hFile = Open myfile For Create
Print #hFile, valore
Close #hFile
Endif
End
Private Sub leggi() As String
Dim myfile As String
Dim hfile As File
Dim lettura As String
myfile = User.Home & "/prova.txt"
If myfile Then
hFile = Open myfile For Input
Line Input #hFile, lettura
Close #hFile
Endif
Return lettura
End
Public Sub Form_Open()
If leggi() = "1" Then
If Message.Warning("Il programma è già aperto", "forza apertura", "non aprire di nuovo") = 1 Then
Else
Me.Close
Endif
Endif
scrivi("1")
End
Public Sub Form_Close()
scrivi("0")
End
@vuot
Ho provato quest'altra soluzione (però torniamo alla Shell):
:ok:
Private iRun As Integer
Public Sub Form_Open()
iRun = settings[Application.Name & "_scn/ctrapp"]
Inc iRun
If iRun > 1 Then
Me.Close
Else
settings[Application.Name & "_scn/ctrapp"] = iRun
settings.Save
Endif
End
Public Sub Form_Close()
Dec iRun
settings[Application.Name & "_scn/ctrapp"] = iRun
End
non dovrebbe
hFile = Open myfile For Create
a me lo ha creato da solo :rolleyes:
A me dà errore "File or directory doesn't exist" sulla riga: hFile = Open myfile For Input !
Del resto suppongo che, quando legge il condizionale:
Public Sub Form_Open()
If leggi() = "1" Then
....
venga chiamata la funzione leggi(), la quale tenta di leggere da un file non ancora creato.
Non ottengo errori, se lo creo prima a parte nella directory prevista dal codice. :-\
Mi dispiace darvi la notizia che a me la soluzione di sotema non funziona. Anche l'idea di scrivere in un file.txt un contatore non è, secondo me, elegante. Io sto cercando di verificare in un colpo solo l'esistenza del mioprogramma.gambas e la contemporanea non esistenza del file mioprogramma -- (cioè quello avviato dall'ide di gambas). Sono arrivato a questa idea dal seguente riscontro:
Avvio programma in prova "TestDbContabFam.gambas"
avvio comando shell: $ ps -ax
------- bla -------bla -------
4281 ? S 0:00 gbr2 /home/piero/mnt/dativari/Gambas2-23/Gambas_Progetti/TestDbContabFam/TestDbContabFam.gambas
Avvio stesso programma dall'Ide di Gambas e successivamente ripeto la shell: $ ps -ax
------- bla -------bla -------
4281 ? S 0:00 gbr2 /home/piero/mnt/dativari/Gambas2-23/Gambas_Progetti/TestDbContabFam/TestDbContabFam.gambas
4291 ? S 0:00 /usr/bin/gbx2 -g -f /home/piero/mnt/dativari/Gambas2-23/Gambas_Progetti/TestDbContabFam --
per eseguire il controllo sulla sola presenza dell'eseguibile, ho modificato la shell di partenza nella sequenza:
DIM bRisult AS Boolean
DIM Esito AS String
SHELL "pgrep -fl TestDbContabFam.gambas" WAIT TO Esito
bRisult = Esito LIKE "*TestDbContabFam.gambas*"
IF bRisult
Message.Warning("Trovato: " & Esito)
QUIT
ENDIF
Come però detto precedentemente al primo avvio dell'eseguibile la stringa TestDbContabFam.gambas viene fornita già come preesistente e quindi la struttura creata non funziona.
Ciao.
Potresti provare questa e dirmi se funzica?
Public Sub Form_Open()
If settings[Application.Name & "_scn/ctrap"] = "1" Then
If Message.Warning("Il programma è già aperto", "forza apertura", "non aprire di nuovo") = 1 Then
Else
Me.Close
Endif
Endif
settings[Application.Name & "_scn/ctrap"] = "1"
settings.Save
End
Public Sub Form_Close()
settings[Application.Name & "_scn/ctrap"] = "0"
settings.Save
End
Mi dispiace darvi la notizia che a me la soluzione di sotema non funziona.
...nel codice postato mancavano un paio di linee, di seguito il codice corretto da inserire nel file FMain.class
Private iRun As Integer
Private hsettings As Settings
Public Sub Form_Open()
hsettings = New Settings(User.Home &/ "prova.conf")
iRun = hsettings[Application.Name & "_scn/ctrapp", 0]
Inc iRun
If iRun > 1 Then
Me.Close
Else
hsettings[Application.Name & "_scn/ctrapp"] = iRun
hsettings.Save
Endif
End
Public Sub Form_Close()
Dec iRun
hsettings[Application.Name & "_scn/ctrapp"] = iRun
hsettings.Save
End
da IDE crea un eseguibile e lancialo + volte...
Penso prorpio di avere risolto, senza impegnare alcun file .txt e senza utilizzare la Form_CLose:
PUBLIC SUB Form_Open()
DIM iPuntIni AS Integer
DIM iPuntFin AS Integer
DIM iLunStriMia AS Integer
DIM iLun2 AS Integer
DIM Esito AS String
DIM $StriMia AS String = "TestDbContabFam.gambas"
iLunStriMia = Len($StriMia)
SHELL "pgrep -fl " & $StriMia WAIT TO Esito
iPuntIni = InStr(Esito, $StriMia)
iPuntFin = RInStr(Esito, $StriMia) + iLunStriMia
iLun2 = iPuntFin - iPuntIni
IF iLun2 > iLunStriMia THEN
QUIT
ENDIF
END
La Sghell restituisce una stringa formata da tutte le ricorrenze contenenti TestDbContabFam.gambas, per cui agendo sulla lunghezza della sottostringa formata dal punto di inizio della prima ricorrenza e dal punto di fine dell'ultima ricorrenza, si intuisce il numero delle chiamate al programma eseguibile e ne viene permessa solamente una, però se la 2^ chiamata viene fatta dall'ide di Gambas, allora la ricorrenza con estensione ".gambas" viene incontrata una volta sola ed il programma si avvia ugualmente. ;) ;D ;D
Provare per credere.
:ciao: :ciao:
l'unione fa la forza:
così dovrebbe funzionare anche in caso che una precedente istanza del programma sia abortita a seguito di errore.
Private hSetting As Settings
Public Sub _new()
End
Public Sub Form_Open()
Dim iPid As Integer = Application.Id
Dim sPid, sSysPid As String
hSetting = New Settings(User.Home &/ "myapp.conf")
If (hSetting["Application/pid", 0] = 0) Then
' questa è la prima esecuzione
hSetting["Application/pid"] = iPid
hSetting.Save
Else
sPid = hSetting["Application/pid"]
Shell "ps aux | grep " & sPid & " | grep -wv grep | wc -l" Wait To sSysPid
sSysPid = Replace(sSysPid, "\n", "")
If (Val(sSysPid) > 0) Then
Me.Close ' Applicazione già attiva
Else
' istanza precedente probabilmente abortita
hSetting["Application/pid"] = iPid
hSetting.Save
Endif
Endif
End
Public Sub Form_Close()
End