以下大部分内容是从网上摘录的

原文如下:
Modify BusEnum to support asynchronous driver loading
a.      Currently, the BuiltIn drivers are loaded by BusEnum.dll in a single thread. BusEnum was designed to be able to call itself. BusEnum can load other bus drivers to enumerate other buses (e.g. PCI, USB, PCCard, SD, etc). We can have BusEnum to load itself with a different bus name.
b.      Add Flags bit for asynchronous driver loading (devload.h)
i.     DEVFLAGS_LOAD_ASYNC              // load driver in a separate thread
c.      Add the registry for asynchronous bus
; BusEnum for AsyncBus. Second instance of BusEnum.dll. Launch a separate thread if DEVFLAGS_LOAD_ASYNC is set.
[HKLM\Drivers\BuiltIn\AsyncBus]
“Dll”=”BusEnum.dll”
“BusName”=”AsyncBus”
“Order”=dword:10
“Flags”=dword: DEVFLAGS_NAKEDENTRIES          ; can have DEVFLAGS_LOAD_ASYNC set if needed
“StartEvent”=”AsyncGroup”      ; waiting for this event before loading. Load immediately if not set.
d.      Change the code in BusEnum around ActivateEx() call.
if(GetLoadFlag() & DEVFLAGS_LOAD_ASYNC)
{
        ; create a thread to call ActivateDeviceEx(). The thread will first wait for the StartEvent then call ActivateDeviceEx().      
}
else
{
m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
}
e.      Identify the drivers to be put in the asynchronous loading group.
f.       Change the registry for drivers to be loaded asynchronously by replacing [HKLM\Drivers\BuiltIn\xxx] to [HKLM\Drivers\BuiltIn\AsyncGroup\xxx]
g.      Write an application to set the StartEvent event after the OS boot is complete to load the drivers in asynchronous group.

 

这个文章讲述的是如何利用BusEnum可以Active自己的特性,把一部分不是启动的时候必须的流驱动延迟到任何时间加载(依然可以用order来控制顺序,只是可以滞后到explorer跑起来后开始)。


原理是这样的,默认的device.exe只加载一个流驱动,它就是busenum.dll,然后其他的流驱动是靠busenum.dll去遍历和Active(加载)的。因为busenum.dll也是流驱动接口的,所以它自己也可以被自己Active,上文就是利用了这个特点,对busenum.dl做了一个微妙的改动,实现了我们可以对流驱动的分批加载,让最关键的dll在出现桌面前加载,其他的都滞后,让用户可以在较短时间见到桌面。


下面来解析实现的具体原理:
默认的,你的注册表肯定有下面的项目:
[HKEY_LOCAL_MACHINE\Drivers]
    "RootKey"="Drivers\\BuiltIn"
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn]
    "Dll"="BusEnum.dll"
    "BusName"="BuiltIn"
    "Flags"=dword:8
    "BusIoctl"=dword:2a0048
    "InterfaceType"=dword:0
    "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"


设备管理器Device.exe在初始化的时候会去读上面的rootkey,然后自己加载rootkey指向的那个驱动,这里就是[HKEY_LOCAL_MACHINE\Drivers\BuiltIn],所以在这里busenum.dll就跑起来了。详细的代码自己可以去private下面check,懒的可以看我借用的一篇文章 http://www.armce.cn/bbs/thread-35-1-1.html ,它分析了device.exe的初始化过程,最下一行很有意思。


接下来busenum.dll会开始遍历它键值下面的流驱动并一一加载。比如:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SDMEMORY]
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\NAND]
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PowerButton]
所以类似的,如果你把BusEnum.dll放到[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\hStartEvent]下面并且把她Active起来,它就会去加载所有[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\hStartEvent\*****]键值下的流驱动。


所以我们只要放两个BusEnum.dll到不同的键值就实现了流驱动的分批问题。

 

刚才有讲,BusEnum.dll(后启动的)自己是可以被当做普通的流驱动被BusEnum.dll(先启动的,device加载)加载的,比如下面的键值。
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus]
  "Dll"="BusEnum.dll"
  "BusName"="AsyncBus"
  "Order"=dword:10;
  "Flags"=dword:0  
    "BusIoctl"=dword:2a0048
    "InterfaceType"=dword:0
    "IClass"=multi_sz:"{B3CC6EBA-5507-4196-8E41-2BF42E4A47C9}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"


因为处于BuiltIn下面,所以肯定会被轮询到被加载。但是就简单这么写还不行,虽然它可以实现加载[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\****]的所有流驱动,但是时间上面它无法控制,它会立刻开始加载操作,无法实现我们从时间上的分批次加载驱动的目的,所以一楼的文章就介绍了一种方法,在上面的键值里面加一个flag,如下:
  "Flags"=dword:408  ; 0x400+0x8 (0x400 is the asyncbus flag)


通过修改busenum.dll的源码,让这个flag会在第二个busenum.dll被加载的时候被第一个busenum读到,我们的例子里面加入的0x400就是代码里面宏定义DEVFLAGS_LOAD_ASYNC的值,第一个busenum就可以判断这个标志不立刻走正常的遍历和加载它,延迟第二个busenum的启动。


下面是一段修改devbus.cpp的一个sample,不去ActivateDeviceEx,而是去调用线程等待启动信号。
if(GetLoadFlag() & DEVFLAGS_LOAD_ASYNC)
{
        HANDLE hAsyncLoadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) AsyncLoadThread, this, 0, NULL);      
}
else
{
m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
}


AsyncLoadThread的线程里面去做类似下面的事情,等待一个hStartEvent事件,以便开始加载第二个busenum.dll. hStartEvent事件要你自己手动去发,比如你可以在explorer.exe起来之后调用一个AP去发这个自定义事件。


WaitForSingleObject(hStartEvent, INFINITE);
NKDbgPrintfW(L"[busenum]Start load %s\r\n",m_lpTemplateRegPath);
   m_hDevice = ActivateDeviceEx(m_lpTemplateRegPath, m_dwInitRegArray,  (m_dwInitRegArray!=NULL?m_dwInitRegCount:0) , NULL);
         m_fDriverLoaded = (m_hDevice!=NULL);


当你的AP调用SetEventhStartEvent)后,第二个busenum.dll就开始加载路径位于[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\AsyncBus\****]下的所有驱动,order依然有效。