0.写配置文件,包括注册表,环境变量和本地文件等。启动的时候写入标志,退出的时候删除即可。缺点就是程序中途崩溃或者被强制终止,那么标志位来不及恢复,后面程序就启动不了。这个方式基本不用。
1.第二种方法是启动一个守护进程,负责这项事情,要启动一个新实例,通过他来调用,他负责管理进程以及服务。一般守护进程需要一直存在,不能被用户轻易干掉。
代码略,一般是调用CreateProcess然后一直监控。
2.内核通知,这类比较常用,比如信号量,事件号,互斥锁等,一般都是有名字对象。启动的时候检查内核对象是否存在,如果存在说明已经启动了实例。
在<<windows核心编程>>第三章里比较全面地介绍了内核对象,并给出一个使用例子,这个例子就是检测运行实例,函数如下:
// Mutex, boundary and namespace used to detect previous running instance
HANDLE g_hSingleton = NULL;
HANDLE g_hBoundary = NULL;
HANDLE g_hNamespace = NULL;
// Keep track whether or not the namespace was created or open for clean-up
BOOL g_bNamespaceOpened = FALSE;
// Names of boundary and private namespace
PCTSTR g_szBoundary = TEXT( "3-Boundary");
PCTSTR g_szNamespace = TEXT( "3-Namespace");
#define AddText printf // 不黏贴其他函数了。
void CheckInstances() {
// Create the boundary descriptor
g_hBoundary = CreateBoundaryDescriptor(g_szBoundary, 0);
// Create a SID corresponding to the Local Administrator group
BYTE localAdminSID[SECURITY_MAX_SID_SIZE];
PSID pLocalAdminSID = &localAdminSID;
DWORD cbSID = sizeof(localAdminSID);
if (!CreateWellKnownSid(
WinBuiltinAdministratorsSid, NULL, pLocalAdminSID, &cbSID)
) {
AddText(TEXT( "AddSIDToBoundaryDescriptor failed: %u\r\n" ),
GetLastError());
return;
}
// Associate the Local Admin SID to the boundary descriptor
// --> only applications running under an administrator user
// will be able to access the kernel objects in the same namespace
if (!AddSIDToBoundaryDescriptor(&g_hBoundary, pLocalAdminSID)) {
AddText(TEXT( "AddSIDToBoundaryDescriptor failed: %u\r\n" ),
GetLastError());