检测哪个 window 在其他实例中具有焦点,并且 post 带有 CString 参数的消息
Detect which window has focus in other instance and post a message with a CString parameter to it
我有在 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);
}
另一个处理程序以类似的方式工作。代码实现没有问题,用户可以双击一个文件,它会在软件中用正确的编辑器打开。
当然,如果我的软件已经是 运行(但仅在主对话框中)并且用户双击一个文件,则会触发复制实例,它只会将 window 带到前景。
我想做的是:
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的另一个实例有模态window了。所以 SendMessageTimeout
永远不会真正超时。
知道了!
if (GetLastActivePopup() != this)
这是我目前所拥有的...
一旦我确定另一个实例已经 运行ning,并且在命令行上提供了一个文件,我就会 运行 在取消重复实例之前使用此方法:
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;
}
我正在尝试按照 here but could not get it to work — Got it to work and code is shown 所述调整 CopyData
方法。
我有在 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);
}
另一个处理程序以类似的方式工作。代码实现没有问题,用户可以双击一个文件,它会在软件中用正确的编辑器打开。
当然,如果我的软件已经是 运行(但仅在主对话框中)并且用户双击一个文件,则会触发复制实例,它只会将 window 带到前景。
我想做的是:
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的另一个实例有模态window了。所以 SendMessageTimeout
永远不会真正超时。
知道了!
if (GetLastActivePopup() != this)
这是我目前所拥有的...
一旦我确定另一个实例已经 运行ning,并且在命令行上提供了一个文件,我就会 运行 在取消重复实例之前使用此方法:
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;
}
我正在尝试按照 here but could not get it to work — Got it to work and code is shown CopyData
方法。