/某软件的实现方法
v5 = CreateMutexA(0, 0, "Mutex_XXXX_object");
if ( GetLastError() == 183 && (CloseHandle(v5), v6 = GetDesktopWindow(), v7 = GetWindow(v6, 5u), IsWindow(v7)) )//GW_CHILD
{
while ( !GetPropA(v7, *(LPCSTR *)(v4 + 140)) )
{
v7 = GetWindow(v7, 2u);//GW_HWNDNEXT
if ( !IsWindow(v7) )
goto LABEL_5;//继续执行
}
if ( IsIconic(v7) )
ShowWindow(v7, 9);//SW_RESTORE
SetForegroundWindow(v7);
}
if ( GetLastError() == 183 && (CloseHandle(v5), v6 = GetDesktopWindow(), v7 = GetWindow(v6, 5u), IsWindow(v7)) )//GW_CHILD
{
while ( !GetPropA(v7, *(LPCSTR *)(v4 + 140)) )
{
v7 = GetWindow(v7, 2u);//GW_HWNDNEXT
if ( !IsWindow(v7) )
goto LABEL_5;//继续执行
}
if ( IsIconic(v7) )
ShowWindow(v7, 9);//SW_RESTORE
SetForegroundWindow(v7);
}
方法一:
::CreateMutex(NULL, FALSE, "MyAPP");
if(ERROR_ALREADY_EXISTS == GetLastError())
{
AfxMessageBox("Already run!");
return FALSE;
}
方法二:
一个程序可以运行多个实例(进程),那我们如何让它仅运行一个实例呢?很简单,使用#pragma编译器指令在进程的地址空间内创建一个“共享节”就可以 达到目的,这个“共享节”里的数据为多个运行的进程所共享,这样我们通过设置一个变量比如:unsigned g_nInstanceCount;作为运行实例的计数,在程序入口处检测一下g_nInstanceCount是否为1,true则禁止运行,否则 g_nInstanceCount++并运行一个实例。
具体如下:
#pragma data_seg("Shared")//这个共享节叫做Shared
unsigned g_nInstanceCount =0;//计数初始为0
#pragma data_seg() //设置完毕
#pragma comment(linker,"/:SECTION:Shared,RWS ")//这句话告诉连接器,我要将Shared设为读写共享
好了,让我们实际动手来做一个小的例子看看,在VC6.0下可以,但在其它IDE(如Code Block)中就有不能达到效果的例子:
#include <iostream>
using namespace std;
#pragma data_seg("Shared")
unsigned g_nInstanceCount = 0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:Shared,RWS")
int main()
{
if(g_nInstanceCount>=1)
{
cout<<"Can only running an instance!"<<endl;
return 0;
}
g_nInstanceCount++; //实例计数加1
cout<<"This is a console program!"<<endl;
system("pause");
return 0;
}
::CreateMutex(NULL, FALSE, "MyAPP");
if(ERROR_ALREADY_EXISTS == GetLastError())
{
}
方法二:
一个程序可以运行多个实例(进程),那我们如何让它仅运行一个实例呢?很简单,使用#pragma编译器指令在进程的地址空间内创建一个“共享节”就可以 达到目的,这个“共享节”里的数据为多个运行的进程所共享,这样我们通过设置一个变量比如:unsigned g_nInstanceCount;作为运行实例的计数,在程序入口处检测一下g_nInstanceCount是否为1,true则禁止运行,否则 g_nInstanceCount++并运行一个实例。
具体如下:
#pragma data_seg("Shared")//这个共享节叫做Shared
unsigned g_nInstanceCount =0;//计数初始为0
#pragma data_seg()
#pragma comment(linker,"/:SECTION:Shared,RWS ")//这句话告诉连接器,我要将Shared设为读写共享
好了,让我们实际动手来做一个小的例子看看,在VC6.0下可以,但在其它IDE(如Code Block)中就有不能达到效果的例子:
#include <iostream>
using namespace std;
#pragma data_seg("Shared")
unsigned g_nInstanceCount = 0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:Shared,RWS")
int main()
{
if(g_nInstanceCount>=1)
{
cout<<"Can only running an instance!"<<endl;
return 0;
}
g_nInstanceCount++;
cout<<"This is a console program!"<<endl;
system("pause");
return 0;
}
方法三:
要使应用程序只运行一个实例,一个简单的方法是在应用程序类中使用互斥量,这可以用VC下的GUIDGEN.EXE程序产生.GUIDGEN.EXE位于VC安装目录CommonTools目录下
实例
1: 新建一基于对话框的工程ex1,采用默认设置
2: 用GUIDGEN.EXE产生一个全局标志,#define one "产生的全局标志"
本例中产生的语句如下:#define one "0xbe8e2ce1, 0xdab6, 0x11d6, 0xad, 0xd0, 0x0, 0xe0, 0x4c, 0x53, 0xf6, 0xe6"
3: 在应用程序类CEx1App::InitInstance()中,用CreateMutex函数创建一个互斥量,后调用函数GetLastError()
如果结果等于ERROR_ALREADY_EXISTS说明已经有一个实例在运行了这时返回FALSE.
实例
1: 新建一基于对话框的工程ex1,采用默认设置
2: 用GUIDGEN.EXE产生一个全局标志,#define one "产生的全局标志"
本例中产生的语句如下:#define one "0xbe8e2ce1, 0xdab6, 0x11d6, 0xad, 0xd0, 0x0, 0xe0, 0x4c, 0x53, 0xf6, 0xe6"
3: 在应用程序类CEx1App::InitInstance()中,用CreateMutex函数创建一个互斥量,后调用函数GetLastError()
如果结果等于ERROR_ALREADY_EXISTS说明已经有一个实例在运行了这时返回FALSE.
BOOL CEx1App::InitInstance()
{
handle=::CreateMutex(NULL,FALSE,one);//handle为声明的HANDLE类型的全局变量
if(GetLastError()==ERROR_ALREADY_EXISTS)
{
AfxMessageBox("应用程序已经在运行");
return FALSE;
}
}
4:在CEx1App::ExitInstance()中,删除这个互斥量
int CEx1App::ExitInstance()
{
CloseHandle(handle);
return CWinApp::ExitInstance();
}
实现程序只运行一次的方法很多,但是原理都是一样的,就是运行第一次的时候设置一个标记,每次运行的时候检查该标记,如果有就说明已经运行了。
具体实现:
1、在程序初始化的时候 (InitInstance()) 枚举所有的窗口,查找本程序的实例是否存在
2、在主窗口初始化的时候在本窗口的属性列表中添加一个标记,以便程序查找.
部分关键代码
1、在App的InitInstance()中枚举所有窗口,查找本程序实例
01.
HWND
oldHWnd = NULL;
02.
EnumWindows(EnumWndProc,(
LPARAM
)&oldHWnd);
//枚举所有运行的窗口
03.
if
(oldHWnd != NULL)
04.
{
05.
AfxMessageBox(
"本程序已经在运行了"
);
06.
::ShowWindow(oldHWnd,SW_SHOWNORMAL);
//激活找到的前一个程序
07.
::SetForegroundWindow(oldHWnd);
//把它设为前景窗口
08.
return
false
;
//退出本次运行
09.
}
2、添加EnumWndProc窗口过程函数:
01.
//添加的标识只运行一次的属性名
02.
CString g_szPropName =
"Your Prop Name"
;
//自己定义一个属性名
03.
HANDLE
g_hValue = (
HANDLE
)1;
//自己定义一个属性值
04.
05.
BOOL
CALLBACK EnumWndProc(
HWND
hwnd,
LPARAM
lParam)
06.
{
07.
HANDLE
h = GetProp(hwnd,g_szPropName);
08.
if
( h == g_hValue)
09.
{
10.
*(
HWND
*)lParam = hwnd;
11.
return
false
;
12.
}
13.
return
true
;
14.
}
3、在主窗口的 OnInitDialog()中添加属性
1.
//设置窗口属性
2.
SetProp(m_hWnd,g_szPropName,g_hValue);
/
if (::IsIconic(oldHWnd)){//第1种::ShowWindow(oldHWnd, SW_SHOWNORMAL); ::SetWindowPos(oldHWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);::SetWindowPos(oldHWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);//第2种//::ShowWindow(oldHWnd, SW_RESTORE); //激活找到的前一个程序//::SetForegroundWindow( (HWND)(((ULONG) oldHWnd) | 0x01) );//把它设为前景窗口return FALSE;}//第3种//hForeWnd = GetForegroundWindow();//dwCurID = GetCurrentThreadId();//dwForeID = GetWindowThreadProcessId( hForeWnd, NULL );//AttachThreadInput( dwCurID, dwForeID, TRUE);//ShowWindow( oldHWnd, SW_SHOWNORMAL );//SetWindowPos( oldHWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE );//SetWindowPos( oldHWnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE );//SetForegroundWindow( oldHWnd );//AttachThreadInput( dwCurID, dwForeID, FALSE);//第3种解释下 设置当前某窗口为当前窗口,有几个步骤要做:1.得到窗口句柄FindWindow
2.切换键盘输入焦点AttachThreadInput
3.显示窗口ShowWindow(有些窗口被最小化/隐藏了)
4.更改窗口的Zorder,SetWindowPos使之最上,为了不影响后续窗口的Zorder,改完之后,再还原
5.最后SetForegroundWindow//第4种//GetWindowThreadProcessId( oldHWnd, &dwForeID);//AllowSetForegroundWindow(dwForeID);//ShowWindow( oldHWnd, SW_SHOW );//SetForegroundWindow(oldHWnd);//第5种只是一个思路//WM_Self_NOTIFY ,在这儿模拟发出消息::SendMessage(oldHWnd, WM_ICON_NOTIFY, NULL, WM_LBUTTONDOWN);/
Setforegroundwindow 将窗口置最前
windows下简单的调用Setforegroundwindow并不能将窗口置最前,我找到三种方法可以实现该功能。 1、先置topmost,然后取消::ShowWindow(oldHWnd, SW_SHOWNORMAL); ::SetWindowPos(oldHWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE); ::SetWindowPos(oldHWnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);ShowWindow( SW_SHOWNORMAL); SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); SetWindowPos(HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 2、改变系统环境参数这些定义winuser.h里都有的#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000 #define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001 #define SPIF_UPDATEINIFILE 0x0001 #define SPIF_SENDWININICHANGE 0x0002先设置环境变量
DWORD lockTime = 0;
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &lockTime, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0,
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);退出程序时还原环境变量
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, lockTime, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);3、AllowSetForegroundWindowHMODULE hModule = NULL; ASFW_PTR pProcAddress = NULL; hModule = GetModuleHandle("User32");if (hModule != NULL) pProcAddress = (ASFW_PTR)GetProcAddress(hModule, "AllowSetForegroundWindow");if (pProcAddress != NULL) { nResult = (*pProcAddress)(-1);if (nResult == FALSE ) MessageBox(NULL, "Could not set foreground permission", NULL, MB_OK | MB_ICONERROR); }