代码之家  ›  专栏  ›  技术社区  ›  Jamie Keeling

使用CreateWindowsEx()生成两个窗口

  •  2
  • Jamie Keeling  · 技术社区  · 14 年前

    我有一个Windows窗体,它有一个简单的菜单并执行一个简单的操作,我希望能够创建另一个具有菜单栏、消息泵等所有功能的Windows窗体。作为一个单独的线程,这样我就可以将操作的结果共享到第二个窗口。

    即。

    1)A型打开B型作为单独的螺纹打开

    2)A表执行操作

    3)表A通过内存将结果传递到表B

    4)表格B显示结果

    我对如何进行感到困惑,主应用运行良好,但我不确定如果第一个窗口已经存在,如何添加第二个窗口。我认为使用CreateWindow将允许我创建另一个窗口,但我再次不确定如何访问消息泵,因此我可以响应某些事件,如第二个窗口上的wm_create。

    我希望这是有道理的。

    谢谢!

    编辑:

    我已经尝试创建第二个窗口,尽管这确实是编译的,但没有任何窗口显示有关生成的所有信息。

    //////////////////////
    // WINDOWS FUNCTION //
    //////////////////////
    LRESULT CALLBACK WindowFunc(HWND hMainWindow, UINT message, 
                                WPARAM wParam, LPARAM lParam)
    {
        //Fields
        WCHAR buffer[256];
        struct DiceData storage;
        HWND hwnd;
    
        // Act on current message
        switch(message)    
        {
        case WM_CREATE:
            AddMenus(hMainWindow);
    
            hwnd = CreateWindowEx(
                0,
                "ChildWClass",
                (LPCTSTR) NULL,
                WS_CHILD | WS_BORDER | WS_VISIBLE,
                0,
                0,
                0,
                0,
                hMainWindow,
                NULL,
                NULL,
                NULL);
    
            ShowWindow(hwnd, SW_SHOW);
    
            break;
    

    关于为什么会发生这种情况有什么建议吗?

    编辑2:

    这就是一切,我不知道我是否正在实现这个权利,但我已经尝试与其他窗口创建保持一致。

    //////////////////
    // WINDOWS MAIN //
    //////////////////
    int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, 
                       LPSTR lpszArgs, int nWinMode)
    {
        // Declaration of window class (used to register program), 
        // handle to window (returned by CreateWindow)
        // and windows message (holds messages received from windows)
        WNDCLASS wcl;
        WNDCLASS scl;
        HWND hwnd;
        MSG msg;
    
        // Name of window and window class
        LPCWSTR szWinName   = L"DiceRoller - Producer";
        LPCWSTR szClassName = L"DiceRollProd";
    
        LPCWSTR szCWinName = L"Dice - Consumer";
        LPCWSTR szCClassName = L"DiceRollCon";
    
        // Set up the windows class struct
        wcl.hInstance = hThisInst;
        wcl.lpszClassName = szClassName;
        wcl.lpfnWndProc = WindowFunc;
        wcl.style = 0;
        wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcl.lpszMenuName = NULL;
        wcl.cbClsExtra = 0;
        wcl.cbWndExtra = 0;
        wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    
        // Set up the windows class struct
        scl.hInstance = hThisInst;
        scl.lpszClassName = szCClassName;
        scl.lpfnWndProc = WindowFunc;
        scl.style = 0;
        scl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        scl.hCursor = LoadCursor(NULL, IDC_ARROW);
        scl.lpszMenuName = NULL;
        scl.cbClsExtra = 0;
        scl.cbWndExtra = 0;
        scl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    
        // Register the windows class
        if(!RegisterClass(&wcl))
        {
            return 0;
        }
    
        if(!RegisterClass(&scl))
        {
            return 0;
        }
    
        // Create the main window
        hwnd = CreateWindowEx(0,
            szClassName,
            szWinName,
            WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
            100,
            100,
            400,
            400,
            HWND_DESKTOP,
            NULL,
            hThisInst,
            NULL );
    
    
        // Show the main window
        ShowWindow(hwnd, nWinMode);
        UpdateWindow(hwnd);
    
        // Main message processing loop
        while(GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return (int)msg.wParam;
    }
    
    
    
    //////////////////////
    // WINDOWS FUNCTION //
    //////////////////////
    LRESULT CALLBACK WindowFunc(HWND hMainWindow, UINT message, 
                                WPARAM wParam, LPARAM lParam)
    {
        //Fields
        WCHAR buffer[256];
        struct DiceData storage;
        HWND hwnd;
    
        // Act on current message
        switch(message)    
        {
        case WM_CREATE:
            AddMenus(hMainWindow);
    
            hwnd = CreateWindowEx(
            0,
            "ChildWClass",
            (LPCTSTR) NULL,
            WS_CHILD | WS_BORDER | WS_VISIBLE,
            CW_USEDEFAULT,  // x location
            CW_USEDEFAULT,  // y location
            400,  // width
            300,  // height
            hMainWindow,
            NULL,
            NULL,
            NULL);
    
            ShowWindow(hwnd, SW_SHOW);
            UpdateWindow(hwnd);
    
            break;
    
    2 回复  |  直到 14 年前
        1
  •  2
  •   JustJeff    14 年前

    在createWindow()调用中,将0传递到位置和大小参数中。
    尝试修改你的wm_创建这样的案例。

    case WM_CREATE:
        AddMenus(hMainWindow);
    
        hwnd = CreateWindowEx(
            0,
            "ChildWClass",
            (LPCTSTR) NULL,
            WS_CHILD | WS_BORDER | WS_VISIBLE,
            CW_USEDEFAULT,  // x location
            CW_USEDEFAULT,  // y location
            400,  // width
            300,  // height
            hMainWindow,
            NULL,
            NULL,
            NULL);
    
        ShowWindow(hwnd, SW_SHOW);
    
        break;
    

    下面是我对你想做的事情的解释,至少考虑到儿童窗。(我仍然不明白为什么需要第二个线程,但一次出现一个问题。)

    #include <windows.h>
    LRESULT CALLBACK TheWndProc(HWND hwnd, UINT msg, WPARAM wP, LPARAM lP) {
        HDC hdc;
        HWND hwother;
    
        switch( msg ) {
        case WM_CREATE:
            hwother =
            CreateWindowEx(0, "TerribleClassName100405", "child title",
                WS_OVERLAPPEDWINDOW,
                100, 100, // location
                200, 160,  // size
                (HWND)hwnd,  // parent
                (HMENU)NULL,
                NULL,
                NULL);
            ShowWindow(hwother, SW_SHOW);
    
            break;
    
        case WM_CHAR: // quit app using escape key
            switch( LOWORD(wP) ) {
            case 27:
                SendMessage(hwnd, WM_CLOSE, 0, 0);
                return 0;
            }
            break;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        }
        return DefWindowProc(hwnd, msg, wP, lP);
    }
    
    LRESULT CALLBACK AltWndProc(HWND hwnd, UINT msg, WPARAM wP, LPARAM lP) {
        HDC hdc;
    
        switch( msg ) {
        case WM_CREATE:
            break;
    
        case WM_CHAR: // quit app using X
            switch( LOWORD(wP) ) {
            case 'X':
                SendMessage(hwnd, WM_CLOSE, 0, 0);
                return 0;
            }
            break;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        }
        return DefWindowProc(hwnd, msg, wP, lP);
    }
    
    void registerCustomWindows(HINSTANCE hInst) {
        WNDCLASSEX wc1;
        WNDCLASSEX wc2;
    
        wc1.lpszClassName = "TerribleClassName040914";
        wc1.hInstance = hInst;
        wc1.lpfnWndProc = TheWndProc;
        wc1.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
        wc1.cbSize = sizeof(wc1);
        wc1.cbClsExtra = 0;
        wc1.cbWndExtra = 0;
        wc1.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wc1.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
        wc1.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc1.hbrBackground = GetStockObject(WHITE_BRUSH);
        wc1.lpszMenuName = NULL;
        RegisterClassEx(&wc1);
    
        wc2.lpszClassName = "TerribleClassName100405";
        wc2.hInstance = hInst;
        wc2.lpfnWndProc = AltWndProc;
        wc2.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
        wc2.cbSize = sizeof(wc2);
        wc2.cbClsExtra = 0;
        wc2.cbWndExtra = 0;
        wc2.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wc2.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
        wc2.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc2.hbrBackground = GetStockObject(WHITE_BRUSH);
        wc2.lpszMenuName = NULL;
        RegisterClassEx(&wc2);
    }
    
    int WINAPI WinMain(HINSTANCE hThis, HINSTANCE hPrev, LPSTR cml, int iCS) {
        MSG msg;
        HWND hwnd;
    
        registerCustomWindows(hThis);
    
        hwnd = CreateWindowEx(0, "TerribleClassName040914", "two windows skeleton",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,   // location
            640, 480,   // size
            (HWND)NULL, // parent
            (HMENU)NULL,
            hThis,
            NULL);
    
        ShowWindow(hwnd, SW_SHOWNORMAL);
        UpdateWindow(hwnd);
    
        while( GetMessage(&msg, NULL, 0, 0) ) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    

    我在一个名为demo.c的文件中有这个确切的代码,并使用MS Visual Studio Express 2005来编译它

    cl demo.c user32.lib gdi32.lib
    

    …我有两扇窗户。为了区分我有两个窗口类,其中一个通过按Esc退出,另一个通过大写X退出。

    为发布第二条回复而道歉。我的另一个回答是非常普遍的,可能只是OBE,因为OP提供了更多的细节。

        2
  •  4
  •   JustJeff    14 年前

    您应该能够使用createWindow()创建另一个辅助窗口,并且标准的getMessage()dispatchMessage()循环实际上应该将窗口事件提供给两个窗口。Windows将以某种方式将调用CreateWindow的线程与这些窗口上的窗口事件相关联,并通过对GetMessage()的调用将这两个线程的事件都提供给它。您不必制作第二个线程来处理第二个窗口的事件。

    现在,如果将同一个窗口类名传递给对createWindow()的两个调用,则应该有同一个窗口类的两个实例,并且区分它们的方法是,在wndproc中,DispatchMessage将为您提供相关窗口的窗口句柄。如果这样做,请注意,任何对应用程序静态的数据实际上都将成为这两个窗口之间的共享资源。例如,如果静态地声明一个屏幕外位图/设备上下文来支持wm_绘制,您可能会突然发现两个窗口都在绘制以响应其中一个窗口上的事件。获得这种纠缠的可能性是为了在线程之间轻松共享数据而付出的代价。

    您可以只使用一个线程,前提是您打算使用它进行的工作不会将消息队列的处理捆绑到用户遇到滞后控制的地方。