检测哪个窗口在其他实例中具有焦点,并向其发布带有CString参数的消息

问题描述 投票:0回答:1

我有在InitInstance中执行的代码,该代码检查我的应用程序是否已在运行,如果运行,则将其置于前台。标准代码:

if (m_hMutex != nullptr)
{   // indicates running instance
    if (::GetLastError() == ERROR_ALREADY_EXISTS)
    {
        EnumWindows(searcher, (LPARAM)&hOther);

        if (hOther != nullptr)
        {
            ::SetForegroundWindow(::GetLastActivePopup(hOther));

            if (IsIconic(hOther))
            {
                ::ShowWindow(hOther, SW_RESTORE);
            }
        }

        return FALSE; // terminates the creation
    }
}

上面我没有问题。最近,我增加了对从文件资源管理器中双击文件的支持,该文件在我的软件CDialog中打开)。因此,我在InitInstance中执行以下操作:

CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (PathFileExists(cmdInfo.m_strFileName))
{
    m_bOpenFileFromFileExplorer = true;
    m_strFileToOpenFromFileExplorerPath = cmdInfo.m_strFileName;
}

然后,在我的主对话框OnInitDialog中,我这样做:

if (theApp.OpenFileFromFileExplorer())
{
    CString strFileToOpen = theApp.GetFileToOpenFromFileExplorerPath();
    CString strFileExtension = PathFindExtension(strFileToOpen);

    strFileExtension.MakeLower();
    if (strFileExtension == _T(".srr"))
        PostMessage(WM_COMMAND, ID_FILE_OPENREPORT);
    else if (strFileExtension == _T(".mwb"))
        PostMessage(WM_COMMAND, ID_FILE_OPEN_CHRISTIAN_LIFE_AND_MINISTRY_REPORT);
}

最后,我每个编辑器的每个处理程序都执行以下操作:

void CMeetingScheduleAssistantDlg::OnFileOpenReport()
{
    CCreateReportDlg dlgReport(this);
    CString          strFilePath, strFileName;

    if (theApp.OpenFileFromFileExplorer())
    {
        strFilePath = theApp.GetFileToOpenFromFileExplorerPath();
        strFileName = PathFindFileName(strFilePath);
        if (strFilePath == _T("") || strFileName == _T(""))
        {
            // Error!
            return;
        }
    }
    else
    {
        CString strTitle, strFilter;

        strTitle.LoadString(IDS_STR_SELECT_SRR_FILE);
        strFilter.LoadString(IDS_STR_SRR_FILTER);

        CFileDialog dlgOpen(TRUE, _T(".SRR"),
            nullptr, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, strFilter, this);

        dlgOpen.m_ofn.lpstrTitle = strTitle;

        // get a file to open from user
        if (dlgOpen.DoModal() != IDOK)
            return;

        strFilePath = dlgOpen.GetPathName();
        strFileName = dlgOpen.GetFileName();
    }

    // AJT V9.1.0 - Most Recent File List support
    theApp.AddToRecentFileList(strFilePath);

    // tell report we want to open it
    dlgReport.SetFileToOpen(strFilePath, strFileName);

    // display it
    dlgReport.DoModal();

    // AJT V9.1.0 Bug Fix
    SetDayStates(m_calStart);
    SetDayStates(m_calEnd);
}

另一个处理程序的工作方式与此类似。所实现的代码没有问题,用户可以双击一个文件,该文件将通过正确的编辑器在软件中打开。

当然,如果我的软件已经在运行(但仅在主对话框中运行),并且用户双击文件,则将触发重复的实例,并将该窗口置于前台。

我想做的是这个:

Is the duplicate instance on the primary window?
    Bring it to the foreground.
    Trigger to open this file the user has double in this attempted instance.
    Shutdown this instance.
Else
    Bring it to the foreground.
    Not much else we can do since a modal window is open in the other instance.
    So just shut down.
End if

所以我该怎么做:

