Windows GetWindowLong()-Creators Update引入的行为变化会破坏我的win32应用程序

Windows GetWindowLong()-Creators Update引入的行为变化会破坏我的win32应用程序,windows,winapi,visual-c++,Windows,Winapi,Visual C++,最近Creators对Windows 10的更新破坏了我使用Win32 API GetWindowLong()的应用程序代码 在Windows10Creator更新之前,一个进程(比如进程A)能够在另一个进程的窗口句柄(比如进程B)上调用GetWindowWord()/GetWindowLong()API,即使进程B(主线程)在某些系统调用中被阻塞(例如等待释放互斥锁)。因此,进程A能够使用这些API成功地查询进程B拥有的窗口的保留内存,尽管进程B被阻塞 但是,在Windows 10上应用了Cr

最近Creators对Windows 10的更新破坏了我使用Win32 API GetWindowLong()的应用程序代码

在Windows10Creator更新之前,一个进程(比如进程A)能够在另一个进程的窗口句柄(比如进程B)上调用GetWindowWord()/GetWindowLong()API,即使进程B(主线程)在某些系统调用中被阻塞(例如等待释放互斥锁)。因此,进程A能够使用这些API成功地查询进程B拥有的窗口的保留内存,尽管进程B被阻塞

但是,在Windows 10上应用了Creator更新后,当进程B(主线程)被阻止时,进程A在属于进程B的窗口上调用这些API时会被阻止

我通过创建两个代表进程A和进程B的独立Win32应用程序来模拟这种情况。在应用了Creators Update的Windows 10系统上,进程A在进程B(主线程)等待互斥时调用属于进程B的窗口上的GetWindowLong()/GetWindowWord()时挂起。换句话说,对GetWindowLong()/GetWindowWord()的调用从未返回,因此使进程挂起

但是,当我在Windows 10系统上使用我的独立应用程序测试同一场景时,如果没有创建者更新或更早的版本(如Windows 7),则在进程a中对GetWindowLong()/GetWindowWord()API的调用会成功返回,即使进程B正在等待释放互斥锁

为了演示上述问题,下面是流程A和流程B的代码。 要查看问题,请运行进程A和进程B。然后,找到进程B窗口的窗口句柄(例如使用Spy++),然后将其粘贴到进程A窗口的编辑字段中。然后点击OK。将显示一个消息框,其中显示在进程B的窗口的额外内存(使用SetWindowLong())中设置的长值。 到目前为止,一切顺利。 现在,转到进程B的窗口,单击“块”按钮使其挂起。这将使进程“B”(主GUI线程)等待一个永远不会释放的互斥锁,因此进程B将挂起

现在,返回到进程A的窗口,再次单击OK(假设编辑字段仍然具有与先前粘贴的进程B相同的窗口句柄)

现在,这里是行为上的区别:

在没有创建者更新的Windows 10上,以及在早期的Windows版本(如Windows 7)上,与以前一样(即当进程B未挂起时),会显示一个消息框,显示进程B窗口的额外内存中设置的长值(使用SetWindowLong())

在Creators更新的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);
}
/*进程A*/
#包括
#包括
#包括
整数计数=0;
int count1=0;
TCHAR-str[1000];
LRESULT回调WindowFunc(HWND、UINT、WPARAM、LPARAM);
HWND g_hwndEdit,g_hwndEdit按钮;
#定义ID_编辑(3456)
#定义ID_OK(3457)
TCHAR szWinName[]=文本(“MyWin”);
HINSTANCE g_hInst=NULL;
int WINAPI WinMain(HINSTANCE hThisInst、HINSTANCE hPrevInst、LPSTR lpszArgs、int nWinMode)
{
HWND-HWND;
味精;
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(空,IDI_应用程序);
wcl.hIconSm=NULL;
wcl.hCursor=LoadCursor(空,IDC_箭头);
wcl.lpszMenuName=NULL;
wcl.cbClsExtra=0;
wcl.cbWndExtra=44;
wcl.hbrBackground=(HBRUSH)GetStockObject(白色画笔);
如果(!RegisterClassEx(&wcl))返回0;
hwnd=CreateWindowEx(
WS_EX_WINDOWEDGE,
szWinName,
“过程A”,
WS_重叠窗口,
CW_使用默认值,
CW_使用默认值,
CW_使用默认值,
CW_使用默认值,
HWND_桌面,
无效的
赫蒂斯特,
无效的
);    
显示窗口(hwnd、nWinMode);
更新窗口(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
翻译信息(&msg);
发送消息(&msg);
}
返回msg.wParam;
}
LRESULT回调WindowFunc(HWND HWND,UINT消息,WPARAM WPARAM,LPARAM LPARAM)
{
长l;
HWND hwndOther=HWND;
char s[]=“在编辑字段中粘贴要调用GetWindowLong()的进程B窗口的窗口句柄(十六进制),然后单击确定。”;
HDC-HDC;
PAINTSTRUCT-ps;
静态int cxClient=0,cyClient=0;
char btnText[1001];
开关(信息){
案例WM_创建:
g_hwndEdit=CreateWindow(“编辑”,NULL,
WS|u CHILD | WS|u VISIBLE | WS|HSCROLL | WS|VSCROLL|
WS|u BORDER|ES|u左,
200,200,200,200,hwnd,(汉努)ID_编辑,
g_hInst,空);
g_hwndButton=创建窗口(
“按钮”,
“好的”,
WS|u CHILD | WS|u可见,
500,
200,
150,
50,
hwnd,
(汉努)好的,
古欣斯特,
无效的
);
返回0;
案例WM_大小:
cxClient=LOWORD(lParam);
cyClient=HIWORD(lParam);
返回0;
案例WM_油漆:
hdc=开始喷漆(hwnd和ps);
文本输出(hdc、10100、s、strlen);
端漆(hwnd和ps);
返回0;
case WM_命令:
{
如果(HIWORD(wParam)==BN\u单击和&LOWORD(wParam)==ID\u确定)
/* 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);
}
#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);
}