VC在线程中操作界面

本文转自tingsking18。

       做界面业务处理的人员,经常会遇到的一个问题,在数据处理过程中需要更新界面。但是这时候如果用户同时在操作界面的话,就会产生莫名其妙的异常了。这就是由于windows用户控件不是线程安全的造成,拥有同样问题的另一个问题是在微软提供的GDI+,在使用IMage对象时,也会经常出现莫名其妙的异常。该异常也是由于GDI+的内核对象不是线程安全所导致。

我们一般的做法都是,在我们的数据线程中向主界面线程中投递消息。让所有对控件的操作都由主线程一个线程执行。这样线程安全问题就被解决了。今天翻看网页突然发现另外一种解决方案,让人虎躯一震。哈哈!转你。。。

1.      定义消息处理函数和SetWindowLong返回值

static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);

long   OldProc;

2.      在Button1的处理函数中创建线程

void CMyDlg::OnButton1()

{

HWND h = m_btn2.m_hWnd;

OldProc = SetWindowLong(h,GWL_WNDPROC,long(PluginWinProc));

_beginthread(ThreadStart1,0,(void *)(&m_btn2));

}

3.  还原系统消息过程

void CMyDlg::OnDestroy()

{

CDialog::OnDestroy();

SetWindowLong(m_btn2.m_hWnd,GWL_WNDPROC,OldProc);                  

}

4.  自定义消息过程函数

static LRESULT CALLBACK PluginWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

    switch (msg)

    {

    case MYMSG:

        {

            CWnd *wnd = CWnd::FromHandle(hwnd);

            wnd->SetWindowText("aaaaaaa");

        }

        break;

    default:

        break;

    }

    return   CallWindowProc((WNDPROC)OldProc,hwnd,msg,wParam,lParam); 

}

代码都非常简单。关键的是SetWindowLong这个函数,这个函数的作用是设定窗口属性。GWL_WNDPROC 为窗口过程设置新地址。下面是MSDN中关于SetWindowLong和GWL_WNDPROC的说明:

若使用SetWindowLong函数和GWL_WNDPROC索引替换窗口过程,则给定的窗口过程必须遵循WindowProc回调函数的说明中指定的准则。

使用GWL_WNDPROC索引调用SetWindowLong函数可创建该窗口类的子类(窗口类用来创建窗口)。应用程序不得用另一个过程的窗口产生子类。

当然要在使用完后在用SetWindowLong原来的窗口过程设置回去。使用这种方法可用于修改你无法更改代码的类,可以重写他的消息处理函数。

     点评:我对作者的最后一句话很是欣赏。想获取一个任务的句柄并不难,API提供了很多的这样的函数。如果能够将一个任务的消息过程拦截了,将它里面一些关键的消息进行重写。那么修改窗体样式,颜色,等等这样的功能,岂不是很容易实现。


你可能感兴趣的:(VC在线程中操作界面)