2012-02-10 10 views
5

Deseo crear mutex por un servicio de Windows y un exe con los mismos nombres usando la función CreateMutex. Si el servicio de Windows crea un mutex y cuando el exe intenta crear otro mutex con el mismo nombre, lo hace sin ningún error como ERROR_ALREADY_EXIST.Mismo nombre mutex para un servicio de Windows y exe en Windows 7

Esto ocurre solo en Windows 7. Pero para Windows XP se muestra ERROR_ALREADY_EXIST. No puedo distinguir el motivo de esta diferencia en el sistema operativo y cómo corregir este problema.

Código de ejemplo

Para el código de servicio

#include<iostream> 
#include<windows.h> 
#include<winbase.h> 
using namespace std; 
#define SLEEP_TIME 50000 

typedef void* handle; 
typedef WINADVAPI BOOL (WINAPI *PInitializeSecurityDescriptor)(PSECURITY_DESCRIPTOR, DWORD); 
typedef WINADVAPI BOOL (WINAPI *PSetSecurityDescriptorDacl)(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL); 
#define LOGFILE "D:\\result.txt" 
handle temp=NULL; 
static int a=65; 
char muname[]={"NewMutex2"}; 
int errNm; 
char *str; 
FILE* log; 

SECURITY_ATTRIBUTES *g_pSaCms; 
SERVICE_STATUS ServiceStatus; 
SERVICE_STATUS_HANDLE hStatus; 

void ServiceMain(int argc, char** argv); 
void ControlHandler(DWORD request); 
int InitService(); 


bool Win32Mutex(char muname[8]) 
{ 

    HINSTANCE hAdvApi = LoadLibrary("Advapi32.DLL"); 
    PInitializeSecurityDescriptor pInitializeSecurityDescriptor = 0; 
    PSetSecurityDescriptorDacl pSetSecurityDescriptorDacl = 0; 
    PSECURITY_DESCRIPTOR pSD = 0; 
    g_pSaCms = new SECURITY_ATTRIBUTES; 
    if (g_pSaCms == 0) 
    { 
     prinerr(); 
     return 1; 
    } 
    memset(g_pSaCms,0X0, sizeof(*g_pSaCms)); 
    g_pSaCms->nLength = sizeof(*g_pSaCms); 
    g_pSaCms->bInheritHandle = 1; 

    pSD = new SECURITY_DESCRIPTOR; 

    if (pSD == 0) 
    { 
     printerr(); 
      goto LABEL_CSA_ERROR; 
    } 

    pInitializeSecurityDescriptor = (PInitializeSecurityDescriptor)GetProcAddress(hAdvApi,"InitializeSecurityDescriptor"); 

    if (pInitializeSecurityDescriptor == 0) 
    { 
     printerr(); 
      goto LABEL_CSA_ERROR; 
    } 

    pSetSecurityDescriptorDacl = (PSetSecurityDescriptorDacl)GetProcAddress(hAdvApi, "SetSecurityDescriptorDacl"); 

    if (pSetSecurityDescriptorDacl == 0) 
    { 
      goto LABEL_CSA_ERROR; 
    } 

    if (!(*pInitializeSecurityDescriptor)(pSD, SECURITY_DESCRIPTOR_REVISION) 
      || (!(*pSetSecurityDescriptorDacl)(pSD, TRUE, (PACL)0, FALSE))) 
    { 
      goto LABEL_CSA_ERROR; 
    } 

    (void)FreeLibrary(hAdvApi); 
    g_pSaCms->lpSecurityDescriptor=pSD; 
    goto LABEL_CSA_PASS; 

LABEL_CSA_ERROR: 
    (void)FreeLibrary(hAdvApi); 

    if (pSD != 0) 
    { 
     delete pSD; 
     pSD = 0; 
    } 

    if (g_pSaCms != 0) 
    { 
     delete g_pSaCms; 
     g_pSaCms = 0; 
    } 


LABEL_CSA_PASS: 
    temp=::CreateMutex(g_pSaCms,0,muname); //for icdcomm 
    errNm=GetLastError(); 
    if (!temp) 
    { 
     print_err(); 
    } 
    else 
    { 
     print_err(); 
    } 
    if ((!temp) || errNm == ERROR_ALREADY_EXISTS) 
    { 
      if(temp) 
      { 
      (void)CloseHandle(temp); 
      a++; 
      muname[8]=a; 
      Win32Mutex(muname); 
      } 
      else 
      { 
      printInf() 
      } 
      return 0; 
    } 
    return 1; 
} 



