- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我在 stackoverflow 上的第一篇文章。
我不是一个编码员,我有时会为了好玩而涉足编码,因此我不会花太多时间来理解基础知识,而是找到任何可行的解决方案,即使它有点“丑陋” .
这让我想到了我的问题:我用 C 编写了一个简单的 winapi 程序,带有一个对话框和一个 DlgProc。它接受文件并对它们做一些事情,比方说,为了简化,它所做的只是创建一个扩展名为 *.BAK 的文件副本。
我已经在注册表 (HKEY_CLASSES_ROOT*\shell\BKUP\command) 中添加了一个键,这样我就可以在 Windows 资源管理器中选择几个文件,并可以选择“创建备份”来将它们的所有名称发送到我的程序,但是分别为每个文件调用我的程序。所以我用谷歌搜索,做了一些阅读,结果我需要一个叫做 IPC(进程间通信)的东西,阅读了一些选项,WM_COPYDATA 消息看起来像是最简单和最简单的解决方案,所以我使用了它并且它像一个魅力一样工作,但是,有时它只是不......首先我会解释我做了什么:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
COPYDATASTRUCT dsIPC;
hwnd=FindWindow("#32770","Backup program");
if(hwnd)
{
// send "__argv[1]" via SendMessage(hwnd,WM_COPYDATA... etc.
return(0);
}
return DialogBox(hInstance, MAKEINTRESOURCE(ID_DIALOG), NULL, DlgProc);
}
我使用 FindWindow() 检查是否有正在运行的程序实例,如果没有,它会正常运行,如果是,我将文件名发送到 FindWindow() 找到的窗口,然后完全退出该程序实例。
在对话过程中,我有代码用文件名填充一个数组,并使用 SetTimer() 为每个设置一个短计时器,当收到所有文件名时,计时器关闭,我开始复制文件。
同样,所有这一切都很好,但有时会打开程序的两个甚至 3 个实例,并且文件在它们之间拆分,这意味着 FindWindow() 有时无法找到第一个窗口。示例:
我在 Windows 资源管理器中选择 10 个文件,右键单击它们并选择“创建备份”。我的程序打开了 2 个窗口。
第一个窗口输出:
"File 00.DAT" Backed up successfully.
"File 01.DAT" Backed up successfully.
第二个窗口输出:
"File 02.DAT" Backed up successfully.
"File 03.DAT" Backed up successfully.
"File 04.DAT" Backed up successfully.
"File 05.DAT" Backed up successfully.
"File 06.DAT" Backed up successfully.
"File 07.DAT" Backed up successfully.
"File 08.DAT" Backed up successfully.
"File 09.DAT" Backed up successfully.
然后,我关闭 2 个窗口并再次选择相同的 10 个文件并再次选择“创建备份”,但这次和接下来的几次尝试我只得到一个窗口:
第一个窗口输出:
"File 00.DAT" Backed up successfully.
"File 01.DAT" Backed up successfully.
"File 02.DAT" Backed up successfully.
"File 03.DAT" Backed up successfully.
"File 04.DAT" Backed up successfully.
"File 05.DAT" Backed up successfully.
"File 06.DAT" Backed up successfully.
"File 07.DAT" Backed up successfully.
"File 08.DAT" Backed up successfully.
"File 09.DAT" Backed up successfully.
谁能解释为什么会这样?
附言如果重要的话,我正在 Windows 7 x64 上进行测试。
[编辑 - 2017 年 5 月 16 日]这是 zett42 代码的简化版本,它非常适合测试,但在我的待办事项列表中,我写下了阅读和理解 zett42 代码的其余部分,因为我的代码可能在某些方面存在缺陷。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
COPYDATASTRUCT dsIPC;
int i;
DWORD err;
HANDLE hMutex;
hMutex = CreateMutex(NULL, TRUE, "56f0e348-2c1a-4e01-a98e-3e6c8198f9aa");
err = GetLastError();
if(!hMutex)
{
MessageBox(NULL, "Cannot create mutex object. Click OK to exit.", "Error:", MB_OK | MB_ICONSTOP);
return (1);
}
if(err == ERROR_ALREADY_EXISTS)
{
for(i=0 ; i<1000 ; i++)
{
hwnd=FindWindow("#32770","Backup program");
if(hwnd) break;
Sleep(30);
}
if(i==1000) return (1);
dsIPC.dwData=666;
dsIPC.cbData=lstrlen(__argv[1])+1;
dsIPC.lpData=__argv[1];
SendMessage(hwnd, WM_COPYDATA, (WPARAM)hInstance, (LPARAM)&dsIPC);
return(0);
}
return DialogBox(hInstance, MAKEINTRESOURCE(ID_DIALOG), NULL, DlgProc);
}
最佳答案
正如评论者 treintje 所建议的:
There could be a race condition happening where two of your program instances are started at the same time and neither of them had the chance to create a dialog window yet, causing FindWindow to return NULL in both cases. You could prevent this by using a mutex object to check if another instance is already running.
这是一个代码示例,展示了 mutex 是如何实现的。可用于避免竞争条件:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// Try to create a mutex. Replace the string by something globally unique,
// for instance a GUID created by using the GuidGen utility, that comes with
// Visual Studio (look in the "Extras" menu).
HANDLE hMutex = CreateMutexW(nullptr, TRUE, L"REPLACE-WITH-YOUR-GUID");
// Make sure to put no other code in between the CreateMutex() and the
// GetLastError() calls to prevent the last error value from being messed up.
DWORD err = GetLastError();
if(!hMutex)
{
// TODO: error handling
return 1;
}
if(err == ERROR_ALREADY_EXISTS)
{
// An instance of this process is already running, but it might not
// have created the window yet, so FindWindow() could still fail.
// You could call FindWindow() in a loop but that would waste resources.
// So I'm using an event object to wait until the window has been created.
// This event object must be set to "signaled" state in WM_INITDIALOG
// handler of the dialog.
HANDLE hWindowCreatedEvent = CreateEventW(nullptr, TRUE, FALSE,
L"PUT-ANOTHER-GUID-HERE");
if(hWindowCreatedEvent)
{
// Wait with timeout of 30s because the 1st process might have failed
// to create the window for some reason.
DWORD waitRes = WaitForSingleObject(hWindowCreatedEvent, 30 * 1000);
if(waitRes == WAIT_OBJECT_0)
{
// The event is signaled so now we know for sure that the window
// has been created.
HWND hwnd;
COPYDATASTRUCT dsIPC;
hwnd=FindWindow("#32770","Backup program");
if(hwnd)
{
// send "__argv[1]" via SendMessage(hwnd,WM_COPYDATA... etc.
}
}
else
{
// TODO: error handling
}
CloseHandle(hWindowCreatedEvent);
}
else
{
// TODO: error handling
}
}
else
{
// This is the first instance of this process.
return DialogBox(hInstance, MAKEINTRESOURCE(ID_DIALOG), NULL, DlgProc);
}
CloseHandle(hMutex);
}
编辑您的 DialogProc设置事件对象,向进程的其他实例发出窗口已创建的信号:
INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch(uMsg)
{
case WM_INITDIALOG:
{
// Use the same event name as in WinMain()!
HANDLE hWindowCreatedEvent = CreateEventW(nullptr, TRUE, FALSE,
L"PUT-GUID-FROM-WINMAIN-HERE");
if(hWindowCreatedEvent)
{
SetEvent(hWindowCreatedEvent);
CloseHandle(hWindowCreatedEvent);
}
// other initialization code...
return TRUE;
}
}
return FALSE;
}
另一个建议:不要搜索窗口标题,因为“备份程序”是通用的方式,可以被其他应用程序使用。然后,您会将 WM_COPYDATA
发送到错误的进程。
相反,register a window class具有全局唯一名称并仅搜索类名(调用 FindWindow()
并将 NULL 作为 lpWindowName
的参数)。您还必须在对话框模板中指定类名。
关于c - FindWindow() 偶尔失败(尝试 IPC),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43959259/
说真的,你怎么能在不发疯的情况下处理所有这些异常呢?我是不是读了太多关于异常处理的文章或什么?我尝试重构了几次,但每次似乎都以更糟糕的结果告终。也许我应该承认确实会发生异常(exception)情况,
背景 两者 try/rescue和 try/catch是 Elixir 中的错误处理技术。根据 corresponding chapter在介绍指南中。 Errors can be rescued u
每当我尝试在 Raspberry PI 上运行此 python 脚本时,我都会遇到问题: import socket import sys # Create a TCP/IP socket sock
我想知道一些关于 PHP 的 try , catch声明。 让我们考虑以下示例。 abstract class ExceptionA extends Exception {} class Except
我的 laravel v5.4 项目中有两个模型,user 和 admin。 在 config/auth.php 中,我向守卫和提供者添加了管理员,如下所示: 'guards' => [ 'w
try: r = requests.get(url, params={'s': thing}) except requests.ConnectionError, e: print e
我有以下代码。 但是,它并不能捕获所有错误,而我仍然会收到“throw er;//未处理的'错误'事件”。 为什么是这样? app.post('/api/properties/zip/:zip/bed
问题与细节 我正在使用自定义错误处理,遇到的错误之一是“路径中的非法字符”。我有一个自定义函数,旨在通过路径字符串查找此类非法字符,并在找到它们时引发自定义错误。但是我发现,取决于非法字符,Test-
This question already has answers here: How do I catch a numpy warning like it's an exception (not j
我正在使用其他人的代码,但我不熟悉try/catch,因此我举了一个类似的小例子。在第11行上,如果我写了error(''),似乎没有发现错误并增加了索引j。但是,编写error(' ')或error
我在我的一个程序中遇到了这个问题,在这种情况下,尝试/异常(exception)的错误使程序变得更好,以防用户意外输入了他们不应该输入的内容。它仍然给我错误,我为为什么感到困惑。如果对我的问题确实很重
我在尝试TRY ... CATCH块时遇到问题。有人可以解释为什么以下代码无法执行我的sp吗? DECLARE @Result int SET @Result = 0 BEGIN TRY SE
我有一个相当大的 powershell 脚本,其中包含许多(20 多个)执行各种操作的函数。 现在所有代码实际上都没有任何错误处理或重试功能。如果某个特定的任务/功能失败,它就会失败并继续。 我想改进
为什么我尝试时需要导入 inputmismatchException catch(InputMismatchException e){ System.out.println("
我对此感到困惑 - 我为辅助方法编写了一个 try/catch 。它的目的是捕获任何无效输入(任何不是“男性”或“女性”的内容(没有特定情况)。如果输入无效,它将通知用户,然后让他们重试。如果有效,则
我有时会发现自己处于如下场景。尽可能简单地陈述问题 “有时我会创建一段代码,Java 让我将其包含在 try/catch 语句中。我没有使用 catch,所以我将其留空。为什么这是错误的?” boo
我有点困惑为什么当我不使用 Try block 时会出现 Try block 错误。 我在代码块底部附近收到错误通知。如果我不使用 try/catch,有人可以向我解释为什么会发生这种情况吗? 它是否
我已经盯着我的电脑两个小时了,我不知道我做错了什么。谁能帮助我看到光明? package blackjack; import java.util.Random; import java.util.Sc
我想将方法保存在 Enum 中,但 Class.getDeclaredMethod 抛出 NoSuchMethodException,那么我该如何处理呢?我的代码: public enum Car
这个问题已经有答案了: Executing multi-line statements in the one-line command-line (18 个回答) 已关闭 3 年前。 如何使用try.
我是一名优秀的程序员,十分优秀!