PCPT
Messages postés13272Date d'inscriptionlundi 13 décembre 2004StatutMembreDernière intervention 3 février 2018
-
29 mai 2009 à 16:58
violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 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.
violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 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és90Date d'inscriptionlundi 16 décembre 2002StatutMembreDerniè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
violent_ken
Messages postés1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 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és90Date d'inscriptionlundi 16 décembre 2002StatutMembreDerniè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és1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 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
<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és1812Date d'inscriptionmardi 31 mai 2005StatutMembreDernière intervention26 octobre 20102 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és13272Date d'inscriptionlundi 13 décembre 2004StatutMembreDernière intervention 3 février 201847 29 mai 2009 à 16:58
29 mai 2009 à 19:51
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)
29 mai 2009 à 19:41
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
29 mai 2009 à 19:26
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
29 mai 2009 à 19:12
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.
29 mai 2009 à 18:29
<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
29 mai 2009 à 18:25
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
@+
29 mai 2009 à 16:58
tu peux poster ton snippet à cette adresse :
http://www.codyx.org/snippet_autoriser-qu-seule-instance-application_211.aspx
(même login/pass)
merci