News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Detecting an existing application instance

Started by MichaelW, January 04, 2005, 08:59:15 PM

Previous topic - Next topic

MichaelW

After seeing mention of the subject here, I decided I needed to learn how to detect a previous instance of an application using a mutex. Based on the information here, I initially created a procedure the accepted a mutex name parameter, checked the Windows version, allocated memory, and conditionally prefixed the name with "Global\". After much experimentation and bug hunting, I determined that there was a major problem with this approach. If I freed the allocated memory within the procedure, then the next instance of the app would create a new mutex rather than opening an existing mutex, and the detection would fail. So I decided to go with a very simple implementation that uses whatever mutex name the programmer supplies. The code does not close the mutex handle, but per the PSDK this should not be a problem because the system will close the handle and destroy the mutex when the process terminates.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    .486                       ; create 32 bit code
    .model flat, stdcall       ; 32 bit memory model
    option casemap :none       ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\kernel32.inc

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\kernel32.lib

    include \masm32\macros\macros.asm

    ; ------------------------------------------------------------------
    ; Returns TRUE if the mutex object specified by quoted_mutex_name
    ; exists. For Windows 2000 & XP the mutex name should be prefixed
    ; with "Global\" to ensure that the global name space is used.
    ; Note that the name must not contain "\" characters other than
    ; the *one* following "Global".
    ;
    ; Contrary to statements in at least one Microsoft document, the
    ; "Global\" prefix does not appear to be necessary for Windows
    ; 2000 Pro SP4, and it does not produce any apparent error under
    ; Windows 98 SE.
    ; ------------------------------------------------------------------
    mutex_exists MACRO quoted_mutex_name
        invoke CreateMutex, NULL, FALSE, chr$( quoted_mutex_name )
        .IF eax != NULL && FUNC( GetLastError ) == ERROR_ALREADY_EXISTS
          mov   eax, TRUE
        .ELSE
          mov   eax, FALSE
        .ENDIF
        EXITM <eax>
    ENDM

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    .data
    .code

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

start:

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .IF mutex_exists( "Global\xxx" )
        print chr$( 13,10,"Mutex does exist" )
    .ELSE
        print chr$( 13,10,"Mutex does not exist" )
    .ENDIF

    mov eax, input( 13,10,"Press enter to exit...",13,10 )
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


I have tested this, as posted, under Windows 2000 Pro SP4 and Windows 98 SE. It would be helpful if someone could test it under other versions of Windows.

eschew obfuscation

00100b

You're timing is perfect.  I was just asking myself earlier today how I would be able to detect a previous instance of an application to enforce only a single instance running.

I had looked at the FindWindow method (and a couple of others mentioned in the MSDN Library) but hadn't had the time today to play with it.

I will give this code a try on XP, either later tonight or early tomorrow morning.

Thanks Michael  :U

donkey

You should not have a problem on any Windows version, I use a Mutex object for the SingleInstance function in my system library and have tested it on 95, 98SE, NT4, 2K and XP without a problem...

SingleInstance FRAME pMutexString
uses ebx

invoke CreateMutexA,0,0,[pMutexString]
mov ebx,eax
invoke GetLastError
cmp eax,ERROR_ALREADY_EXISTS
jne >
invoke CloseHandle,ebx
invoke ExitProcess,0
:
mov eax,ebx
RET
ENDF
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

00100b


QvasiModo

Hi all :)

I have some a couple silly questions... why is the "Global\" needed for Windows XP and 2K? And doesn't this break compatibility with previous versions of Windows?

donkey

As far as I understand it, the Global\ is only necessary if terminal services is running in 2K otherwise it is ignored, with XP terminal services are always running but the Global\ is only necessary if you have multiple users and are switching between them. Since in most cases you can allow multiple instances to be used as long as different users are running them in their kernel namespace, I don't generally use it. However my SingleInstance function allows for it.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable