mfc 参数传递
- 格式:docx
- 大小:16.83 KB
- 文档页数:2
3 多线程的调度和处理在32 位Windows 环境下,开发多线程应用程序可以利用提供的Win32 API 接口函数,也可以利用VC++ 中提供的MFC类库进行开发。
两种方式对于多线程编程原理是一样的,用户可以根据需要选择相应的工具。
下面以利用MFC 类库实现多线程调度与处理为例,介绍多线程的实现方法以及多个线程间任务调度所应注意的一些关键技术。
3.1 基于MFC的多线程设计在VC++6.0环境下,MFC类库提供了对多线程编程支持,使得多线程能方便的实现。
MFC区分两种类型的线程:辅助线程(Worker Thread)和用户界面线程(UserInterface Thread)。
辅助线程没有消息机制,通常用来执行后台计算和维护任务。
MFC 为用户界面线程提供消息机制,用来处理用户的输入,响应用户产生的事件和消息。
但对于Win32 的API 来说,这两种线程并没有区别,它只需要线程的启动地址以便启动线程执行任务。
用户界面线程的一个典型应用就是类CWinApp,类CwinApp是CWinThread 类的派生类,应用程序的主线程是由它提供,并由它负责处理用户产生的事件和消息。
类CwinThread 是用户接口线程的基本类。
CWinThread 的对象用以维护特定线程的局部数据。
因为处理线程局部数据依赖于类CWinThread,所以所有使用MFC 的线程都必须由MFC 来创建。
3.2 多线程的创建及涉及的关键问题要创建一个线程,需要调用函数AfxBeginThread。
该函数通过参数重载可以实现辅助线程和用户界面线程的创建。
但不论是辅助线程还是用户界面线程,都需要指定额外的参数以修改优先级,堆栈大小,创建标志和安全特性等。
函数AfxBeginThread 返回指向CWinThread 类对象的指针。
创建助手线程相对简单,并不必须从CWinThread 派生一个类。
实现起来需要两步:实现控制函数和启动线程。
afxbeginthread用法afxbeginthread是一个非常重要的函数,它可以帮助我们在MFC 程序中创建一个新的线程。
在本文中,我们将详细介绍afxbeginthread的用法,以及如何在MFC程序中使用它。
我们需要了解afxbeginthread的语法。
它的语法如下:CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc,LPVOID pParam,int nPriority = THREAD_PRIORITY_NORMAL,UINT nStackSize = 0,DWORD dwCreateFlags = 0,LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);其中,pfnThreadProc是一个指向线程函数的指针,pParam是传递给线程函数的参数,nPriority是线程的优先级,nStackSize是线程堆栈的大小,dwCreateFlags是线程的创建标志,lpSecurityAttrs 是线程的安全属性。
接下来,我们将介绍如何在MFC程序中使用afxbeginthread。
首先,我们需要在MFC程序中创建一个新的类,该类继承自CWinThread。
然后,我们需要在该类中实现线程函数。
例如,下面是一个简单的线程函数:UINT MyThreadFunction(LPVOID pParam){// Do some work herereturn 0;}接下来,我们需要在该类的构造函数中调用afxbeginthread函数,以创建一个新的线程。
例如,下面是一个简单的构造函数:CMyThread::CMyThread(){AfxBeginThread(MyThreadFunction, NULL);}在这个例子中,我们调用了afxbeginthread函数,并将MyThreadFunction作为线程函数传递给它。
引言在C++的消息公告板上经常可以看到出现ASSERT错误的求助信息。
虽然这通常是希望消除ASSERT 错误的帮助请求,但是几乎所有的求助者都认为ASSERT本身是罪恶的。
我完全能理解一个ASSERT错误给程序员新手带来的沮丧。
你的程序正在运行,通常如你所愿,突然一声巨响——一个ASSERT错误!那么就让我们来看看ASSERT们,为什么他们会出现在那里以及我们能从他们那里得到什么信息。
我应该强调一下,这篇文章讨论MFC如何处理ASSERT。
语言学打开google搜索,输入“define assert”,然后单击搜索。
WordNet中“ASSERT”有四种意思:1.断言、声称、主张……(直接了当的陈述)2.确认、查证、承认、宣誓……(正式而严肃的宣告某事属实,如:“Before God I swear I am innocent”——“在上帝面前我发誓我是清白的”)3. 坚持己见大胆地或强有力地提出(自己)的观点,以使其为大家所知。
(“Womenshould assert themselves more!”)4.强调、表明(表明事实,“The letter asserts a free society”)上面的意思都很接近,但是第4个意思字面上更加接近我们的ASSERT。
ASSERT表明条件已经被强调为真。
如果条件不为真,则程序将处于严重故障中,而你——程序员,则应该收到这个警告。
ASSERT在代码中的意思当一个程序员写一条ASSERT就表明他在说“这个条件必须为真,否则我们将发生错误”。
比如你正在写一个函数,希望得到一个字符串指针。
void CMyClass::MyFunc(LPCTSTR szStringPtr){if (*szStringPtr == ’7’)DoSomething();}这个函数读取这个指针所指向的内存段,因此它最好是指向一段合法有效的内存。
否则你的程序将崩溃!如果你传递一个空指针给这个函数,那么任何程序在调用这个函数时都将发生错误。
__cdecl__stdcallC和C++程序的缺省调用规范为了使用这种调用规范,需要你明确的加上__stdcall(或WINAPI)文字。
即return-type__stdcall function-name[(argument-list)]在被调用函数(Callee)返回后,由调用方(Caller)调整堆栈。
1. 调用方的函数调用2. 被调用函数的执行3. 被调用函数的结果返回4. 调用方清除调整堆栈在被调用函数(Callee)返回前,由被调用函数(Callee)调整堆栈。
图示:1. 调用方的函数调用2. 被调用函数的执行3. 被调用函数清除调整堆栈4. 被调用函数的结果返回因为每个调用的地方都需要生成一段调整堆栈的代码,所以最后生成的文件较大。
因为调整堆栈的代码只存在在一个地方(被调用函数的代码内),所以最后生成的文件较小。
函数的参数个数可变(就像printf函数一样),因为只有调用者才知道它传给被调用函数几个参数,才能在调用结束时适当地调整堆栈。
函数的参数个数不能是可变的。
对于定义在C程序文件中的输出函数,函数名会保持原样,不会被修饰。
对于定义在C++程序文件中的输出函数,函数名会被修饰, MSDN说Underscore character (_) is prefixed to names. 我实际测试(VC4和VC6)下来发现好像不是那么简单。
可通过在前面加上extern “C”以去除函数名修饰。
也可通过.def文件去除函数名修饰。
不论是C程序文件中的输出函数还是C++程序文件中的输出函数,函数名都会被修饰。
对于定义在C程序文件中的输出函数,An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.对于定义在C++程序文件中的输出函数,好像更复杂,和__cdecl的情况类似。
在MFC(Microsoft Foundation Classes)中,通常使用Win32的API来执行跨线程的操作。
但如果你需要从一个非UI线程(比如一个工作线程或后台线程)返回到主UI线程并执行某个方法,你可以使用多种技术来实现。
下面是一个基本的方法,使用PostMessage或SendMessage来通知主线程执行某个操作。
定义自定义消息:首先,你需要定义一个自定义的消息,这样当后台线程需要主线程执行某个操作时,就可以发送这个消息。
cpp#define WM_MY_CUSTOM_MESSAGE (WM_USER + 1)处理消息:在你的主窗口类(通常是一个从CWnd或CDialogEx派生的类)中,你需要重写WindowProc方法来处理这个自定义消息。
cppBEGIN_MESSAGE_MAP(CYourMainWindow, CFrameWnd)ON_MESSAGE(WM_MY_CUSTOM_MESSAGE, &CYourMainWindow::OnMyCustomMessage)END_MESSAGE_MAP()LRESULT CYourMainWindow::OnMyCustomMessage(WPARAM wParam, LPARAM lParam){// 在这里执行你需要的方法或操作return0;}从后台线程发送消息:当你的后台线程需要主线程执行某个操作时,它可以发送自定义的消息。
cpp::PostMessage((HWND)yourMainWindowHandle, WM_MY_CUSTOM_MESSAGE, 0, 0);这里,yourMainWindowHandle是主窗口的句柄。
你可以通过多种方式获取这个句柄,比如将其作为参数传递给后台线程,或者在创建后台线程之前保存它。
4.注意事项:使用PostMessage是异步的,意味着它会立即返回,而消息会被放入主线程的消息队列中等待处理。
mfc getbuffer函数MFC GetBuffer函数:解析和使用在MFC(Microsoft Foundation Classes)中,GetBuffer函数是一个常用的函数之一。
它主要用于获取指向字符数组的指针,以便在MFC应用程序中对字符串进行操作。
本文将详细介绍GetBuffer 函数的用法和常见应用场景。
一、GetBuffer函数的基本用法GetBuffer函数是CString类的成员函数,在CString类中定义如下:LPTSTR GetBuffer(int nMinBufLength) const;该函数的参数nMinBufLength表示所需的最小缓冲区长度。
GetBuffer函数的返回值为指向字符数组的指针。
使用GetBuffer函数的一般步骤如下:1. 创建一个CString对象并初始化。
2. 调用GetBuffer函数获取指向字符数组的指针。
3. 对字符数组进行操作。
4. 调用ReleaseBuffer函数释放字符数组。
下面以一个简单的示例来说明GetBuffer函数的基本用法:```CString str("Hello, World!");LPTSTR pBuffer = str.GetBuffer(20);// 对字符数组进行操作str.ReleaseBuffer();```在上述示例中,首先创建了一个CString对象str并初始化为"Hello, World!"。
然后调用GetBuffer函数并指定最小缓冲区长度为20,获取指向字符数组的指针pBuffer。
接下来可以对字符数组进行操作,比如修改其中的字符或进行其他操作。
最后调用ReleaseBuffer函数释放字符数组。
二、GetBuffer函数的常见应用场景1. 字符串拼接GetBuffer函数可以用于方便地进行字符串拼接操作。
例如,当需要将多个字符串拼接成一个较长的字符串时,可以使用GetBuffer 函数获取指向字符数组的指针,并使用字符串操作函数对字符数组进行拼接。
mfc多线程编程主线程等待子线程退出函数-回复MFC多线程编程是指使用Microsoft Foundation Classes (MFC)框架开发多线程应用程序的过程。
在这种编程模型中,主线程是应用程序的入口点,而子线程则用于执行一些独立的任务,从而提高应用程序的性能和响应能力。
在实际开发中,经常需要主线程等待子线程执行完毕的情况。
这样做的目的是确保主线程在继续执行之前,所有的子线程已经完成任务,从而避免可能的数据竞争和资源冲突。
本文将详细介绍如何在MFC多线程编程中,实现主线程等待子线程退出函数的方法,以及一些相关的注意事项。
第一步:创建子线程在MFC中,可以通过调用AfxBeginThread函数来创建子线程。
该函数的原型如下:CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0,LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);其中,pfnThreadProc是子线程函数的指针,LPVOID pParam是传递给子线程函数的参数。
以下是一个示例的子线程函数的定义:UINT MyThreadFunction(LPVOID pParam){子线程的任务代码...return 0;}要创建子线程,可以在主线程中调用AfxBeginThread函数。
例如:CWinThread* pThread = AfxBeginThread(MyThreadFunction, pParam);这将创建一个新的子线程,并启动执行MyThreadFunction函数。
参数pParam是可选的,可根据实际需要进行传递。
第二步:等待子线程退出函数主线程需要等待子线程执行完毕后才能继续执行。
MFC 消息类型(详解)1、命令消息(WM_COMMAND)所有派生自 CCmdTarget 的类都有资格接受WM_COMMAND。
2、Window消息(WM_xxx)所有派生自 CWnd 的类都有资格接受 WM_xxx。
3、控件消息(WM_NOTIFY)控件向其父窗口通知消息。
三、消息处理1、WM_xxx 消息处理窗口类(自身)处理→基类处理→CWnd∷DefWindowProc()处理;其所对应的宏一般为在消息 WM_ 前面加上 ON_。
2、命令消息处理命令消息来自命令用户接口对象(菜单、加速键或工具栏按钮)发出的WM_COMMAND消息;㈠、WM_COMMAND消息其所包含的类型和对应的宏如下:①、ON_COMMAND(ID,pfn)标准的命令消息;②、ON_COMMAND_EX(ID,pfn)多个对象对同一个命令 ID 的处理;其函数的原型如下:afx_msg BOOL pfn(UINT nID)说明:当返回 TRUE 时表示已经处理,不用在消息处理链中继续处理该命令;为 FALSE 时表示继续在消息处理链中处理该命令。
注意:其一:在多对象处理中一定要使用该宏;其二:pfn(UINT nID)(消息处理函数)返回值将其类型void改成BOOL,而且必须为FALSE;其三:多个对象的处理是由高层向低层的过程:即视图类→主框架窗口类→应用程序类;③、ON_COMMAND_RANGE(nID,nLastID,pfn)多个命令 ID 提供相同的处理;注意:其一:确保nID、nLastID的值在 Resource.h 中是连续的。
其二:一般在函数 pfn(UINT nID) 中加入参数,用来确定那一个按钮点击。
㈡、CN_UPDATE_COMMAND_UI消息当菜单项、工具栏按钮等[命令用户接口对象]要更新其状态时所对应的消息,它所包含的类型和对应的宏如下:①、ON_UPDATE_COMMAND_UI(ID,pfn)其中函数的原型如下:afx_msg void pfn(CCmdUI* pCmdUI)②、ON_UPDATE_COMMAND_UI_RANGE(nID,nLastID,pfn)该函数可以处理一组[命令用户接口对象]的外观;其中函数的原型如下:afx_msg void pfn(CCmdUI* pCmdUI)重要:CCmdUI 中的 m_nID 成员表示不同的 ID,因此可以利用它来进行区别处理。
MFC启动和关闭线程1、启动线程:CWinThread* AfxBeginThread( 线程函数,this );2、通常导致线程终⽌的两种情况是:控制函数退出或不允许线程完成运⾏。
如果字处理器使⽤后台打印线程,若成功完成打印,则控制函数将正常终⽌。
但是,如果⽤户要取消打印,后台打印线程则不得不提前终⽌。
本主题介绍如何实现每⼀种情况,以及在终⽌后如何获取线程的退出代码。
(1)正常线程终⽌对于辅助线程,正常线程终⽌很简单:退出控制函数并返回表⽰终⽌原因的值。
可以使⽤函数或 return 语句。
⼀般情况下,0 表⽰成功完成,但这取决于您⾃⼰。
对于⽤户界⾯线程,该过程也很简单:从⽤户界⾯线程内调⽤ Platform SDK 中的。
PostQuitMessage 采⽤的唯⼀参数是线程的退出代码。
对于辅助线程,0 通常表⽰成功完成。
(2)过早的线程终⽌过早终⽌线程⼏乎⼀样简单:从线程内调⽤。
将所需的退出代码作为唯⼀参数传递。
这将停⽌执⾏线程、解除对线程堆栈的分配、分离附加到线程的所有 DLL 并从内存中删除线程对象。
必须从要终⽌的线程内调⽤ AfxEndThread。
如果要从其他线程终⽌线程,必须设置两个线程间的通信⽅法。
举⼀个例⼦:可以创建⼀个信号量,⽤WaitForSingleObject函数来检测该信号量的状态。
成员变量 m_hThreadEvent;m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );线程的执⾏函数:for( ; ;){DWORD dwRetVal;dwRetVal = WaitForSingleObject( m_hThreadEvent, 100 );if ( dwRetVal == WAIT_TIMEOUT ){// TODO:}else{// stop receive text thread.DWORD dwExitCode;GetExitCodeThread( m_pThreadRecv->m_hThread, &dwExitCode );AfxEndThread( dwExitCode, TRUE );}}要结束线程时,使⽤SetEvent,将信号量置为有信号。
MFC常用类及其成员函数CRuntimeClass结构在CRuntimeClass结构中定义了类名、对象所占存储空间的大小、类的版本号等成员变量及动态创建对象、派生关系判断等成员函数。
每一个从CObject 类派生的类都有一个CRuntimeClass结构同它关联,以便完成在运行时得到对象的信息或基类的信息。
要使用CRuntimeClass结构,必须结合使用RUNTIME_CLASS()宏和其他有关运行时类型识别的MFC宏。
CCmdTarget类(1)消息发送MFC应用程序为每个CCmdTarget派生类创建一个称为消息映射表的静态数据结构,可将消息映射到对象所对应的消息处理函数上。
(2)设置光标BeginWaitCursor() 将光标改为沙漏形状;EndWaitCursor() 将光标改回到之前的形状;RestoreWaitCursor()用于将光标还原为等待状态。
(3)支持自动化CCmdTarget类支持程序通过COM接口进行交互操作,自动翻译COM接口的方法。
CWinThread类由CCmdTarget派生,主要工作是创建和处理消息循环。
CWinApp类从CWinThread类派生,成员函数InitApplication()、InitInstance()、Run()。
在InitInstance()函数中,创建了一个单文档模板类或多文档模板类(CDocTemplate)的对象,并且在文档模板的构造函数中,系统定义的宏RUNTIME_CLASS创建了文档类对象,框架窗口类对象和视图类对象.在MFC应用程序中有且仅有一个CWinApp派生类的对象,代表程序运行的主线程,代表应用程序本身。
CWnd类由CCmdTarget类直接派生,是MFC中最基本的GUI对象。
公共变量m_hWnd 用于存放供API函数调用的窗口句柄。
CframeWnd类从CWnd类派生而来,主要用来掌管一个窗口。
其对象是一个框架窗口,包括边界、标题栏、菜单、最大化按钮、最小化按钮和一个激活的视图。
mfc 参数传递
(原创版)
目录
1.MFC 参数传递简介
2.MFC 参数传递的方式
3.MFC 参数传递的优点
4.MFC 参数传递的缺点
5.MFC 参数传递的实际应用
正文
一、MFC 参数传递简介
MFC(Microsoft Foundation Class)是微软提供的一个用于开发Windows 应用程序的类库。
MFC 参数传递是指在 MFC 程序中,如何将数据从一个对象传递到另一个对象的过程。
参数传递在 MFC 中具有重要作用,它使得程序员能够方便地管理和操作对象之间的数据。
二、MFC 参数传递的方式
在 MFC 中,参数传递主要有以下几种方式:
1.构造函数传递:通过构造函数将数据传递给对象。
这种方式适用于对象的初始化,通过传递的参数来设定对象的初始状态。
2.成员函数传递:通过成员函数将数据传递给对象。
这种方式适用于在对象创建后,通过调用成员函数来修改对象的状态。
3.指针和引用传递:通过指针或引用将数据传递给对象。
这种方式适用于传递临时数据,或用于对象之间的数据共享。
4.存储类和类型转换:通过存储类和类型转换将数据传递给对象。
这种方式适用于处理不同类型的数据,或将数据从一个对象传递到另一个对
象。
三、MFC 参数传递的优点
1.灵活性:MFC 参数传递提供了多种方式,可以根据实际需求选择合适的传递方式。
2.封装性:MFC 参数传递可以有效地封装对象内部的数据,使得外部程序无法直接访问,提高了数据的安全性。
3.可维护性:MFC 参数传递使得对象之间的数据传递更加清晰,有利于程序的维护和调试。
四、MFC 参数传递的缺点
1.复杂性:MFC 参数传递涉及到构造函数、成员函数、指针和引用等多个概念,增加了程序的复杂性。
2.内存管理:MFC 参数传递过程中,需要处理好数据的内存管理,避免内存泄漏等问题。
五、MFC 参数传递的实际应用
在 MFC 程序开发中,参数传递被广泛应用于各类控件、对话框和窗口等对象之间。