visual una saber propiedades objetos lista esta ejemplos ejecutando definicion clases clase aplicacion vb6 mutex singleinstance

vb6 - una - objetos de visual basic y sus propiedades



VB6: aplicación de instancia única en todas las sesiones de usuario (3)

Creo que tus instintos son exactamente lo correcto. No sé por qué no sería seguro inferir de ERROR_ACCESS_DENIED que algún otro proceso tiene el mutex, así que efectivamente es lo mismo que ERROR_ALREADY_EXISTS (en este contexto). Pero al mismo tiempo, no se siente Muy bien.

Como sugiere, establecer un descriptor de seguridad adecuado es la forma correcta de hacerlo. MSDN dice que otorgar privilegios MUTEX_ALL_ACCESS aumenta el riesgo de que el usuario tenga que ser un administrador, y creo que necesita MUTEX_ALL_ACCESS. Pero en mi experiencia, funciona bien para los que no son administradores.

Tu pregunta me intrigó lo suficiente como para hacer una prueba rápida. Eso significa que tengo un código fuente, y aquí está:

int wmain(int argc, wchar_t* argv[]) { ACL *existing_dacl = NULL; ACL *new_dacl = NULL; PSECURITY_DESCRIPTOR security_descriptor = NULL; bool owner = false; HANDLE mutex = CreateMutex(NULL,FALSE,L"Global//blah"); if(mutex == NULL) wprintf(L"CreateMutex failed: 0x%08x/r/n",GetLastError()); if(GetLastError() == ERROR_ALREADY_EXISTS) wprintf(L"Got handle to existing mutex/r/n"); else { wprintf(L"Created new mutex/r/n"); owner = true; } if(owner) { // Get the DACL on the mutex HRESULT hr = GetSecurityInfo(mutex,SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,NULL,NULL, &existing_dacl,NULL, &security_descriptor); if(hr != S_OK) wprintf(L"GetSecurityInfo failed: 0x%08x/r/n",hr); // Add an ACE to the ACL EXPLICIT_ACCESSW ace; memset(&ace,0,sizeof(ace)); ace.grfAccessPermissions = MUTEX_ALL_ACCESS; ace.grfAccessMode = GRANT_ACCESS; ace.grfInheritance = NO_INHERITANCE; ace.Trustee.pMultipleTrustee = NULL; ace.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ace.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ace.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ace.Trustee.ptstrName = L"EVERYONE"; hr = SetEntriesInAcl(1,&ace,existing_dacl,&new_dacl); if(hr != S_OK) wprintf(L"SetEntriesInAcl failed: 0x%08x/r/n",hr); // Set the modified DACL on the mutex hr = SetSecurityInfo(mutex,SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,NULL,NULL,new_dacl,NULL); if(hr != S_OK) wprintf(L"SetSecurityInfo failed: 0x%08x/r/n",hr); else wprintf(L"Changed ACL/r/n"); LocalFree(existing_dacl); LocalFree(new_dacl); LocalFree(security_descriptor); } wprintf(L"Press any key..."); _getch(); CloseHandle(mutex); return 0; }

Tengo una aplicación que necesita ser una aplicación de instancia única en todas las sesiones de usuario en una PC con Windows. Hasta ahora, mi investigación se ha centrado en usar un mutex para lograr esto, pero estoy teniendo un problema que no estoy seguro que sea realmente un problema, esta es realmente una pregunta de mejores prácticas, creo.

Aquí está el código antes que nada:

Private Const AppVer = "Global/UNIQUENAME" '' This is not what i am using but the name is unique Public Sub Main() Dim mutexValue As Long mutexValue = CreateMutex(ByVal 0&, 1, AppVer) If (Err.LastDllError = ERROR_ALREADY_EXISTS) Then SaveTitle$ = App.Title App.Title = "... duplicate instance." MsgBox "A duplicate instance of this program exists." CloseHandle mutexValue Exit Sub End If '' Else keep on truckin''

Ahora, en base a este artículo, creo que entiendo que al pasar el puntero NULL a la función CreateMutex como estoy arriba, básicamente estoy asignando cualquier descriptor de seguridad asociado con el usuario actualmente conectado.

Si eso significa lo que creo que es (puedo necesitar más orientación aquí) que me dice que otros usuarios que inicien sesión no podrán "ver" el mutex creado en la sesión original del usuario, ni podrán crear un mutex con el mismo nombre.

Ahora, la evidencia emperical parece respaldar esto. Utilicé un cuadro de mensaje para mostrar el "LastDLLError" que estaba recibiendo, y cuando otro usuario intentó iniciar la aplicación (mientras ya se estaba ejecutando en otra cuenta de usuario) recibiría un código ERROR_ACCESS_DENIED. Estoy de acuerdo con las pruebas en contra de esto junto con el código ERROR_ALREADY_EXISTS y simplemente salir en cualquiera de los dos. Sin embargo, esto parece una especie de hackish y me pregunto si alguien puede sugerir una alternativa. Lo "correcto" parece ser pasar el puntero correcto a la función CreateMutex de modo que cualquier usuario tenga los permisos adecuados para ver los mutexes existentes (¿mutices?), Pero no estoy tan seguro de que esto sea posible sin el actual el usuario registrado es un administrador (que es inaceptable). Cualquier asistencia / orientación es muy apreciada. ¡Gracias por adelantado!


Estaba buscando una solución similar en VB6 a fines del año pasado. En ese momento no pude encontrar ningún ejemplo de aplicaciones VB6 que se comunicaran a través del límite del usuario, así que tuve que escribir el mío.

Ver: comunicación entre procesos a través de semáforos

Puede usar la clase para crear y verificar un semáforo global que le dirá si su aplicación ya se está ejecutando bajo cualquier usuario. No miré las API de Mutex, pero su uso es muy similar. La función GetSecurityDescriptor es lo que desea transportar si ya tiene un código Mutex escrito.


No necesita privilegios de administrador para establecer la seguridad de sus propios mutexes. Aquí hay una aplicación de demostración simple que básicamente le da a Todos / Control total al mutex.

Option Explicit Private Const STANDARD_RIGHTS_REQUIRED As Long = &HF0000 Private Const SYNCHRONIZE As Long = &H100000 Private Const MUTANT_QUERY_STATE As Long = &H1 Private Const MUTANT_ALL_ACCESS As Long = (STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or MUTANT_QUERY_STATE) Private Const SECURITY_DESCRIPTOR_REVISION As Long = 1 Private Const DACL_SECURITY_INFORMATION As Long = 4 Private Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (lpMutexAttributes As Any, ByVal bInitialOwner As Long, ByVal lpName As String) As Long Private Declare Function OpenMutex Lib "kernel32" Alias "OpenMutexA" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As String) As Long Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long Private Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" (pSecurityDescriptor As Any, ByVal dwRevision As Long) As Long Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" (pSecurityDescriptor As Any, ByVal bDaclPresent As Long, pDacl As Any, ByVal bDaclDefaulted As Long) As Long Private Declare Function SetKernelObjectSecurity Lib "advapi32.dll" (ByVal Handle As Long, ByVal SecurityInformation As Long, pSecurityDescriptor As SECURITY_DESCRIPTOR) As Long Private Type SECURITY_DESCRIPTOR Revision As Byte Sbz1 As Byte Control As Long Owner As Long Group As Long pSacl As Long pDacl As Long End Type Private Const MUTEX_NAME As String = "Global/20b70e57-1c2e-4de9-99e5-20f3961e6812" Private m_hCurrentMutex As Long Private Sub Form_Load() Dim hMutex As Long Dim uSec As SECURITY_DESCRIPTOR hMutex = OpenMutex(MUTANT_ALL_ACCESS, 0, MUTEX_NAME) If hMutex <> 0 Then Call CloseHandle(hMutex) MsgBox "Already running", vbExclamation Unload Me Exit Sub End If m_hCurrentMutex = CreateMutex(ByVal 0&, 1, MUTEX_NAME) Call InitializeSecurityDescriptor(uSec, SECURITY_DESCRIPTOR_REVISION) Call SetSecurityDescriptorDacl(uSec, 1, ByVal 0, 0) Call SetKernelObjectSecurity(m_hCurrentMutex, DACL_SECURITY_INFORMATION, uSec) End Sub Private Sub Form_Unload(Cancel As Integer) If m_hCurrentMutex <> 0 Then Call CloseHandle(m_hCurrentMutex) m_hCurrentMutex = 0 End If End Sub