APP.PREVINSTANCE QUI TIENT COMPTE DU RÉPERTOIRE

PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 - 29 mai 2009 à 16:58
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 - 29 mai 2009 à 19:51
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/50087-app-previnstance-qui-tient-compte-du-repertoire

violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
29 mai 2009 à 19:51
Il faut pas un identifiant unique par démarrage de l'application justement, mais un ID connu uniquement des process dont on veut vérifier qu'il ne se lancent pas deux fois.

Dans l'exemple, j'ai mis une string "à peu près unique" (YAPM-...), mais sinon on peut utiliser le GUID de l'assembly, mais PAS un GUID généré, sinon jamais on détectera la présence d'une autre instance.

@+ (désolé je répond à l'arrache je pars à mon entrainement dans 1 seconde)
cs_Tropic Messages postés 90 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 1 février 2011
29 mai 2009 à 19:41
Création d'un identifiant unique d'instance.

Pour chaque instance, je veux avoir un identifiant unique,
un globally unique identifier (GUID).

Private m_ID As System.Guid

Sub New()
m_ID = System.Guid.NewGuid
End Sub

Exemple d'identifiant unique:

'0f8fad5b-d9cb-469f-a165-70867728950e

Chaque instance ayant un identifiant unique, je peux ainsi 'repérer' les instances
(en créant une property ReadOnly afin de lire cet identifiant)

Il existe une très faible probabilité
pour que le nouveau GUID soit égal à zéro ou égal à un autre GUID

COPIER COLLER du site
http://plasserre.developpez.com/v5-2.2.htm
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
29 mai 2009 à 19:26
Tu as entièrement raison, on pourrais utiliser le GUID.

Private Function getGuid() As String
Dim assemblyGuid As Guid = Nothing
Dim assemblyObjects As Object() = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(GetType(System.Runtime.InteropServices.GuidAttribute), True)
If assemblyObjects.Length > 0 Then
assemblyGuid = New Guid(DirectCast(assemblyObjects(0), _
System.Runtime.InteropServices.GuidAttribute).Value)
End If
Return assemblyGuid.ToString
End Function
cs_Tropic Messages postés 90 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 1 février 2011
29 mai 2009 à 19:12
violent_ken:
Il m'arrive souvent de lancer le même programme dans des dossiers différents en plusieurs fois.
Parce que le fichier de config n'est pas la même.
Ce qui me gêne c'est
Const FILE_NAME As String = "YAPM- nstanceCheck"
parce que cela signifie que je peux pas le lancer une deuxième fois s'il est dans un autre répertoire.

Mais bon y a peut-être le moyen de générer
FILE_NAME avec un GUID.

Je vais l'étudier.
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
29 mai 2009 à 18:29
Voilà quelques déclarations plus ou moins bien déclarées pour aller avec :


<Flags()> _
Public Enum FileMapAccess As UInteger
FileMapCopy = &H1
FileMapWrite = &H2
FileMapRead = &H4
FileMapAllAccess = &H1F
fileMapExecute = &H20
End Enum

<Flags()> _
Public Enum FileMapProtection As UInteger
PageReadonly = &H2
PageReadWrite = &H4
PageWriteCopy = &H8
PageExecuteRead = &H20
PageExecuteReadWrite = &H40
SectionCommit = &H8000000
SectionImage = &H1000000
SectionNoCache = &H10000000
SectionReserve = &H4000000
End Enum

<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function CreateFileMapping(ByVal hFile As IntPtr, ByVal lpFileMappingAttributes As IntPtr, ByVal flProtect As FileMapProtection, ByVal dwMaximumSizeHigh As UInteger, ByVal dwMaximumSizeLow As UInteger, <MarshalAs(UnmanagedType.LPTStr)> ByVal lpName As String) As IntPtr
End Function

<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function OpenFileMapping(ByVal dwDesiredAccess As UInteger, ByVal bInheritHandle As Boolean, ByVal lpName As String) As IntPtr
End Function

<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function UnmapViewOfFile(ByVal lpBaseAddress As IntPtr) As Boolean
End Function

<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function MapViewOfFile(ByVal hFileMappingObject As IntPtr, ByVal dwDesiredAccess As FileMapAccess, ByVal dwFileOffsetHigh As UInteger, ByVal dwFileOffsetLow As UInteger, ByVal dwNumberOfBytesToMap As UInteger) As IntPtr
End Function

Public Declare Function GetCurrentProcessId Lib "kernel32.dll" () As Integer
Public Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As IntPtr) As Integer


Public Const FILE_MAP_READ As Integer = SECTION_MAP_READ
Public Const FILE_MAP_WRITE As Integer = SECTION_MAP_WRITE
Public Const PAGE_READWRITE As Integer = &H4
Public Const SECTION_MAP_READ As Integer = &H4
Public Const SECTION_MAP_WRITE As Integer = &H2
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
29 mai 2009 à 18:25
Salut,

je pense qu'il faut privilégier la méthode proposée par Renfield (qui permet d'activer le process, et qui en plus est plus performante).

Voilà sa version .Net :
(FILE_NAME à adapter bien sur)



' Return true if the application is already running
Private Function IsAlreadyRunning() As Boolean
Dim hMap As IntPtr
Dim pMem As IntPtr
Dim hPid As Integer

Const FILE_NAME As String = "YAPM-instanceCheck"

'# Nous tentons ici d'acceder au mappage (précedemment créé ?)
hMap = API.OpenFileMapping(API.FILE_MAP_READ, False, FILE_NAME)
If hMap <> IntPtr.Zero Then
'# L'application est déjà lancée.
pMem = API.MapViewOfFile(hMap, API.FileMapAccess.FileMapRead, 0, 0, 0)
If pMem <> IntPtr.Zero Then
'# On récupère le handle vers la précédente fenêtre
hPid = Marshal.ReadInt32(pMem, 0)
If hPid <> 0 Then
'# On active l'instance précedente
Try
AppActivate(hPid)
Catch ex As Exception
'
End Try
End If
API.UnmapViewOfFile(pMem)
End If
'# On libère le handle hmap
API.CloseHandle(hMap)
'# et on prévient l'appelant que l'application avait dejà été lancée.
Return True
Else
'# Nous sommes dans la première instance de l'application.
'# Nous allons laisser une marque en mémoire, pour l'indiquer
hMap = API.CreateFileMapping(New IntPtr(-1), IntPtr.Zero, API.FileMapProtection.PageReadWrite, 0, 4, FILE_NAME)
If hMap <> IntPtr.Zero Then
'# On ouvre le 'fichier' en écriture
pMem = API.MapViewOfFile(hMap, API.FileMapAccess.FileMapWrite, 0, 0, 0)
If pMem <> IntPtr.Zero Then
'# On y écrit l'ID du process courant
Marshal.WriteInt32(pMem, 0, API.GetCurrentProcessId)
API.UnmapViewOfFile(pMem)
End If
'# Pas de CloseHandle hMap ici, sous peine de détruire le mappage lui-même...
End If
End If

Return False

End Function

@+
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
29 mai 2009 à 16:58
salut,

tu peux poster ton snippet à cette adresse :
http://www.codyx.org/snippet_autoriser-qu-seule-instance-application_211.aspx

(même login/pass)
merci
Rejoignez-nous