wordpress   发布时间:2022-04-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了windows – GetWindowLong() – 使用Creators Update引入的行为更改会破坏我的win32应用程序大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

最近对 Windows 10进行的Creator更新破坏了我使用Win32 API GetWindowLong()的应用程序代码. 在Windows 10 Creator update之前,一个进程(比如进程A)能够在另一个进程的窗口句柄(比如进程B)上调用GetWindowWord()/ GetWindowLong()API,即使在某些系统中阻止了进程B(主线程)调用(例如等待释放互斥锁).因此
最近对 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和进程B.然后,找出进程B窗口的窗口句柄(例如,使用Spy),然后将其粘贴到进程A的窗口的编辑字段中.然后单击“确定”.将显示一个消息框,显示在进程B的窗口的额外内存中设置的LONG值(使用SetWindowLong()).
到现在为止还挺好.
现在,进入B的窗口,点击“Block”按钮使其挂起.这将使进程“B”(主GUI线程)等待永远不会被释放的互斥锁,因此进程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 – GetWindowLong() – 使用Creators Update引入的行为更改会破坏我的win32应用程序全部内容,希望文章能够帮你解决windows – GetWindowLong() – 使用Creators Update引入的行为更改会破坏我的win32应用程序所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。