用MFC AppWizard创建一个窗口应用程序。点OK,用AfxBeginThread创建一个UI线程,显示一个Dialog,非模态的。
然后用PostMessage(hwnd, WM_QUIT, ...) 把MFC AppWizard创建的那个窗口关掉。
不知道为什么整个应用程序就退出了,我不是还创建了个新的线程吗?应该所有的线程都退出应用程序才结束呀?然而,我不用mfc,用菜单File->New,然后选Win32 Application创建一个Win32应用程序,用CreateThread创建一个
线程,线程函数里跟WinMain里一样,创建窗口,然后进入消息循环( while (GetMessage(&msg, NULL, 0, 0)) 
我调用PostMessage(hwnd, WM_QUIT,...),让VC自动生成的那个窗口退出,这样,应用程序没有退出,第二个窗口还在不知道为什么会有这样迥异的结果?
我一直觉得windows线程地位都是一样的,所有线程退出,应用程序才退出,sdk编程测试是这个结果,用MFC时为啥不同?
谢谢

解决方案 »

  1.   

    子线程的地位可能一样,但和主线程相比地位是不一样的。
    MFC内对消息的处理进行了封装而以,但并不是主线程退出就会自动强制结束所有子线程退出的,只有在结束进程时才会产生这种效果,MFC只是特例。
      

  2.   

    程序真正的入口点是在VC的某个静态库里面(不同类型的项目导入的静态库不同),由静态库中的代码来调用程序的主函数,当程序的主函数返回后,静态库会调用ExitProcess退出进程,所以整个程序就结束了。
    如果想让主线程退出而其它线程继续执行,可以在主线程中调用ExitThread函数来退出线程。
    至于Win32应用程序项目,我记得也是只要主函数返回就会结束进程的,是不是你没有让主函数返回?也可能是不同版本的VC对这个部分的处理方式不同。
      

  3.   

    你可以把mfc程序想成int main{
    CXXXApp _theApp;
    }_theApp的构造函数随后进行一些操作开始消息循环防止程序直接退出 而你关了这个主线程开的窗口 整个进程就退了 别的线程死于非命;听了你 Win32线程没有什么不一样 我特意试了一下 事情确实是按常理发生的 没有被任何鬼神控制。
    // DelMe.cpp : Defines the entry point for the application.
    //#include "stdafx.h"
    #include "resource.h"
    #include <process.h>
    #include <assert.h>#define MAX_LOADSTRING 100// Global Variables:
    HINSTANCE hInst; // current instance
    TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text// Foward declarations of functions included in this code module:
    ATOM MyRegisterClass(HINSTANCE hInstance);
    BOOL InitInstance(HINSTANCE, int, HWND& newWnd);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);struct  _PARAM
    {
    HINSTANCE hInstance;
    HINSTANCE hPrevInstance;
    LPSTR     lpCmdLine;
        int       nCmdShow;
    };unsigned APIENTRY SubThread(LPVOID param){
    // TODO: Place code here. _PARAM* lpData = (_PARAM*)param; MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(lpData->hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(lpData->hInstance, IDC_DELME, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(lpData->hInstance);

    // Perform application initialization:
    static bool bFirst = true;
    static HWND newWnd1 = NULL; HWND newWnd2 =NULL;
    // 保存主线程所创建的窗口的句柄
    if (!InitInstance (lpData->hInstance, lpData->nCmdShow, bFirst? newWnd1 : newWnd2)) 
    {
    return FALSE;
    }


    hAccelTable = LoadAccelerators(lpData->hInstance, (LPCTSTR)IDC_DELME);
    if (bFirst)
    {
    bFirst = false; unsigned st = 0;
    HANDLE hSubThread = (HANDLE)_beginthreadex(NULL, 0, SubThread, lpData, 0, &st);
    assert(hSubThread);
    Sleep(2000); // 等子线程建立窗口之类
    }else{
    Sleep(4000); // 等主窗口开始消息循环
    assert(hParentThread);
    PostMessage(newWnd1, WM_QUIT, 0, 0);
    } // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0)) 
    {
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    }

    return msg.wParam;
    }
    int APIENTRY WinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR     lpCmdLine,
                         int       nCmdShow)
    {

    _PARAM param = {
    hInstance, hPrevInstance, lpCmdLine, nCmdShow
    }; SubThread(&param);
    return 0;
    }//
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Registers the window class.
    //
    //  COMMENTS:
    //
    //    This function and its usage is only necessary if you want this code
    //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
    //    function that was added to Windows 95. It is important to call this function
    //    so that the application will get 'well formed' small icons associated
    //    with it.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX);  wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = (WNDPROC)WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DELME);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = (LPCSTR)IDC_DELME;
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex);
    }//
    //   FUNCTION: InitInstance(HANDLE, int)
    //
    //   PURPOSE: Saves instance handle and creates main window
    //
    //   COMMENTS:
    //
    //        In this function, we save the instance handle in a global variable and
    //        create and display the main program window.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow, HWND& newWnd)
    {
       HWND hWnd;   hInst = hInstance; // Store instance handle in our global variable   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);   if (!hWnd)
       {
          return FALSE;
       }   newWnd = hWnd;   ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);   return TRUE;
    }//
    //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
    //
    //  PURPOSE:  Processes messages for the main window.
    //
    //  WM_COMMAND - process the application menu
    //  WM_PAINT - Paint the main window
    //  WM_DESTROY - post a quit message and return
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR szHello[MAX_LOADSTRING];
    LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); switch (message) 
    {
    case WM_COMMAND:
    wmId    = LOWORD(wParam); 
    wmEvent = HIWORD(wParam); 
    // Parse the menu selections:
    switch (wmId)
    {
    case IDM_ABOUT:
       DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
       break;
    case IDM_EXIT:
       DestroyWindow(hWnd);
       break;
    default:
       return DefWindowProc(hWnd, message, wParam, lParam);
    }
    break;
    case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    // TODO: Add any drawing code here...
    RECT rt;
    GetClientRect(hWnd, &rt);
    DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
    EndPaint(hWnd, &ps);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
       }
       return 0;
    }// Mesage handler for about box.
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    switch (message)
    {
    case WM_INITDIALOG:
    return TRUE; case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
    {
    EndDialog(hDlg, LOWORD(wParam));
    return TRUE;
    }
    break;
    }
        return FALSE;
    }
      

  4.   

    这个例子就是向导生成的win32工程稍加修改
    在主线程创建窗口后再创建一个子线程 并由子线程创建窗口 子线程随后Post WM_QUIT给主窗口
    主窗口的消息循环结束 WinMain自然返回,进程结束。
      

  5.   

    WinMain函数已经返回了,你说的库函数,是vc的mfc库吧,但是我sdk编程,不用mfc库的
      

  6.   

    哈哈,是我记错了,WinMain返回后,运行库接着就会调用 退出函数。
    用sdk编程也是这样