1.系统线程和KSystemThread类
在DriverWorks包装类库中有一个叫做KSystemThread的类,可以用来创建线程,线程函数可以是标准的驱动系统线程例程函数,也可以是任意对象的成员函数.感觉用起来还是比较舒服的.下面分别说明.
1.1 使用标准线程例程创建系统线程
KSystemThread thdobj;
......
VOID ThreadProc(PVOID Context)
{
KSystemThread *pthdobj=(KSystemThread*)Context;
PVOID pMyContext=pthobj->GetParameter();
pthdobj->Terminate(STATUS_SUCCESS);
}
可以通过这样的语句启动系统线程:
thdobj.Start(ThreadProc,pMyContext);
可能有点晕了吧,呵呵,其实看一下Start的代码就知道为什么了
NTSTATUS KSystemThread::Start(
PKSTART_ROUTINE ThreadMain,
PVOID ThreadParam,
ULONG Access);
Start将ThreadParam保存到一个成员m_parameter里,然后用this代替Context,调用PsCreateSystemThread
status = PsCreateSystemThread(
&m_Handle,
Access,
NULL,
NULL,
NULL,
ThreadMain,
this
);
而GetParameter函数是这样的:
inline PVOID KSystemThread::GetParameter(void)
{
return m_parameter;
}
所以我们可以正常访问到pMyContext.
KSystemThread::Terminate的底层设置一些状态变量值后调用PsTerminateSystemThread结束结程.
其实这里不追看底层代码还好一点,看了反而有点昏,我觉得关于KSystemThread类还是看DriverWorks里的描述和上面的那段示例代码就够了,我只是想学会在DDK的非面向对象层面里怎么使用系统线程.
1.2 使用对象成员函数创建系统线程
上面的代码可以看出并没有发挥出面向对象的强大优秀,我觉得好一点的用法是从KSystemThread派生一个类,添加一些成员变量当做参数,最后在线程里直接把Context转成对象指针后可以直接使用它的成员变量.
然而,我们有更好的方法来创建系统线程,就是将一个类的成员函数做为线程函数:
通常要在类里加上MEMBER_THREAD定义
MEMBER_THREAD(
object_class,
function_name
);
object_class是指对象类名,function_name是成员函数,它的原形必须是这样的:
VOID function_name(void)
类的定义就像下面这样
class myobject:public ......
{
....
MEMER_THREAD(myobject,ThreadProc);
KSystemThread m_thread;
void StartThread(void);
};
在类的成员函数StartThread里启动线程:
void myobject:StartThread()
{
Start(LinkTo(ThreadProc),this);
}
而在类的成员函数ThreadProc中:
VOID myobject:ThreadProc()
{
//访问成员变量,做工作
m_thread.Terminate();
}
在这里我不打算再接露这是如何做到的,可能说了你会感觉更昏,就从使用系统线程的角度来说,解释到这里已经够了.
KSystemThread还有其它的成函数可以调用的,比如:
SetPriority:设置运行时优先
ExitStatus:取得线程退出代码
...等等.
因为KSystemThread由KDispatcherObject派生而来,我们可以调用Wait和WaitMultiple等函数来等待.
2.同步对象
在DirverWorks里有好几个包装好的同步对象,它们都派生KDispatcherObject,也就是说它们都可以通过名字来初使化,这样就有机会与应用程序做同步.
通常在ring3的应用程序创建一个命名的全局同步对象,然后驱动程序打开这个对象,这样应用程序和驱动程序都可以读写对象状态(并且应用程序和驱动程序都可以等待同步对象).
例如:
在驱动程序中创建一个事件对象
KEvent EventObj(L"\\BaseNamedObjects\\XyzSynch", SynchronizationEvent);
在应用程序中刚可以打开这个事件对象
HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, "XyzSynch");
然后应用程序等在这个事件对象上,当防火墙驱动程序(假如是一个NDIS Hook Driver)发现有进程启图连接出去,它可以将事件设置成信号态,这样应用程序的等待线程会返回,它可以调用ReadFile来与驱动交互读取数据,驱动在IRP_MJ_READ里将进程ID和连接地址,端口返回给应用程序,应用程序弹出提示信息,等用户确定后,驱动放行或是丢失掉连接请求.
另外,还有KTimer,KSemaphore,KMutex等也可以用来同步,具体的可以参考DriverWorks帮助文档.
3.实例
//驱动代码:
//threads.cpp
#define VDW_MAIN
#define DRIVER_FUNCTION_UNLOAD
#include
#define EVENT_NAME L"\\BaseNamedObjects\\{F2C91027-1DB5-41a3-B29B-E0240A3F4C97}"
class ThreadDriver:public KDriver
{
SAFE_DESTRUCTORS;
public:
MEMBER_THREAD(ThreadDriver,ThreadProc);
VOID Unload();
NTSTATUS DriverEntry(IN PUNICODE_STRING RegistryPath);
KSystemThread m_thread;
KEvent m_SynchEvent;
};
DECLARE_DRIVER_CLASS(ThreadDriver,NULL)
NTSTATUS ThreadDriver::DriverEntry(IN PUNICODE_STRING RegistryPath)
{
DbgPrint(__FUNCTION__);
KUstring EventName(EVENT_NAME);
m_SynchEvent.Initialize(EventName,SynchronizationEvent);
m_thread.Start(LinkTo(ThreadProc),this);
return STATUS_SUCCESS;
}
VOID ThreadDriver::Unload()
{
DbgPrint(__FUNCTION__":Wait thread to quit...\n");
m_thread.Wait();
DbgPrint(__FUNCTION__":thread terminated\n");
}
VOID ThreadDriver::ThreadProc()
{
DbgPrint(__FUNCTION__":Wait Event state...\n");
m_SynchEvent.Wait();
DbgPrint(__FUNCTION__":thread Terminated...\n");
m_thread.Terminate(STATUS_SUCCESS);
}
//应用程序代码
//unit1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
syncobjs, StdCtrls;
type
TForm1 = class(TForm)
btnSignal: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure btnSignalClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
var
event:TEvent;//使用事件对象
procedure TForm1.FormCreate(Sender: TObject);
begin
//创建一个非手工重置和初使为非信号态的全局事件,使用GUID做名字,它和驱动里的是一样的
event:=TEvent.Create(nil,False,False,'Global\{F2C91027-1DB5-41a3-B29B-E0240A3F4C97}');
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
event.Free;
end;
procedure TForm1.btnSignalClick(Sender: TObject);
begin
//当按下按钮时,调事件设置成信号态
event.SetEvent;
ShowMessage('已发信');
end;
end.
启动应用程序后,再启动驱动程序,驱动会创建一个系统线程,然后ThreadProc会等待事件成信号态,而Unload会等待系统线程对象成信号态(退出后)才会返回.驱动一定要在应用程序后启动,因为要应用程序先创建全局事件,m_SynchEvent.Initialize才会返回这个事件的实例,才可以同步,否则m_SynchEvent.Initialize会直接创建一个事件.
就到这里吧,好累哦!唉!努力哦!只想多学点东西,但愿不要学无用处......