c# 用Windows API CreateThread函数如何创建的线程

作者&投稿:宁面 (若有异议请与网页底部的电邮联系)
WINAPI里的CreateThread函数~

传给CreateThread的函数,必须是全局函数或静态函数,不能使用类的普通函数
即,你可以使用如下函数声明:
static DWORD WINAPI Run(LPVOID LpParameter);
因为类的普通函数会传递类对象指针作为隐含参数,所以与CreateThread所要求的函数类型不匹配

CWinThread

CObject
└CCmdTarget
└CWinThread

CWinThread对象代表在一个应用程序内运行的线程。运行的主线程通常由CWinApp的派生类提供;CWinApp由CWinThread派生。另外,CWinThread对象允许一给定的应用程序拥有多个线程。

CWinThread支持两种线程类型:工作者线程(Worker Thread)和用户界面线程(UI thread)。工作者线程没有收发消息的功能(没有消息队列):例如,在电子表格应用程序中进行后台计算的线程。

用户界面线程具有收发消息的功能,并处理从系统收到的消息。CWinApp及其派生类是用户界面线程的例子。其它用户界面线程也可由CWinThread直接派生。

CWinThread类的对象存在于线程的生存期。如果你希望改变这个特性,将m_bAutoDelete设为FALSE。

要使你的代码和MFC是完全线程安全的,CWinThread类是完全必要的。框架使用的用来维护与线程相关的信息的线程局部数据由CWinThread对象管理。由于依赖CWinThread来处理线程局部数据(Thread
Local Storage),任何使用MFC的线程必须由MFC创建。例如,由运行时函数_beginthreadex创建的线程不能使用任何MFC
API。

为了创建一个线程,调用AfxBeginThread函数。根据你需要工作者线程还是用户界面线程,有两种调用AfxBeginThread的格式。如果你需要用户界面线程,则将指向你的CWinThread派生类的CRuntimeClass的指针传递给AfxBeginThread。如果你需要创建工作者线程,则将指向控制函数的指针和控制函数的参数传递给AfxBeginThread。对于工作者线程和用户界面线程,你可以指定可选的参数来修改优先级,堆栈大小,创建标志和安全属性。

AfxBeginThread线程将返回指向新的CWinThread对象的指针。
与调用AfxBeginThread相反,你可以构造一个CWinThread派生类的对象,然后调用CreateThread。如果你需要在连续创建和终止线程的执行之间重复使用CWinThread对象,这种两步构造方法非常有用。

CWinThread类成员

数据成员

m_bAutoDelete 指定线程结束时是否要销毁对象
m_hThread 当前线程的句柄
m_nThreadID 当前线程的ID
m_pMainWnd 保存指向应用程序的主窗口的指针
m_pActiveWnd 指向容器应用程序的主窗口,当一个OLE服务器被现场激活时

构造函数

CWinThread 构造一个CWinThread对象
CreateThread 开始一个CWinThread对象的执行

操作

GetMainWnd 查询指向线程主窗口的指针
GetThreadPriority 获取当前线程的优先级
PostThreadMessage 向另外的CWinThread对象传递一条消息
ResumeThread 减少一个线程的挂起计数
SetThreadPriority 设置当前线程的优先级
SuspendThread 增加一个线程的挂起计数

可重载函数

ExitInstance 重载以进行线程终止时的清理工作
InitInstance 重载以实现线程实例的初始化
OnIdle 重载以进行线程特定的空闲操作
PreTranslateMessage 在消息被发送到Windows函数TranslateMessage和DispatchMessage之前过滤消息
IsIdleMessage 检测特定的消息
ProcessWndProcException 截获线程消息和命令处理函数出现的所有未处理的异常
ProcessMessageFilter 在特定的消息到达应用程序之前截获消息
Run 线程的具有消息收发功能的控制函数,可重载以定制缺省的消息循环

AfxBeginThread和CreateThread具体区别

具体说来,CreateThread这个 函数是windows提供给用户的 API函数,是SDK的标准形式.
AfxBeginThread,是编译器对原来的CreateThread函数的封装,用与MFC.
而_beginthread是C的运行库函数。
在使用AfxBeginThread时,线程函数的定义为:UINT _yourThreadFun(LPVOID pParam)
在使用CreateThread时,线程的函数定义为: DWORD WINAPI _yourThreadFun(LPVOID pParameter)。