Is the duplicate instance on the primary window?
    Bring it to the foreground.
    Trigger to open this file the user has double in this attempted instance.
    Shutdown this instance.
Else

更新

问题是:

HWND hOther = nullptr;
if (DetectRunningInstance(hOther))
{
    DetectFileToOpenFromFileExplorer(); // AJT v20.1.6

    CString strFile = GetFileToOpenFromFileExplorerPath();

    LPCTSTR lpszString = strFile.GetBufferSetLength(_MAX_PATH);
    COPYDATASTRUCT cds;
    cds.dwData = 1;
    cds.cbData = _MAX_PATH;
    cds.lpData = (LPVOID)lpszString;

    DWORD dwResult;
    SendMessageTimeout(hOther, WM_COPYDATA,
            NULL, (LPARAM)(LPVOID)&cds, SMTO_BLOCK, 2000, &dwResult);
    strFile.ReleaseBuffer();


    return FALSE; // Terminates the creation
}

...
...

BOOL CMeetingScheduleAssistantDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
    if (pCopyDataStruct->dwData == nnn)
    {
        LPCTSTR lpszString = (LPCTSTR)(pCopyDataStruct->lpData);
        AfxMessageBox(lpszString);
    }

    return TRUE;
}

即使MSA的另一个实例的模式窗口向上,上述内容也会传递字符串。因此SendMessageTimeout从不实际超时。

知道!

if (GetLastActivePopup() != this)
c++ mfc instance
1个回答
0
投票

这是我到目前为止所拥有的...

一旦确定另一个实例已经在运行,并且在命令行上提供了一个文件,然后在取消重复的实例之前运行此方法:

void CMeetingScheduleAssistantApp::TryToOpenFileInOtherInstance(HWND hOtherInstance)
{
    CString strFile = GetFileToOpenFromFileExplorerPath();

    LPCTSTR lpszString = strFile.GetBufferSetLength(_MAX_PATH);
    COPYDATASTRUCT cds;
    cds.dwData = xxxxx;
    cds.cbData = _MAX_PATH;
    cds.lpData = (LPVOID)lpszString;

    DWORD_PTR dwResult;
    if (SendMessageTimeout(hOtherInstance, WM_COPYDATA,
                    NULL, (LPARAM)(LPVOID)&cds, SMTO_BLOCK, 2000, &dwResult) != 0)
    {
        // The message was sent and processed
        if (dwResult == FALSE)
        {
            // The other instance returned FALSE. This is probably because it
            // has a pop-up window open so can't open the file
            ::OutputDebugString(_T("InitInstance::SendMessageTimeout [dwResult was FALSE].\n"));
        }
    }
    else
    {
        DWORD dwError = ::GetLastError();
        if (dwError == ERROR_TIMEOUT)
        {
            // The message timed out for some reason
            ::OutputDebugString(_T("InitInstance::SendMessageTimeout [ERROR_TIMEOUT].\n"));
        }
        else
        {
            // Another unknown error
        }
        CString strError = _T("");
        strError.Format(_T("InitInstance::SendMessageTimeout [%d: %s]\n"), dwError, GetLastErrorAsStringEx(dwError));

        ::OutputDebugString(strError);
    }
    strFile.ReleaseBuffer();
}

WM_COPYDATA消息处理程序中:

BOOL CMeetingScheduleAssistantDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
    if (pCopyDataStruct->dwData == xxx)
    {
        LPCTSTR lpszString = (LPCTSTR)(pCopyDataStruct->lpData);
        {
            if (GetLastActivePopup() != this) // Popup windows!
            {
                // TODO: Tell user?
                return FALSE;
            }

            theApp.SetFileToOpenFromFileExplorer(lpszString);

            OpenFileFromFileExplorer();
        }
    }

    return TRUE;
}

我正在尝试像CopyData所述适应here方法,但无法使其起作用。

© www.soinside.com 2019 - 2024. All rights reserved.