- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
最近对 Windows 10 进行的创意者更新破坏了我使用 Win32 API GetWindowLong() 的应用程序代码。
在 Windows 10 Creator Update 之前,即使进程 B(主线程)被阻止,一个进程(比如进程 A)也能够在另一个进程的窗口句柄(比如进程 B)上调用 GetWindowWord()/GetWindowLong() API在某些系统调用中(例如等待释放互斥量)。因此,尽管进程 B 被阻塞,进程 A 仍能够使用这些 API 成功查询进程 B 拥有的窗口的保留内存。
但是,在 Windows 10 上应用 Creator Updates 后,当进程 B(主线程)被阻塞时,进程 A 在属于进程 B 的窗口上调用这些 API 时会被阻塞。
我通过创建 2 个代表进程 A 和进程 B 的独立 Win32 应用程序来模拟这种情况。在应用了创意者更新的 Windows 10 系统上,进程 A 在属于的窗口上调用 GetWindowLong()/GetWindowWord() 时挂起当进程 B(主线程)正在等待互斥锁时,进程 B。换句话说,对 GetWindowLong()/GetWindowWord() 的调用从未返回,从而导致进程 A 挂起。
但是,当我在没有 Creators Update 或更早版本(例如 Windows 7)的 Windows 10 系统上使用我的独立应用程序测试相同的场景时,对进程 A 中的 GetWindowLong()/GetWindowWord() API 的调用返回即使进程 B 正在等待释放互斥锁,也能成功。
为了演示上述问题,这里是进程 A 和进程 B 的代码。要查看问题,请运行进程 A 和进程 B。然后,找出进程 B 窗口的窗口句柄(例如使用 Spy++),然后将其粘贴到进程 A 窗口的编辑字段中。然后单击“确定”。显示在进程 B 的窗口的额外内存(使用 SetWindowLong())中设置的 LONG 值的消息框。到目前为止,一切都很好。现在,转到进程 B 的窗口并通过单击“阻止”按钮使其挂起。这将使进程“B”(主 GUI 线程)等待一个永远不会被释放的互斥量,因此进程 B 将挂起。
现在,返回进程 A 的窗口并再次单击“确定”(假设编辑字段仍然具有您之前粘贴的进程 B 的相同窗口句柄)。
现在,这是行为上的差异:
在没有 Creators Update 的 Windows 10 和早期的 Windows 版本(例如 Windows 7)上,和以前一样(即当进程 B 没有挂起时),一个消息框显示在进程 B 的窗口的额外内存中设置的 LONG 值(使用 SetWindowLong ()) 显示。
在带有创意者更新的 Windows 10 上,进程 A 挂起,因为使用进程 B 的窗口句柄对 SetWindowLong() 的调用永远不会返回,从而导致进程 A 挂起。
请建议我如何解决 Windows 10 Creators Update 上的这种行为变化,以便我的应用程序不会挂起。任何想法/帮助将不胜感激。
这是进程 A 的代码。
/* Process A */
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
int count = 0;
int count1 = 0;
TCHAR str[1000];
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
HWND g_hwndEdit, g_hwndButton;
#define ID_EDIT (3456)
#define ID_OK (3457)
TCHAR szWinName[] = TEXT("MyWin");
HINSTANCE g_hInst = NULL;
int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR lpszArgs,int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wcl;
g_hInst = hThisInst;
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.hInstance = hThisInst;
wcl.lpszClassName = szWinName;
wcl.lpfnWndProc = WindowFunc;
wcl.style = CS_HREDRAW|CS_VREDRAW;
wcl.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wcl.hIconSm = NULL;
wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 44;
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
if(!RegisterClassEx(&wcl)) return 0;
hwnd = CreateWindowEx(
WS_EX_WINDOWEDGE,
szWinName,
"Process A",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
NULL,
hThisInst,
NULL
);
ShowWindow(hwnd,nWinMode);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
LONG l;
HWND hwndOther = hwnd;
char s[] = "Paste the window handle (in HEX) of Process B's window on which you wish to call GetWindowLong() in the edit field and click on OK.";
HDC hdc;
PAINTSTRUCT ps;
static int cxClient = 0, cyClient = 0;
char btnText[1001];
switch(message){
case WM_CREATE:
g_hwndEdit = CreateWindow ("edit", NULL,
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
WS_BORDER | ES_LEFT,
200, 200, 200, 200, hwnd, (HMENU)ID_EDIT,
g_hInst, NULL) ;
g_hwndButton = CreateWindow(
"Button",
"OK",
WS_CHILD|WS_VISIBLE,
500,
200,
150,
50,
hwnd,
(HMENU)ID_OK,
g_hInst,
NULL
);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 100, s, strlen(s));
EndPaint(hwnd, &ps);
return 0;
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == ID_OK)
{
GetWindowText(g_hwndEdit, btnText, 1000);
sscanf(btnText, "%x", &hwndOther);
l = GetWindowLong(hwndOther, 24);
sprintf(str, "The LONG value at offset 24 of the window with handle 0x%x is %d.", hwndOther, l);
MessageBox(hwnd, str, "", 0);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
这是进程 B 的代码:
/* Process B */
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
int count = 0;
int count1 = 0;
TCHAR str[1000];
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
TCHAR szWinName[] = TEXT("MyWin");
HINSTANCE g_hInst = NULL;
HANDLE g_hThread, g_hMutex;
HWND g_hwndButton;
#define ID_BUTTON (3456)
//worker thread fn
DWORD WINAPI ThreadFunc(LPVOID p)
{
g_hMutex = CreateMutex(NULL, TRUE, "HELLO_MUTEX");
// this worker thread now owns the above created mutex and goes into an infinite loop so that
// the mutex is never released
while (1){}
return 0;
}
// main (GUI) thread
int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR lpszArgs,int nWinMode)
{
HANDLE hThread;
DWORD threadld;
// create a worker thread that will create a mutex and then will go into an infinite loop making sure that the mutex is never released
// and thus when the main (GUI) thread calls WaitForSingleObject() on this mutex handle, it is going to block forever.
hThread = CreateThread(NULL,
0,
ThreadFunc,
0,
0,
&threadld);
// make the main (GUI) thread sleep for 5 secs so that by the time it wakes up, the worker thread will have created the mutex and gone into an infinite loop
Sleep(5000);
HWND hwnd;
MSG msg;
WNDCLASSEX wcl;
g_hInst = hThisInst;
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.hInstance = hThisInst;
wcl.lpszClassName = szWinName;
wcl.lpfnWndProc = WindowFunc;
wcl.style = CS_HREDRAW|CS_VREDRAW;
wcl.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wcl.hIconSm = NULL;
wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 44;
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
if(!RegisterClassEx(&wcl)) return 0;
hwnd = CreateWindowEx(
WS_EX_WINDOWEDGE,
szWinName,
"Process B",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
NULL,
hThisInst,
NULL
);
SetWindowLong(hwnd, 24, 135678);
ShowWindow(hwnd,nWinMode);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
char strr[1000];
char s[] = "Click on the \"Block\" button below to make the main (GUI) thread block by waiting on a mutex forever since the mutex will never be released.";
HWND hwndOther = hwnd;
HDC hdc;
PAINTSTRUCT ps;
static int cxClient = 0, cyClient = 0;
switch(message){
case WM_CREATE:
sprintf(strr, "Window created - handle is %x.\n", hwnd);
OutputDebugString(strr);
g_hwndButton = CreateWindow(
"Button",
"Block",
WS_CHILD|WS_VISIBLE,
10,
120,
50,
50,
hwnd,
(HMENU)ID_BUTTON,
g_hInst,
NULL
);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 100, s, strlen(s));
EndPaint(hwnd, &ps);
return 0;
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == ID_BUTTON)
{
MessageBox(hwnd, "Main (GUI) Thread going in blocking state by waiting for mutex forever now", "", 0);
WaitForSingleObject(g_hMutex, INFINITE);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
最佳答案
我想我找到了在进程 B 中使用 MsgWaitForMultipleObjects() 的解决方案,这样它除了等待互斥锁之外,还会继续在队列中寻找消息。这样,进程A对进程B的窗口句柄的GetWindowLong()调用将正常返回,不会阻塞,问题就解决了。
这是进程 B 的更新代码,更改是在“阻止”按钮单击处理 WM_COMMAND 情况下(进程 A 代码保持不变):
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
int count = 0;
int count1 = 0;
TCHAR str[1000];
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
TCHAR szWinName[] = TEXT("MyWin");
HINSTANCE g_hInst = NULL;
HANDLE g_hThread, g_hMutex;
HWND g_hwndButton;
#define ID_BUTTON (3456)
//worker thread fn
DWORD WINAPI ThreadFunc(LPVOID p)
{
g_hMutex = CreateMutex(NULL, TRUE, "HELLO_MUTEX");
// this worker thread now owns the above created mutex and goes into an infinite loop so that
// the mutex is never released
while (1){}
return 0;
}
// main (GUI) thread
int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR lpszArgs,int nWinMode)
{
HANDLE hThread;
DWORD threadld;
// create a worker thread that will create a mutex and then will go into an infinite loop making sure that the mutex is never released
// and thus when the main (GUI) thread calls WaitForSingleObject() on this mutex handle, it is going to block forever.
hThread = CreateThread(NULL,
0,
ThreadFunc,
0,
0,
&threadld);
// make the main (GUI) thread sleep for 5 secs so that by the time it wakes up, the worker thread will have created the mutex and gone into an infinite loop
Sleep(5000);
HWND hwnd;
MSG msg;
WNDCLASSEX wcl;
g_hInst = hThisInst;
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.hInstance = hThisInst;
wcl.lpszClassName = szWinName;
wcl.lpfnWndProc = WindowFunc;
wcl.style = CS_HREDRAW|CS_VREDRAW;
wcl.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wcl.hIconSm = NULL;
wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 44;
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
if(!RegisterClassEx(&wcl)) return 0;
hwnd = CreateWindowEx(
WS_EX_WINDOWEDGE,
szWinName,
"Process B",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
NULL,
hThisInst,
NULL
);
SetWindowLong(hwnd, 24, 135678);
ShowWindow(hwnd,nWinMode);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
BOOL waitWithMessageLoop(HANDLE hMutex, BOOL &bExit)
{
BOOL bContinue = TRUE;
bExit = FALSE;
while(bContinue)
{
DWORD dwReturn = ::MsgWaitForMultipleObjects(1, &hMutex, FALSE, INFINITE, QS_ALLINPUT);
if(dwReturn == WAIT_OBJECT_0)
{
// our mutex got released
bContinue = FALSE;
}
else if(dwReturn == WAIT_OBJECT_0 + 1)
{
MSG msg;
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
bExit = TRUE;
bContinue = FALSE;
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
else
{
// MsgWaitForMultipleObjects() returned error
return FALSE;
}
}
return TRUE;
}
LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
char strr[1000];
char s[] = "Click on the \"Block\" button below to make the main (GUI) thread block by waiting on a mutex forever since the mutex will never be released.";
HWND hwndOther = hwnd;
HDC hdc;
PAINTSTRUCT ps;
static int cxClient = 0, cyClient = 0;
switch(message){
case WM_CREATE:
sprintf(strr, "Window created - handle is %x.\n", hwnd);
OutputDebugString(strr);
g_hwndButton = CreateWindow(
"Button",
"Block",
WS_CHILD|WS_VISIBLE,
10,
120,
50,
50,
hwnd,
(HMENU)ID_BUTTON,
g_hInst,
NULL
);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 10, 100, s, strlen(s));
EndPaint(hwnd, &ps);
return 0;
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == ID_BUTTON)
{
MessageBox(hwnd, "Main (GUI) Thread going in blocking state by waiting for mutex forever now", "", 0);
// disable the "Block" button
EnableWindow(g_hwndButton, FALSE);
//WaitForSingleObject(g_hMutex, INFINITE);// do NOT use this as this cause the GetWindowLong() call made in Process A to hang
BOOL bExit = FALSE;
waitWithMessageLoop(g_hMutex, bExit);
if (bExit)
{
PostQuitMessage(0);
}
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
谢谢,--阿努拉格。
关于windows - GetWindowLong() - Creators Update 引入的行为变化破坏了我的 win32 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43562901/
嘿伙计们。 实现背景变化(基本上是幻灯片放映)和过渡效果的常见方法有哪些。我想每隔一段时间改变complte文档背景。 我是一名 ASP.net 开发人员,并且希望大部分内容都可以在 ASP 中实现。
也许,指针已经在修改过程中指向 auto_ptr 的常规指针指向 unique_ptr 和 shared_ptr 我只是想知道已经开发出来的新型指针是否完全覆盖了旧版本(或者您可能认为存在内存泄漏问题
我使用 Android Studio 构建 Android 应用。 我的问题是:当 fragment 改变时,应用程序崩溃。 控制台输出[控制台] 01-06 18:35:21.952 27756-
****澄清**我做了这个 [Fiddle] ( http://jsfiddle.net/sggPv/10/ ) 来帮助澄清情况。 该脚本起初适用于两个表格,但随后当您点击 slider 并将新表格加
我有图标,单击它会将新的 div(列)添加到 div 容器。问题是,当新的 div(列)出现时,按钮不会向右移动。是否可以以某种方式仅在 div 内添加 position:fixed? 这是我的几个屏
我是 Java 新手,继承了现有的 Android 应用程序。原始开发人员选择使用常量接口(interface)。 我的问题是我需要更改其中一些常量来编译生产应用程序与开发应用程序。如果我手动修改一些
在 Apple developer Document 中,我在 UIColor 中发现了一些新东西。 If your app was linked on or after iOS 10 and whe
我没有经常使用 ShareKit,但我只想拥有三个共享选项:Facebook、Twitter 和电子邮件。 ShareKit 提供了更多选项,包括更多按钮。但是,我不想要“更多”选项,只想要三个。 在
我正在构建一个 JS 库,其中一个用例要求我在 DOM 更改时触发一个事件,特别是如果它是一个单页应用程序,例如:github search bar 经过一番研究,我遇到了MutationObserv
我已经设法编写了一个代码来检测任何工作表中特定单元格的值变化,但我一直在努力构建检测和跟踪范围(值)变化的东西。 例如,如果用户决定复制和粘贴某个范围的数据(假设超过 1 个单元格),它不会被宏捕获。
使用 ffmpeg ,我们可以对音频电平进行多少控制?例如,我想在程序的时间轴上映射一个“M”形: t0 - t1 : fade in from 0 to 1 t1 - t2 : play at fu
使用 jQuery 1.7.1,我尝试为下拉列表上的更改事件创建一个事件处理程序。下拉列表会动态添加到 DOM 中。似乎在大多数浏览器上都能很好地工作,但是哦,奇怪的 IE8 想要变得困难。有解决方法
我想制作一个具有可选边框大小的自定义控件。请参阅下面的代码。边框绘制在非客户区,其宽度可以是 0、1 或 2 像素。我已经在 WM_NCPAINT 中成功完成了边框绘制。问题是,在更改控制边框大小的属
我知道这个问题之前已经被问过,而且我实际上已经找到了一些我已经实现的解决方案。不幸的是,我没能得到我想要的。 我以前没有做过AngularJS,我想做的是: 检测网址何时更改 根据网址更改的内容进行一
我有一个 auto-carousel 指令,它循环访问链接元素的子元素。 但是,子级尚未加载到 DOM 中,因为它们的 ng-if 表达式尚未解析。 如何确保父指令知道其 DOM 树已发生更改?
我有一个流程可以通过内容提供商从数据库中获取数据。 fun getDataFlow(): Flow { return flow { emit(Result.Loading)
我有一些有效的代码,但有时它只是“跳转”到其他文本而不考虑间隔。 该代码基本上按时间间隔更改标题的文本。 var text = ["text1", "text2", "text3","text4","
我正在尝试将 onCLick 监听器添加到我的 PreferenceScreen 上的开关,但它不起作用。我尝试了 Java 教程中的代码并将其转换为 Kotlin,但由于某种原因它无法正常工作。 这
我们目前正在尝试升级我们的程序使用的 ffmpeg 版本。跳跃很大,因为我们目前使用的是 ffmpeg 0.8,最新版本是 1.2。 在这些测试中,我使用的是(让我说)我发现的令人惊叹的软件包 her
我有一个流程可以通过内容提供商从数据库中获取数据。 fun getDataFlow(): Flow { return flow { emit(Result.Loading)
我是一名优秀的程序员,十分优秀!