实现应用程序的单实例运行有很多种方式。如果是有窗口的应用程序,可以通过FindWindow()查找窗口来确认是否已有同名窗口存在。如果是无窗口的应用程序,可以用互斥体等内核对象实现。一般来说,在程序的入口处检查是否已有实例在运行。如果没有,则继续执行。如果有,则退出本次运行。基本流程如下图所示。
以互斥体实现的单实例参考代码如下。
{
HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT( " SINGLE_INSTANCE " ));
if ( ! hMutex)
{
RETAILMSG( 1 ,(TEXT( " \r\nFailed to CreateMutex()... " )));
return 0 ;
}
if ( GetLastError() == ERROR_ALREADY_EXISTS)
{
RETAILMSG( 1 ,(TEXT( " \r\nApp already run,CloseHandle(%x)... " ), hMutex));
CloseHandle(hMutex);
return 0 ;
}
RETAILMSG( 1 ,(TEXT( " \r\nApp is running (%x)... " ), hMutex));
Sleep( 3000 );
RETAILMSG( 1 ,(TEXT( " \r\nApp prepare to exit... " )));
Sleep( 2000 );
RETAILMSG( 1 ,(TEXT( " \r\nApp exit(%x)... " ), hMutex));
return 0 ;
}
项目中的倒车可视和DVD播放都使用了TCC89的CIF接口,它们不能同时运行。其中,DVD播放是应用程序实现的,而倒车可视在驱动中处理。在播放DVD的过程中,如果进入倒车可视,需首先关闭DVD播放程序,在退出倒车可视时,再启动DVD播放。DVD播放程序的退出时间较长,也就是T3,大概在2S左右。由于DVD播放程序是单实例运行的,所以在T3这个时间内启动第二个实例会失败,第一个实例也将退出。这样就会出现退出倒车可视后,DVD播放无画面的现象。
为了解决这个问题,需要在检查单实例时做一些调整。如果检查到有实例在运行,并不马上退出,而是等一段时间后再检查一次,如果先前的实例退出了,则继续运行本次的程序。如果先前的实例仍然在运行,则退出本次运行。其中等待的时间,可以设置为T3的2倍。修改后的代码如下。
{
HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT( " SINGLE_INSTANCE " ));
if ( ! hMutex)
{
RETAILMSG( 1 ,(TEXT( " \r\nFailed to CreateMutex()... " )));
return 0 ;
}
if ( GetLastError() == ERROR_ALREADY_EXISTS)
{
RETAILMSG( 1 ,(TEXT( " \r\nApp already run,CloseHandle(%x)111... " ), hMutex));
CloseHandle(hMutex);
Sleep( 4000 );
hMutex = CreateMutex(NULL, FALSE, TEXT( " SINGLE_INSTANCE " ));
if ( ! hMutex)
{
RETAILMSG( 1 ,(TEXT( " \r\nFailed to CreateMutex()... " )));
return 0 ;
}
if ( GetLastError() == ERROR_ALREADY_EXISTS)
{
RETAILMSG( 1 ,(TEXT( " \r\nApp already run,CloseHandle(%x)222... " ), hMutex));
CloseHandle(hMutex);
return 0 ;
}
}
RETAILMSG( 1 ,(TEXT( " \r\nApp is running (%x)... " ), hMutex));
Sleep( 3000 );
RETAILMSG( 1 ,(TEXT( " \r\nApp prepare to exit... " )));
Sleep( 2000 );
RETAILMSG( 1 ,(TEXT( " \r\nApp exit(%x)... " ), hMutex));
return 0 ;
}
修改前,运行的结果如下图所示。可以看到,在T2和T3时间内启动的实例都失败了。
修改后,运行的结果如下图所示。可以看到,在第一个实例结束后,第二个实例开始了运行,而其他的实例都逐一关闭。
对比两次执行的结果,可以看到,采用第二种方法应该能有所改善。但是否会带来新的问题呢?解BUG最怕的就是解了一个,却又引入一堆!