使用CreateWindowsEx()创建两个窗口

使用CreateWindowsEx()创建两个窗口,c,winapi,forms,C,Winapi,Forms,我有一个windows窗体,它有一个简单的菜单并执行一个简单的操作,我希望能够创建另一个具有菜单栏、消息泵等所有功能的windows窗体。。作为一个单独的线程,这样我就可以将操作的结果共享给第二个窗口 即 1) 表单A打开表单B作为单独的线程打开 2) 表格A执行操作 3) 表格A通过内存将结果传递给表格B 4) 表格B显示结果 我不知道该怎么做,主应用运行良好,但如果第一个窗口已经存在,我不知道如何添加第二个窗口。我认为使用CreateWindow将允许我创建另一个窗口,但我同样不确定如何访问

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

1) 表单A打开表单B作为单独的线程打开

2) 表格A执行操作

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

4) 表格B显示结果

我不知道该怎么做,主应用运行良好,但如果第一个窗口已经存在,我不知道如何添加第二个窗口。我认为使用CreateWindow将允许我创建另一个窗口,但我同样不确定如何访问消息泵,以便能够响应某些事件,如第二个窗口上的WM_CREATE

我希望这是有道理的

谢谢

编辑:

我试图创建第二个窗口,虽然它可以编译,但没有窗口在构建时显示atall

//////////////////////
// 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;

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

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

您可能只需要使用一个线程就可以获得消息,前提是您打算使用它进行的工作不会将消息队列的处理与用户体验到的滞后控件联系在一起。

在您的CreateWindow()调用中,您将0传递到位置和大小参数中。
试着像这样修改你的案例

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;
这是我对你想做的事情的一种解释,至少是关于儿童窗口。(我仍然不明白为什么需要第二个线程,但一次解决一个问题….)

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


为第二次回复而道歉。我的另一个回答是非常笼统的,可能只是OBE,因为OP已经提供了更多细节。

呃,我不认为你真的需要另一个过程——你可能只需要另一个线程!您正在第二次CreateWindow调用中写入第一个hwnd。您需要2个hwnd变量来跟踪和显示2个窗口。>您不希望仅仅为了显示第二个窗口而创建第二个线程。99%的Windows应用程序在屏幕上有数百个窗口(按钮和控件算作窗口句柄),整个过程只使用一个线程就可以正常运行。为后台“无头”(非UI)工作保存线程。即使在那个时,也要避免线程,除非你们已经准备好处理头痛问题。几乎任何事情都可以在没有线程和线程头痛的情况下完成。@d我之所以希望在不同的线程上使用线程,是因为我将使用一些共享内存在完全不同的窗口之间传递信息。杰米:在同一个应用程序中,在不同的窗口之间传递信息不需要线程。您也不需要共享内存—处理其消息的窗口句柄和windproc位于同一线程、同一进程中,并且可以访问同一全局内存。如果你打算在老式的Win32 API级别上工作,那就去读老式的圣经:阅读Petzold的Windows编程手册-。@JustJeff我已经添加了我认为你想要了解的内容,尽管我在实现它时遇到了问题。我刚刚测试了一些与你文章类似的代码,但只是用了一个普通的旧按钮在儿童窗口。已验证您应该能够在WM_create的范围内创建子窗口,并且如果您忘记父窗口上的WS_CLIPCHILDREN,您的子窗口将无法访问。只需再次检查,这将使窗口与我可以添加菜单的第一个窗口相同,对吗?我看过一些网页提到用它来创建组合框和按钮,这不是我想要的。我只是用了一个按钮,因为这是一个简单的预定义窗口类,我不必四处寻找来找到什么。就CreateWindow()和CreateWindowEx()而言,窗口、对话框和控件都几乎相同。我添加了WS_CLIPCHILDREN,但我只能看到一个窗口,我不太确定哪里出了问题。仍然只有一个窗口可见,它应该与您的示例和Microsoft MSDN相同。感谢您提供的解决方案,您的解决方案很好。我要重新检查一下我的,看看它为什么不起作用。非常感谢你的耐心。
#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;
}
cl demo.c user32.lib gdi32.lib