MFC-只运行一个实例

方法一:创建互斥体 Mutex 法 

代码要加在主线程的InitInstance函数中[APP的InitInstance函数中]

 

 代码要放在窗口显示之前

 

复制代码
    // 例如修改为公司或组织名
    SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

    HANDLE m_hMutex = ::CreateMutex(NULL, FALSE, _T("{A2224701-B9F8-4AC4-BBD0-8B81D56B2E00}"));
    //参数3:互斥锁对象的名称   
    //可以用GUID  工具->创建GUID
    //就是利用参数3来判断程序是否已经打开一个:当第二次打开时,由于参数3重名,
    //会返回错误信息GetLastError() == ERROR_ALREADY_EXISTS=183=当文件已存在时,无法创建该文件
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        AfxMessageBox(_T("已经有一个实例正在运行中……"));
        CloseHandle(m_hMutex);
        //虽然返回ERROR_ALREADY_EXISTS=183错误信息,但是互斥锁对象还是创建成功的,所以需要关闭
        m_hMutex = NULL;
        return FALSE;
    }



    CyigesiliDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
复制代码

 

复制代码
else if (nResponse == IDCANCEL)
    {
        // TODO: 在此放置处理何时用
        //  “取消”来关闭对话框的代码

        //关闭对话框时,关闭互斥锁对象
        if (m_hMutex) {
            CloseHandle(m_hMutex);
            m_hMutex = NULL;
        }
        

    }
复制代码

实例工程下载:

链接:https://pan.baidu.com/s/1JKTIIqCG-3XjjKP75pV7Lw
提取码:6666

这种方法的缺点:第二次想打开程序时,第一次窗口在后台,没有置顶

 

方法二:FindWindow窗口查找法

通过 FindWindow 进行窗口的查找,若发现则说明已经运行过一个实例,并将其窗口激活 

注意:代码添加位置与方法一相同

复制代码
    // 例如修改为公司或组织名
    SetRegistryKey(_T("应用程序向导生成的本地应用程序"));


    HWND hWnd = ::FindWindow(_T("#32770"), _T("DlgTest"));
    //MFC对话框默认类名是#32770
    if (hWnd != NULL) {
        AfxMessageBox(_T("已经有一个实例正在运行中……"));
        ::ShowWindow(hWnd, SW_NORMAL);
        ::SetForegroundWindow(hWnd);
        return FALSE;
    }





    Cyigesili1Dlg dlg;
    m_pMainWnd = &dlg;
复制代码

此种方法不是很好,如果窗口标题改变了或者每个窗口实例的标题不一样,就找不到了!

 

方法三:设置窗口属性-推荐

复制代码
// yigesili1Dlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "yigesili1.h"
#include "yigesili1Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// Cyigesili1Dlg 对话框



Cyigesili1Dlg::Cyigesili1Dlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_YIGESILI1_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void Cyigesili1Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(Cyigesili1Dlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_DESTROY()
END_MESSAGE_MAP()


//加入全局变量的定义及枚举窗口函数:
TCHAR g_szPropName[] = _T("{0736D43A-ACCD-4C43-8CFB-0D83E11E795C}");//要增加的属性
//尽量采用GUID,防止重合
HANDLE g_hValue = (HANDLE)19680104;//属性数据
//可以任意数据强转成HANDLE

BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam) //枚举窗口的回调函数
{
    HANDLE hProp = GetProp(hwnd, g_szPropName);
    if (hProp == g_hValue) {
        *(HWND*)lParam = hwnd;
        return FALSE;
    }
    return TRUE;
}

// Cyigesili1Dlg 消息处理程序

BOOL Cyigesili1Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 在此添加额外的初始化代码
    HWND hPreWnd = NULL;
    ::EnumWindows(EnumWndProc, (LPARAM)&hPreWnd);//枚举顶层窗口

    if (hPreWnd != NULL) {  //如果找到窗口
        AfxMessageBox(_T("已经有一个实例正在运行中……"));
        ::ShowWindow(hPreWnd, SW_NORMAL);
        ::SetForegroundWindow(hPreWnd);
        ExitProcess(0);
        return FALSE;
    }
    ::SetProp(m_hWnd, g_szPropName, g_hValue);//给指定窗口增加或修改一个属性
    





    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void Cyigesili1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void Cyigesili1Dlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR Cyigesili1Dlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}



void Cyigesili1Dlg::OnDestroy()
{
    CDialogEx::OnDestroy();

    // TODO: 在此处添加消息处理程序代码

    ::RemoveProp(m_hWnd, g_szPropName);//删除窗口属性



}
复制代码

注意:代码分3部分

实例工程下载:

链接:https://pan.baidu.com/s/1y10BrS3e9hXVTVqc8ukuYw
提取码:6666

 

方法四:使用全局共享变量的共享节法-推荐

复制代码
// duoxiancen2Dlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "duoxiancen2.h"
#include "duoxiancen2Dlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_ABOUTBOX };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// Cduoxiancen2Dlg 对话框



Cduoxiancen2Dlg::Cduoxiancen2Dlg(CWnd* pParent /*=nullptr*/)
    : CDialogEx(IDD_DUOXIANCEN2_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void Cduoxiancen2Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(Cduoxiancen2Dlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON1, &Cduoxiancen2Dlg::OnBnClickedButton1)
END_MESSAGE_MAP()


//新建共享节
#pragma data_seg("Shared")   
HWND hPreWnd = NULL;
#pragma data_seg()
#pragma comment(linker, "/Section:Shared,RWS") 
//多个进程之间可共享数据


// Cduoxiancen2Dlg 消息处理程序

BOOL Cduoxiancen2Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != nullptr)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 在此添加额外的初始化代码


    if (hPreWnd == NULL) {
        hPreWnd = m_hWnd;
    }
    else {
        AfxMessageBox(_T("已经有一个实例正在运行中……"));
        ::ShowWindow(hPreWnd, SW_NORMAL);
        ::SetForegroundWindow(hPreWnd);
        ExitProcess(0);
        return FALSE;
    }




    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void Cduoxiancen2Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void Cduoxiancen2Dlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // 用于绘制的设备上下文

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // 使图标在工作区矩形中居中
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // 绘制图标
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR Cduoxiancen2Dlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}



void Cduoxiancen2Dlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码






}
复制代码

实例工程下载:

链接:https://pan.baidu.com/s/1sQV4qdeON9azfCZl4vS2vw
提取码:6666

 

 

 

 

 

 

 

 

 

 

 

posted @   天子骄龙  阅读(386)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
历史上的今天:
2022-04-07 浩辰CAD-退出全屏
2022-04-07 浩辰CAD-构造线
2021-04-07 AutoCAD-平移
2021-04-07 AutoCAD-放大镜
2021-04-07 AutoCAD--单位设置
2020-04-07 python-pyStrich条形码模块
2019-04-07 python-函数
点击右上角即可分享
微信分享提示

目录导航