int main() 
{ 
    SERVICE_TABLE_ENTRY ServiceTable[2]; 
    ServiceTable[0].lpServiceName = "MemoryStatus"; 
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; 

    ServiceTable[1].lpServiceName = NULL; 
    ServiceTable[1].lpServiceProc = NULL; 
    StartServiceCtrlDispatcher(ServiceTable); 
    return 0; 
} 

void ServiceMain(int argc, char** argv) 
{ 
    int error; 
    ServiceStatus.dwServiceType  = SERVICE_WIN32; 
    ServiceStatus.dwCurrentState  = SERVICE_START_PENDING; 
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; 
    ServiceStatus.dwWin32ExitCode  = 0; 
    ServiceStatus.dwServiceSpecificExitCode = 0; 
    ServiceStatus.dwCheckPoint   = 0; 
    ServiceStatus.dwWaitHint   = 0; 

    hStatus = RegisterServiceCtrlHandler(
     "MemoryStatus", 
     (LPHANDLER_FUNCTION)ControlHandler); 
    if (hStatus == (SERVICE_STATUS_HANDLE)0) 
    { 
     // Registering Control Handler failed 
     return; 
    } 
    // Initialize Service 
    error = InitService(); 
    if (error) 
    { 
     // Initialization failed 
     ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
     ServiceStatus.dwWin32ExitCode  = -1; 
     SetServiceStatus(hStatus, &ServiceStatus); 
     return; 
    } 

    // My service 
    muname[8]=a; 
    Win32Mutex(muname); 

    // We report the running status to SCM. 
    ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
    SetServiceStatus (hStatus, &ServiceStatus); 


    // The worker loop of a service 
    while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) 
    { 
     Sleep(SLEEP_TIME); 
    } 
    return; 
} 

// Control handler function 
void ControlHandler(DWORD request) 
{ 
    switch(request) 
    { 
     case SERVICE_CONTROL_STOP: 
      ServiceStatus.dwWin32ExitCode = 0; 
      ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
      SetServiceStatus (hStatus, &ServiceStatus); 
      return; 

     case SERVICE_CONTROL_SHUTDOWN: 

      ServiceStatus.dwWin32ExitCode = 0; 
      ServiceStatus.dwCurrentState = SERVICE_STOPPED; 
      SetServiceStatus (hStatus, &ServiceStatus); 
      return; 

     default: 
      break; 
    } 

    // Report current status 
    SetServiceStatus (hStatus, &ServiceStatus); 

    return; 
} 

Para el código ejecutable (código permanece igual, Buc único cambio en la función principal)

int main() 
{ 
    muname[8]=a; 
    Win32Mutex(muname); 
    Sleep(SLEEP_TIME); 
    return 0; 
} 
+0

¿A qué te refieres? Usted dijo que 'ERROR_ALREADY_EXIST' aparece en ambos casos (en ambas versiones de Windows). Los procesos pueden compartir (nombrado) mutex. Uno lo creará (servicio en su caso, ya que se ejecuta antes de su aplicación independiente) y otro (su aplicación) simplemente lo abrirá (con 'CreateMutex' que devolverá' ERROR_ALREADY_EXIST'). –

+0

@Bojan: No, dijo que el código se ejecuta en Win7 *** sin *** 'ERROR_ALREADY_EXIST'. –

+0

Oooups, mi error, tenía demasiadas ventanas abiertas, estaba haciendo tareas múltiples, así que pasé por alto la palabra :) –

Respuesta

16

En XP:

El servicio, ejecutándose en sess ion cero, crea el mutex. La aplicación, que también se ejecuta en la sesión cero, abre con éxito un identificador para el mutex existente y el último error se establece en ERROR_ALREADY_EXISTS para informarle lo sucedido.

En Windows 7:

El servicio, que se ejecuta en la sesión cero, crea el mutex. La aplicación, que probablemente se está ejecutando en la sesión uno, crea un nuevo mutex que tiene el mismo nombre. Los dos mutexes son independientes. Esto es posible porque los nombres mutex tienen un alcance para la sesión actual.

si desea que el mutex para ser compartidos es necesario crear en el espacio de nombres global anteponiendo el nombre con el prefijo "Global \", es decir:

char muname[]={"Global\\NewMutex2"}; 

se pueden encontrar más detalles sobre session zero isolation aquí .

+0

Gracias por la respuesta. Una pregunta de seguimiento, ¿cómo hacemos una sola pieza de código, que funciona tanto en vista previa y pos-Vista. ¿Podemos simplemente usar GLOBAL \ para el sistema operativo WIN o necesitamos proteger diferentes tipos de mutex con header guard? ¿Cuál sería su consejo? –

+0

Este artículo implica que "Global" es compatible desde Windows 2000 en adelante: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684292%28v=vs.85%29.aspx – arx

+0

Thanks arx for la respuesta. La solución funcionó para mí – Baplix