【问题标题】:How to prevent an application from having multiple instances?如何防止一个应用程序有多个实例?
【发布时间】:2023-03-20 11:03:01
【问题描述】:

目前我正在开发一个 mfc 应用程序,它应该被命名为 setup.exe 并完成。在进入我被击中的地方之前,我会告诉你我所做的。 首先,我必须阻止我的应用程序的多个实例。在初级阶段,我创建了一个事件并检查::getlasterror() setup.exe 是否已经存在,如果 .exe 存在,我正在显示一个消息框。那么,有多少当我运行 exe 时,消息框会重复很多次。 所以,而不是显示那么多的消息框。我有一个想法,如果我的 setup.exe 已经存在,那么把它带到屏幕的前面。所以,我试过这样,它工作得很好。但是这里出现了我的实际问题,即,一旦我安装了一些 Windows setup.exe,它的安装正在进行中,同时我尝试运行我的 setup.exe,然后我将 Windows setup.exe 放在前面,但不是我的应用程序“setup.exe” . 这个其实是我在InitInstance中实现的如下,

BOOL CMyApp::InitInstance()
{
   CWinApp::InitInstance();
   AppIsAllreadyRunning();
   return TRUE;
}

BOOL CMyApp::AppIsAllreadyRunning(BOOL bShow/*=TRUE*/)
{
   BOOL bRunning = FALSE;

   WCHAR szAppName[MAX_PATH] = {0};
  ::wcscpy_s(szAppName, MAX_PATH, theApp.m_pszExeName);
  ::wcscat_s(szAppName, MAX_PATH, L".exe");
   DWORD dwOwnPID = ::GetProcessId(::GetCurrentProcess());
   HANDLE hSnapShot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   PROCESSENTRY32* processInfo = new PROCESSENTRY32;
   processInfo->dwSize = sizeof(PROCESSENTRY32);
   int index = 0;
   while(::Process32Next(hSnapShot, processInfo) != FALSE)
   {
     if(!::wcscmp(processInfo->szExeFile, szAppName))
      {
        if(processInfo->th32ProcessID != dwOwnPID)
        {
            if(bShow)
      ::EnumWindows(ShowAppEnum, processInfo->th32ProcessID);

            bRunning = TRUE;
            break;
        }
     }
  }
    ::CloseHandle(hSnapShot);
    delete processInfo;
    return bRunning;

}

 BOOL CALLBACK ShowAppEnum(HWND hwnd, LPARAM lParam)
{
  DWORD dwID = 0;
  ::GetWindowThreadProcessId(hwnd, &dwID) ;
  if(dwID == (DWORD)lParam)
  {
    if (!::IsWindowVisible(hwnd))
        ::ShowWindow(hwnd,SW_SHOW); 
    ::SetForegroundWindow(hwnd);
  }
  return TRUE;
}

这就是我尝试过的方法。谁能让我知道如何使我的 setup.exe 与其他 setup.exe 不同,当我运行我的 setup.exe 时,它​​应该只出现在前面,正如我在上面首先解释的那样如果我运行不同的 setup.exe 并且正在进行一些安装,同时如果我运行我的 setup.exe,它必须启动,或者如果它已经存在,它必须放在前面。但是不同的 setup.exe已经运行的会弹出到前面(这不应该发生)。

【问题讨论】:

标签: c++ visual-c++ mfc


【解决方案1】:

在 CYourApp.h 中:

extern const CString g_sMutexName;

在 CYourApp.cpp 中:

const CString g_sMutexName = _T("TRA-LA-LA-LA-YOURUNIQUE_ID");


BOOL CYourApp::InitInstance()
{
CWnd* pWnd = CWnd::FindWindow(g_sMutexName, NULL);

if(NULL != pWnd)
{
    // A prevous running instance already created a window with the given class name.
    // Bring it to front then return. 
    pWnd->ShowWindow(SW_SHOWNA);
    if(pWnd->IsIconic())
        pWnd->ShowWindow(SW_RESTORE);
    pWnd->SetForegroundWindow();
    return FALSE;
}

AfxEnableControlContainer();

// Standard initialization
// If you are not using these features and wish to reduce the size
//  of your final executable, you should remove from the following
//  the specific initialization routines you do not need.
 ...

}

在您的 CMainFrame.cpp 中:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if(! CFrameWnd::PreCreateWindow(cs))
    return FALSE;
// TODO: Modify the Window class or styles here by modifying
//  the CREATESTRUCT cs

WNDCLASS wclass;
::ZeroMemory(&wclass, sizeof(WNDCLASS));
wclass.style = CS_DBLCLKS;
wclass.hCursor = ::AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wclass.hIcon = ::AfxGetApp()->LoadIcon(IDR_MAINFRAME);
wclass.lpfnWndProc = ::DefWindowProc;
wclass.lpszClassName = g_sMutexName;
::AfxRegisterClass(&wclass);

cs.lpszClass = g_sMutexName;

return TRUE;
}

当尝试打开您应用的另一个实例时,现有的实例将处于活动状态......

弗拉维。

【讨论】:

  • 我使用的不是 MDI 或 SDI 应用程序的属性表。在你提到的应用程序类中 CWnd* pWnd = CWnd::FindWindow(g_sMutexName, NULL); pWnd 总是返回 null。if 块中的代码根本没有命中。在向导表类中,我添加了 precreatewindow,但它从未被调用。这是一个属性表应用程序。
  • 好的,你那里没有 PreCreateWindow,但你必须在创建窗口之前有一些东西......在那里,你可以将类名设置为互斥体......
  • 从这里检查所有项目:microsoft.com/msj/archive/S252.aspx ... 解压缩它们,然后检查 UNDR0296 项目 ... 表现得如你所愿。 :)
猜你喜欢
  • 2014-02-11
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
  • 2012-02-06
  • 1970-01-01
  • 2016-11-29
相关资源
最近更新 更多