Mutex instances

General FreeBASIC programming questions.
Post Reply
Thrawn89
Posts: 477
Joined: Oct 08, 2005 13:12

Mutex instances

Post by Thrawn89 »

I wish to make a program that can only have one instance of the code...under C++ this can be accomplished via CreateMutex because a specific ID is used in the parameter, and if there is already a Mutex with that id then it fails...

Can this be done in FB with MutexCreate?

Thanks,
Thrawn
VonGodric
Posts: 997
Joined: May 27, 2005 9:06
Location: London
Contact:

Post by VonGodric »

mutexes are used for locking threads while another thread accesses shared resources. And why would you want to have one instance anyway?

you can do smth like:

Code: Select all

sub test ()
   static init = 0
   if (init > 0) exit sub
   init = 1
   '' do your stuff here
end sub
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Post by Zippy »

This works in Windows (compile, execute 2 or more instances from command line or Explorer):

Code: Select all

'fb v0.16 release
option explicit
#include once "windows.bi"
dim as integer res
dim as string mtn
dim as HANDLE mc
'
mtn="MyProgInst" 'your specific ID
SetLastError(0)
mc=CreateMutex(NULL,TRUE,strptr(mtn))
res=GetLastError()
print mc,res
if res=ERROR_ALREADY_EXISTS then
    print "This is not the first instance of this exe (mutex=";mc;")"
else
    print "First instance of this exe (mutex=";mc;")"
end if
sleep
ReleaseMutex(mc)
end
See also: OpenMutex
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Post by yetifoot »

Some people do want to have a single instance program. It is recommended also in some MS documentation for stopping multiple instances, however some people disagree with this due to security implications if someone steals your unique mutex name.

Heres some code I got from one of the API help files, or from MSDN, i forget which now.

The reason for checking ERROR_ACCESS_DENIED, is because we are passing a NULL security descriptor, and will be denied access to the mutex if an other, higher level user has access.

I don't think it can be done using the FB mutex commands, as they don't allow a named mutex, but i could be wrong, i've not used them much.

Code: Select all

#include "windows.bi"

Option Explicit

Function IsAlreadyRunning() As Integer
  Dim ret As DWORD
    If CreateMutex(NULL, TRUE, "_YourProgNameMutex") <> 0 Then
      ret = GetLastError()
      If (ret = ERROR_ALREADY_EXISTS) OR (ret = ERROR_ACCESS_DENIED) Then
        Return -1
      End If
    End If
    Return 0
End Function

If IsAlreadyRunning Then
  Print "An instance of this program is already running"
Else
  Print "Hello"
End If

Sleep

End
Heres some writing on how it could be a potential security problem.

http://blogs.msdn.com/oldnewthing/archi ... 39479.aspx
VonGodric
Posts: 997
Joined: May 27, 2005 9:06
Location: London
Contact:

Post by VonGodric »

oh sry -I misunderstood the point.
Thrawn89
Posts: 477
Joined: Oct 08, 2005 13:12

Post by Thrawn89 »

Ok then, well, I want to be able to port this over to linux, so I guess if someone clicks the icon twice, they've screwed themselves...lol, but I'll import the windows code for the win32 build I guess...

I can understand the security risk, but because it is a game, denial of the program from an attacker is not really my consern...

Plus theres a way to limit the security risk by terminating the new instance AFTER you focus the already instanced program...

I just think its better than a computer crash cause by an impatient user, which is more likey than an attacker...

Is there a way to do this on linux?

Thanks for everything,
Thrawn
DrV
Site Admin
Posts: 2116
Joined: May 27, 2005 18:39
Location: Midwestern USA
Contact:

Post by DrV »

Just for curiosity's sake, why do you need to enforce single instance?

This is tough to do correctly on Linux, due to the fact that there can be multiple users logged in at once, multiple X sessions, multiple desktops, etc... There is no really good way without knowing why you need such a thing. (Of course, the same could be said for Windows if you consider Terminal Services, but most people aren't running Windows Server, whereas X is designed to do this sort of thing. :)
Thrawn89
Posts: 477
Joined: Oct 08, 2005 13:12

Post by Thrawn89 »

Its just for a game, I just think it would be bad to crash the user's computer if the user decides that "oooh, mabey if I click on the icon a few more times it'll load faster"...

But then again, those that have linux, arent the type to do that anyways, so I'll include the code on the win32 build only...kk thanks,

Thrawn
DrV
Site Admin
Posts: 2116
Joined: May 27, 2005 18:39
Location: Midwestern USA
Contact:

Post by DrV »

The part I don't understand is what will "crash the user's computer" when your game is launched multiple times. You shouldn't be able to do anything that would cause an operating system crash without consciously trying to do so.
Thrawn89
Posts: 477
Joined: Oct 08, 2005 13:12

Post by Thrawn89 »

Well, when you are loading large blocks of data into memory/initializing libs and major processor intensive stuff, you dont really want to have two or three copies of that application trying to exact same thing...

Thrawn
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Post by Zippy »

The positives of using a global mutex in Windows are:

1. It's really simple
2. The mutex will be released if something untoward happens (program crash, sys reboot, etc)

The code below is a demo of how to use a (Windows) file locking method to detect multiple instances. This is still in effect a "global lock", not TS-friendly. Write the lock file to the user's home dir to limit one instance per user (TS-friendly). See "Notes:" at end.

Code: Select all

'lockfile for single-instance detection, Windows
' compile, execute 2 or more instances
'fb v0.16 release
option explicit
#include once "windows.bi"
declare function LockFileCheck(fname as string) as HANDLE
dim as integer res
dim as string fname
dim as HANDLE FHandle

fname=exepath + "\Zfile.lck" 'file lock location/name
FHandle=LockFileCheck(fname)
res=LockFile(FHandle,0,0,8,0)
if res=0 then
    print "This is not the first instance"
    'bail here..
else
    print "First instance.."
end if

sleep
res=UnLockFile(FHandle,0,0,8,0)
CloseHandle(FHandle)
end

function LockFileCheck(fname as string) as HANDLE
dim as integer pcount,res
dim tbuff as string
dim as HANDLE FHandle
SetLastError(0)
FHandle = CreateFile(fname, _ 
                     GENERIC_WRITE, _ 
                     FILE_SHARE_WRITE, _ 
                     NULL, _ 
                     OPEN_ALWAYS, _ 
                     FILE_ATTRIBUTE_NORMAL, _ 
                     NULL)
                     
if GetLastError=0 then 'file didn't exist..
    tbuff="LockFile"
    res=WriteFile(FHandle,_ 
                  strptr(tbuff),_ 
                  len(tbuff),_ 
                  @pcount,_ 
                  NULL)
    CloseHandle(FHandle)
    'print "File created"
    LockFileCheck(fname) 'reopen to get handle
end if
    
return FHandle
end function
Notes:

The lock created by code above will release, if not released deliberately, when the process terminates (I think even with abnormal termination). But at the whim (timing) of the OS. Probably not an issue..

This same method, but using flock() or fnctl(), can be used on *.nix - you'd have to create the lock file in /tmp to make it global. BUT (big but) I don't rem if that lock is removed if the creating/locking process terminates without removing same lock. You could also do something extremely crude like parse the proclist checking for a previous instance of your prog.

This code hasn't been tested thoroughly. Caveat emptor. Needs better (any) error checking in case file creation fails..
Post Reply