windows – GetWindowLong() – 使用Creators Update引入的行为
|
最近对
Windows 10进行的Creator更新破坏了我使用Win32 API GetWindowLong()的应用程序代码.
在Windows 10 Creator Update之前,一个进程(比如进程A)能够在另一个进程的窗口句柄(比如进程B)上调用GetWindowWord()/ GetWindowLong()API,即使在某些系统中阻止了进程B(主线程)调用(例如等待释放互斥锁).因此,尽管进程B被阻止,但进程A能够成功地使用这些API查询进程B拥有的窗口的保留内存. 但是,在Windows 10上应用创建者更新时,当进程B(主线程)被阻止时,进程A在属于进程B的窗口上调用这些API时会被阻止. 我通过创建2个代表进程A和进程B的独立Win32应用程序来模拟这种情况.在应用了创建者更新的Windows 10系统上,进程A在属于进程B的窗口上调用GetWindowLong()/ GetWindowWord()时挂起进程B(主线程)正在等待互斥锁.换句话说,对GetWindowLong()/ GetWindowWord()的调用从未返回,从而使进程A挂起. 但是,当我在没有Creators Update或早期版本(如Windows 7)的Windows 10系统上使用我的独立应用程序测试相同的场景时,对进程A中的GetWindowLong()/ GetWindowWord()API的调用成功返回进程B正在等待一个互斥锁被释放. 为了演示上述问题,这里是进程A和进程B的代码. 现在,返回进程A的窗口并再次单击OK(假设编辑字段仍然具有您之前粘贴的进程B的窗口句柄). 现在,这是行为上的差异: 在Windows 10上没有创建者更新和早期的Windows版本(如Windows 7),就像以前一样(即进程B没有挂起),一个消息框显示在进程B的窗口的额外内存中设置的LONG值(使用SetWindowLong())显示. 在带有Creators Update的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,HWND_DESKTOP,NULL,hThisInst,NULL
);
ShowWindow(hwnd,nWinMode);
UpdateWindow(hwnd);
while(GetMessage(&msg,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",WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
WS_BORDER | ES_LEFT,200,hwnd,(HMENU)ID_EDIT,g_hInst,NULL) ;
g_hwndButton = CreateWindow(
"Button","OK",WS_CHILD|WS_VISIBLE,500,150,50,(HMENU)ID_OK,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,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,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,ThreadFunc,&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,"Process B",NULL
);
SetWindowLong(hwnd,24,135678);
ShowWindow(hwnd,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",120,(HMENU)ID_BUTTON,&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,lParam);
}
解决方法
我想我找到了在进程B中使用MsgWaitForMultipleObjects()的解决方案,这样除了等待互斥锁之外,它还一直在队列中查找消息.
通过这样做,进程B的窗口句柄上的进程A中的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,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,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,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,lParam);
}
谢谢,–ANURAG. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 使用Windows脚本更改进程的亲和力
- OpenProcess:仅在Windows 8.1上访问被拒绝错误
- .net – Windows Server 2008上的最大tcp / ip连接
- Windows+MyEclipse+MySQL【连接数据库报错caching_sha2_pas
- uwp – 如何使用Universal Windows App中的System.Net.Http
- 在Windows 8,python 3.3中创建虚拟环境的麻烦
- 如何在Windows中打开文件而不阻止其重命名
- windows – 设置iis的语言
- windows – 将“Everyone”组添加到目录及其所有子目录中
- powershell – System.Net.Webclient仅下载81.4 MB(85,363,
