本帖最后由 liuchao35758600 于 2013-09-14 19:10:19 编辑

解决方案 »

  1.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
      

  2.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
      

  3.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
      

  4.   

    唯一的消息循环是在新建的线程上跑的,窗口也是在这个线程上调用 CreateWindow 函数创建的。
    显示窗口和调整窗口位置、尺寸及样式,是在主线程上执行的。
      

  5.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。在子线程上创建的窗口是无法得到Window消息的,必须创建线程的消息循环,然后在子线程上创建窗口
      

  6.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
    我好像明白一点了,你这个不是MFC工程吧?
      

  7.   

    就在GetMessage函数获取到消息后打印它的,与该函数处于同一线程。
    代码类似于这样:if( GetMessage( &msg, hwnd, 0, 0 ) ) {
        printf("message: %u\n", msg.message);
        //......
    }
      

  8.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
    我好像明白一点了,你这个不是MFC工程吧?
    不是MFC工程,用的工具是VisualStudio2012,选择的是“win32 项目”,应用程序类型为:“windows 应用程序”。
      

  9.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
    我好像明白一点了,你这个不是MFC工程吧?
    不是MFC工程,用的工具是VisualStudio2012,选择的是“win32 项目”,应用程序类型为:“windows 应用程序”。

    还真没试验过这种用法。你在子线程中也可以做阻塞的,只要你这么做
    while(true)
    {
        Sleep(100); // ms
        if (bQuit) // 控制从线程结束的全局变量
        {
             _endthread();
        }   
        要实现的功能
    }
      

  10.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
    我好像明白一点了,你这个不是MFC工程吧?
    不是MFC工程,用的工具是VisualStudio2012,选择的是“win32 项目”,应用程序类型为:“windows 应用程序”。

    还真没试验过这种用法。你在子线程中也可以做阻塞的,只要你这么做
    while(true)
    {
        Sleep(100); // ms
        if (bQuit) // 控制从线程结束的全局变量
        {
             _endthread();
        }   
        要实现的功能
    }
    但问题是,我问的不是如何在子线程中做阻塞,而是子线程上的消息循环为何能不能接收到WM_QUIT、WM_CLOSE和WM_DESTROY这三个消息、其它消息(鼠标移动、鼠标点击、按键等)却能接收?
      

  11.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
    我好像明白一点了,你这个不是MFC工程吧?
    不是MFC工程,用的工具是VisualStudio2012,选择的是“win32 项目”,应用程序类型为:“windows 应用程序”。

    还真没试验过这种用法。你在子线程中也可以做阻塞的,只要你这么做
    while(true)
    {
        Sleep(100); // ms
        if (bQuit) // 控制从线程结束的全局变量
        {
             _endthread();
        }   
        要实现的功能
    }
    但问题是,我问的不是如何在子线程中做阻塞,而是子线程上的消息循环为何能不能接收到WM_QUIT、WM_CLOSE和WM_DESTROY这三个消息、其它消息(鼠标移动、鼠标点击、按键等)却能接收?
    你能把你界面线程启动的代码贴一下么?我现在想不出来你是怎么实现的。
      

  12.   

    在主线程的close函数中对窗口发送WM_CLOSE消息试试
    SendMessage(pSubWnd->m_hWnd, WM_CLOSE, 0, 0);
      

  13.   

    主窗口是主线程创建,子窗口是子线程创建。void//主窗口结束函数
    MainDialog::OnClose()
    {
    CloseSubWnd(&m_dlgToolbox);
    CloseSubWnd(&m_dlgAutoDiagnose); SetMsgHandled(FALSE);
    EndDialog(IDCANCEL);
    }template<typename SubWndType>
    BOOL 
    MainDialog::CloseSubWnd(SubWndType* pSubWnd)
    {
    if(pSubWnd->m_hWnd)
    {
    ::SendMessage(pSubWnd->m_hWnd, WM_CLOSE, 0, 0);
    } return TRUE;
    }
      

  14.   

    还有在子窗口中要写WM_CLOSE和WM_DISTORY消息响应(十分重要)
    template<typename SubWndType>
    LRESULT 
    CSubWndCommon<SubWndType>::OnClose()
    {
    DestroyWindow(m_pSubWnd->m_hWnd);
    return S_OK;
    }template<typename SubWndType>
    LRESULT 
    CSubWndCommon<SubWndType>::OnDestroy()
    {
    PostQuitMessage(0);
    return S_OK;
    }
      

  15.   

    这个阻塞函数和GetMessage函数类似,用于在循环里阻塞获取数据,让程序处理。
    目前有个解决方案,将那个阻塞函数放到线程上执行,消息循环还是放在主线程上执行。但我想知道这个问题的原因。
    消息的投递有4个参数,第一个是窗口句柄,也就是说,你点击程序界面的关闭按钮
    此时接收该消息的窗口是主线程创建的,因此只有主线程的消息循环处理能知道
    你新建的线程是看不到的
    程序唯一的一个窗口也是在新线程上创建的。
    我好像明白一点了,你这个不是MFC工程吧?
    不是MFC工程,用的工具是VisualStudio2012,选择的是“win32 项目”,应用程序类型为:“windows 应用程序”。

    还真没试验过这种用法。你在子线程中也可以做阻塞的,只要你这么做
    while(true)
    {
        Sleep(100); // ms
        if (bQuit) // 控制从线程结束的全局变量
        {
             _endthread();
        }   
        要实现的功能
    }
    但问题是,我问的不是如何在子线程中做阻塞,而是子线程上的消息循环为何能不能接收到WM_QUIT、WM_CLOSE和WM_DESTROY这三个消息、其它消息(鼠标移动、鼠标点击、按键等)却能接收?
    你能把你界面线程启动的代码贴一下么?我现在想不出来你是怎么实现的。
    以下是部分代码:
    #include <LCUI_Build.h>
    #include LC_LCUI_H#ifdef LCUI_VIDEO_DRIVER_WIN32#include LC_GRAPH_H
    #include LC_INPUT_H
    #include LC_CURSOR_H
    #include LC_DISPLAY_H
    #include LC_WIDGET_H
    #include <Windows.h>
    #include "resource.h"static HWND current_hwnd = NULL;
    static int pixel_mem_len = 0;
    static unsigned char *pixel_mem = NULL;
    static HDC hdc_client, hdc_framebuffer;
    static HBITMAP client_bitmap;
    static HINSTANCE win32_hInstance = NULL, dll_hInstance = NULL;
    static LCUI_Mutex screen_mutex;
    static LCUI_Thread th_win32;
    static LCUI_Sleeper win32_init_sleeper;
    static LCUI_BOOL win32_init_error = TRUE;LCUI_API void Win32_LCUI_Init( HINSTANCE hInstance )
    {
    win32_hInstance = hInstance;
    }static LRESULT CALLBACK Win32_LCUI_WndProc(
    HWND hwnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam )
    {
    PAINTSTRUCT ps;
    LCUI_Rect area; switch (message) {
    case WM_KEYDOWN:
    LCUIKeyboard_HitKey( wParam );
    return 0;
    case WM_KEYUP:
    LCUIKeyboard_FreeKey( wParam );
    return 0;
    case WM_RBUTTONDOWN:
    LCUIMouse_ButtonDown( LCUIKEY_RIGHTBUTTON );
    return 0;
    case WM_RBUTTONUP:
    LCUIMouse_ButtonUp( LCUIKEY_RIGHTBUTTON );
    return 0;
    case WM_LBUTTONDOWN:
    LCUIMouse_ButtonDown( LCUIKEY_LEFTBUTTON );
    return 0;
    case WM_LBUTTONUP:
    LCUIMouse_ButtonUp( LCUIKEY_LEFTBUTTON );
    return 0;
    case WM_PAINT:
    BeginPaint( hwnd, &ps );
    /* 获取区域坐标及尺寸 */
    area.x = ps.rcPaint.left;
    area.y = ps.rcPaint.top;
    area.width = ps.rcPaint.right - area.x;
    area.height = ps.rcPaint.bottom - area.y;
    /* 记录该无效区域 */
    LCUIScreen_InvalidArea( area );
    EndPaint( hwnd, &ps );
    return 0;
    case WM_DESTROY:
    PostQuitMessage(0);
    LCUI_Quit();
    return 0;
    default:break;
    }
    return DefWindowProc (hwnd, message, wParam, lParam) ;
    }LCUI_API HWND Win32_GetSelfHWND( void )
    {
    return current_hwnd;
    }LCUI_API void Win32_SetSelfHWND( HWND hwnd )
    {
    current_hwnd = hwnd;
    }/** 动态库的入口函数 */
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved )
    {
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    break;
    }
    dll_hInstance = hModule;
    return TRUE;
    }static int Win32_ScreenInit(void)
    {
    WNDCLASS wndclass;
    TCHAR szAppName[] = TEXT ("LCUI OutPut"); wndclass.style         = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc   = Win32_LCUI_WndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = win32_hInstance;
    /* 载入动态库里的图标 */
    wndclass.hIcon         = LoadIcon( dll_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) );
    wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW );
    wndclass.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH );
    wndclass.lpszMenuName  = NULL;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClass (&wndclass)) {
    MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
    szAppName, MB_ICONERROR) ;
    return -1;
    }
    /* 创建窗口 */
    current_hwnd = CreateWindow (
    szAppName, TEXT ("LCUI"),
    WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,
    CW_USEDEFAULT, CW_USEDEFAULT,
    0, 0,
    NULL, NULL, win32_hInstance, NULL);
    return 0;
    }/** Win32的消息循环线程 */
    static void LCUI_Win32_Thread( void *arg )
    {
    MSG msg;
    if( Win32_ScreenInit() == -1 ) {
    /* 设置标志为TRUE,表示初始化失败 */
    win32_init_error = TRUE;
    /* 打断处于睡眠状态的线程的睡眠 */
    LCUISleeper_BreakSleep( &win32_init_sleeper );
    LCUIThread_Exit(NULL);
    return;
    }
    /* 设置标志为FALSE,表示初始化成功 */
    win32_init_error = FALSE;
    /* 隐藏windows的鼠标游标 */
    ShowCursor( FALSE );
    LCUISleeper_BreakSleep( &win32_init_sleeper );
    while( LCUI_Sys.state == ACTIVE ) {
    /* 获取消息 */
    if( GetMessage( &msg, Win32_GetSelfHWND(), 0, 0 ) ) {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
    }
    }
    LCUIThread_Exit(NULL);
    }/** 初始化屏幕 */
    LCUI_API int LCUIScreen_Init( int w, int h, int mode )
    {
    LCUI_Widget *root_widget;
    LCUI_Screen screen_info; /* 初始化屏幕互斥锁 */
    LCUIMutex_Init( &screen_mutex );
    LCUISleeper_Create( &win32_init_sleeper );
    /* 创建线程 */
    LCUIThread_Create( &th_win32, LCUI_Win32_Thread, NULL );
    /* 进行睡眠,最长时间为5秒 */
    LCUISleeper_StartSleep( &win32_init_sleeper, 5000 );
    /* 若初始化出现错误 */
    if( win32_init_error ) {
    return -1;
    }
    /* 准备屏幕相关信息 */
    screen_info.bits = 32;
    screen_info.mode = mode;
    strcpy( screen_info.dev_name, "win32 GDI" );
    /* 设置屏幕信息 */
    LCUIScreen_SetInfo( &screen_info );
    /* 设置图形输出模式 */
    LCUIScreen_SetMode( w, h, mode ); w = GetSystemMetrics(SM_CXSCREEN);
    h = GetSystemMetrics(SM_CYSCREEN);
    pixel_mem_len = w*h*4; /* 分配内存,储存像素数据 */ 
    pixel_mem = (uchar_t*)malloc( pixel_mem_len );
    /* 获取客户区的DC */
    hdc_client = GetDC( current_hwnd );
    /* 为帧缓冲创建一个DC */
    hdc_framebuffer = CreateCompatibleDC( hdc_client );
    /* 为客户区创建一个Bitmap */ 
    client_bitmap = CreateCompatibleBitmap( hdc_client, w, h );
    /* 为帧缓冲的DC选择client_bitmap作为对象 */
    SelectObject( hdc_framebuffer, client_bitmap );

    root_widget = RootWidget_GetSelf();
    Widget_Resize( root_widget, screen_info.size );
    Widget_SetBackgroundColor( root_widget, RGB(255,255,255) );
    Widget_SetBackgroundTransparent( root_widget, FALSE );
    Widget_Show( root_widget );
    /* 显示窗口 */
    ShowWindow( current_hwnd, SW_SHOWNORMAL );
    UpdateWindow( current_hwnd );
    return 0;
    }// 省略剩余代码
      

  16.   

    楼主说的是在子线程创建的窗口?那主线程有木有窗口呢?
    楼主可以看一下这个:
    http://blog.csdn.net/norains/article/details/2023957