两个的实质都是一样的,不过AfxBeginThread返回一个CWinThread的指针,就是说他会new一个CWinThread对象,而且这个对象是自动删除的(在线程运行结束时),给我们带来的不便就是无法获得它的状态,因为随时都有可能这个指针指向的是一个已经无效的内存区域,所以使用时(如果需要了解它的运行状况的话)首先CREATE_SUSPENDED让他挂起,然后m_bAutoDelete=FALSE,接着才ResumeThread,最后不要了delete那个指针。

CreatThread就方便多了,它返回的是一个句柄,如果你不使用CloseHandle的话就可以通过他安全的了解线程状态,最后不要的时候CloseHandle,Windows才会释放资源(线程内核对象).
下面我们就来看一下AfxBeginThread函数的内部实现:

复制代码 代码如下:
//启动worker线程
CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
int nPriority, UINT nStackSize, DWORD dwCreateFlags,
LPSECURITY_ATTRIBUTES lpSecurityAttrs)
{
ASSERT(pfnThreadProc != NULL);

CWinThread* pThread = DEBUG_NEW CWinThread(pfnThreadProc, pParam);
ASSERT_VALID(pThread);

if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
lpSecurityAttrs))
{
pThread->Delete();
return NULL;
}
VERIFY(pThread->SetThreadPriority(nPriority));
if (!(dwCreateFlags & CREATE_SUSPENDED))
VERIFY(pThread->ResumeThread() != (DWORD)-1);
return pThread;
}

//启动UI线程
CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,int
nPriority, UINT nStackSize, DWORD dwCreateFlags, LPSECURITY_ATTRIBUTES
lpSecurityAttrs)
{

ASSERT(pThreadClass != NULL);
ASSERT(pThreadClass->IsDerivedFrom(RUNTIME_CLASS(CWinThread)));
CWinThread* pThread = (CWinThread*)pThreadClass->CreateObject();
if (pThread == NULL)
AfxThrowMemoryException();
ASSERT_VALID(pThread);
pThread->m_pThreadParams = NULL;
if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,
lpSecurityAttrs))
{
pThread->Delete();
return NULL;
}
VERIFY(pThread->SetThreadPriority(nPriority));
if (!(dwCreateFlags & CREATE_SUSPENDED))
VERIFY(pThread->ResumeThread() != (DWORD)-1);
return pThread;
}

主要创建函数是
复制代码 代码如下:
pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize,lpSecurityAttrs))

也就是
复制代码 代码如下:
CWinThread::CreateThread

