玩玩DriverWorks(四)-系统线程和同步对象

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会直接创建一个事件.

就到这里吧,好累哦!唉!努力哦!只想多学点东西,但愿不要学无用处......

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值