CreateThread
  微软在Windows API中提供了建立新的线程的函数CreateThread,
  概述:
  当使用CreateProcess调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:
  1在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回
  2把线程退出码置为STILL_ACTIVE,把线程挂起计数置1
  3分配context结构
  4分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD
  5lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数
  6把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数
  MSDN中CreateThread原型:
  HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  DWORD dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId);
  参数说明:
  lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL,表示使用缺省值。
  dwStackSize,线程堆栈大小,一般=0,在任何情况下,Windows根据需要动态延长堆栈的大小。
  lpStartAddress,指向线程函数的指针,形式:@函数名,函数名称没有限制,但是必须以下列形式声明:
  DWORD WINAPI ThreadProc (PVOID pParam) ,格式不正确将无法调用成功。
  lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为Nil。
  dwCreationFlags :线程标志,可取值如下
  CREATE_SUSPENDED: 创建一个挂起的线程
  0 :创建后立即激活。
  lpThreadId:保存新线程的id。
  返回值:
  函数成功,返回线程句柄;函数失败返回false。
  函数说明:
  创建一个线程。
  语法:
  hThread = CreateThread (&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ;
  一般并不推荐使用 CreateTheard函数,而推荐使用RTL 库里的System单元中定义的 BeginTheard函数,因为这除了能创建一个线程和一个入口函数以外,还增加了几项保护措施。

  微软在Windows API中提供了建立新的线程的函数CreateThread。


  概述:
  当使用CreateProcess调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:

  1. 在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回

  2. 把线程退出码置为STILL_ACTIVE,把线程挂起计数置1

  3. 分配context结构

  4. 分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD

  5. lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数

  6. 把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数

  MSDN中CreateThread原型:
  HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  DWORD dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId); 


  参数说明:

  1. lpThreadAttributes:指向SECURITY_ATTRIBUTES型态的结构的指针。在Windows 98中忽略该参数。在Windows NT中,它被设为NULL,表示使用缺省值。

  2. dwStackSize:线程堆栈大小,一般=0,在任何情况下,Windows根据需要动态延长堆栈的大小。

  3. lpStartAddress,指向线程函数的指针,形式:@函数名,函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (PVOID pParam) ,格式不正确将无法调用成功。 

  4. lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为Nil。 

  5. dwCreationFlags :线程标志,可取值如下 

  6. CREATE_SUSPENDED: 创建一个挂起的线程 

  7. 0 :创建后立即激活。 

  8. lpThreadId:保存新线程的id。


    返回值:

    函数成功,返回线程句柄;函数失败返回false。

    函数说明:

    创建一个线程。

    语法:

  hThread = CreateThread (&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ;


  一般并不推荐使用 CreateTheard函数,而推荐使用RTL 库里的System单元中定义的 BeginTheard函数,因为这除了能创建一个线程和一个入口函数以外,还增加了几项保护措施。



C#里面的Thread类不是非常好用吗,还用这个干吗。


九龙坡区13272774421: windows api可以用于c#吗? -
凭费金薯: C#是微软的...API可以在C#上调用

九龙坡区13272774421: C#能直接调用windows api吗 -
凭费金薯: 你说的没错,java调用windows api很困难,vc++只是一个工具,你可以转向c#或者c++,直接操作windows api很容易的.

九龙坡区13272774421: C#编程中如何调用WIN32 API函数 -
凭费金薯: visual c#和其它开发工具一样也能够调用动态链接库的api函数..net框架本身提供了这样一种服务,允许受管辖的代码调用动态链接库中实现的非受管辖函数, 包括操作系统提供的windows api函数.它能够定位和调用输出函数,根据需要,组...

九龙坡区13272774421: c#怎样调用windows api 最好附有代码. -
凭费金薯: #region 调用API函数显示窗体 [DllImportAttribute("user32.dll")]private static extern Boolean ShowWindow(IntPtr hwnd, Int32 cmdShow); //该方法用来显示窗体#endregion user32.dll 是其中一个有API的文件,根据要调用的API不同,可以换不同的dll文件.下面的函数就是windows API里的函数,要声明才能用.声明每个API函数前都要加[DllImportAttribute("....")] ,不能只有一个[]

九龙坡区13272774421: C# Windows API函数怎么使用,举例说明? -
凭费金薯: //调用方法不难,但是自己要查清楚所调的函数的一些参数才能调 using System; using System.Runtime.InteropServices; class Program { [DllImport("User32.dll")]//引用你调用的API函数的DLL,这个自己可以在MS上查得到.一般就那几个DLL ...

九龙坡区13272774421: C#如何实现Windows API -
凭费金薯: 1、C#如何实现Windows API? 你这句话让人难以理解,你是想编WindowsAPI?那是不可能了.既然叫WindowsAPI,那就是给你用的,不是让你编的,这是一;WindowsAPI主要做一些操作系统底层或者对硬件的操作,托管代码无法越级直接...

九龙坡区13272774421: c#种怎么直接调用win32 api啊?? -
凭费金薯: 使用DIIImport特性可以指示CLR从哪个DLL导出想要调用的函数.GDI32.dll、Kernel32.dll和User32.dll是最常用的三个DLL.如果不确定哪个DLL定义了需要使用的WindowsAPI函数,可以参考PlateformSDK文档. 例子:(需要引入命名空间...

九龙坡区13272774421: c# 用Windows API CreateThread函数如何创建的线程 -
凭费金薯: 微软在Windows API中提供了建立新的线程的函数CreateThread. 概述: 当使用CreateProcess调用时,系统将创建一个进程和一个主线程.CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤: 1. 在内核对象中分配一个线...

九龙坡区13272774421: 在C#中如何使用WINDOWS API函数?
凭费金薯: 使用DLLImport . http://www.cnblogs.com/xumingming/archive/2008/10/10/1308248.html 这里有详细的例子. 希望对你有所帮助.

九龙坡区13272774421: C# 用不用学windows API? -
凭费金薯: 如果用C#开发WebForm(即:动态网页),那么基本可以不用Windows API. 但如果开发WinForm,则经常会遇到,因为任何一个开发工具,都不可能将所有Windows API都包装成Class.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网