均转自http://blog.csdn.net/njuitjf
一、如何在wince下实现一个文件系统驱动
应用程序操作文件是通过wince 文件系统提供的接口进行操作,如:可以通过CreateFile函数,打开或创建一个文件。接下来,系统是如何去完成这个任务的呢?比如我们要操作SD卡上的文件,SD卡上也有自己的文件系统,用于组织和管理文件,wince文件系统是如果操作这些文件的呢?这时候,FSD(文件系统驱动)就发挥它的作用了。文件的操作共涉及到五个层次:
1、应用程序:用户通过应用程序操作文件。
2、wince文件系统:操作系统的一部分,根据用户的请求,判断操作的是那个设备上的文件,以便调用相应的驱动。
3、文件系统驱动:操作系统没办法直接和设备驱动进行交互,需要通过文件系统驱动,实现与设备驱动的操作,以实现文件操作。
4、设备驱动:实现了设备上的操作,包括文件操作等。
5、设备上的文件系统:组织和管理设备上的文件存储。
从以上的分析可以知道,文件系统在操作系统和设备驱动之间起到了一个连接作用。在实现的时候,文件系统驱动基于设备驱动,实现了wince文件系统中的文件操作函数,如CreateFile等。
实现一个文件系统驱动,大致可以分为以下几步:
1、基于设备驱动,实现文件系统函数,如:CreateFile, WriteFile, ReadFile等等。实现的时候,函数的名字可以根据个人爱好随便定义。函数的实现放在一个动态连接库里面。
2、将定义的文件系统函数Export出去。Export出去的名字,就不能那么随便了,就像在家里面,你喊你老婆什么都可以,但是公布给外面的名字,就不能那么任意了。规则是所以的函数都要有一个固定的前缀,前缀后面就是标准的文件系统函数名。前缀可以自己定义,如MyFSD_,你只要在注册表里面说明你的文件系统驱动是这个前缀就行了。也可以使用一个默认的前缀--FSD,使用这个的话,就不用在注册表里面说明了,文件系统是知道的。
3、将文件系统驱动的代码文件添加到wince os的工程中。打开wince工程(ce5.0使用pb,ce6.0使用vs2005,此处以ce6.0为例),打开:PLATFORM/你的平台对应的文件夹/src/,右击src目录下的drivers,选择Add->New Sources Subproject,在提示框中选择动态链接库模板,然后一次操作...。
注:你也可以不进行这一步操作,完全可以单独建个动态链接库工程,编译生成动态链接库,然后将动态链接库包含到os中就行了。不过,我并没有进行过验证。
4、将文件系统驱动的注册表信息添加到wince的注册表中。如:
[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/MyFSD]
"Dll"="MyFSD.dll" // 驱动的名字,也就是实现的文件系统驱动,最后生成的动态链接库
"Paging"=dword:0 // 内存是否分页,0-不分页,1-分页。分页的话,则可以被提交到缓存,不分页的话,则不可以
"Folder"="MyDev" // 设备的跟目录名。应用程序在设计上进行文件操作时的根目录
"Prefix"="MyFSD" // 文件驱动函数的前缀
5、将文件系统驱动模块添加到os中。通过修改.bib文件来实现。如:
MyFSD.dll $(_FLATRELEASEDIR)/MyFSD.dll NK SHK
至此,文件系统驱动已经实现和添加完成,在设备Mount之后,就可以进行相应的文件操作了。
二、wince文件系统函数的调用过程
查了一下MSDN,在页面:http://msdn.microsoft.com/en-us/library/ee489755.aspx有如下内容:
Applications that access an installable file system use standard Win32 functions. For example, when an application creates a folder on a device that
contains an installable file system, it calls the CreateDirectory function. FSDMGR recognizes that the path is to a device containing an installable
file system and calls the appropriate function, which in the case of the MyFSD file system is MyFSD_CreateDirectoryW. That is, the application calls
CreateDirectory, causing FSDMGR to call MyFSD_CreateDirectoryW.
可见调用过程可以分为一下几步:
1、应用程序调用wince文件系统接口。
2、文件系统中的FSDMGR根据操作路径的根目录,判断需要使用哪个文件系统驱动。
3、找到相应的文件系统驱动后,调用文件系统驱动中对应的函数。
4、接下来,具体进行了什么操作,就要看FSD的实现了。
三、wince如何通知设备已经mount
应用程序怎样知道何时设备可以使用,即可以成功的在设备上进行文件操作,这就涉及到mount和mount通知的问题。这部分包括两个方面的内容:
1、mount的实现和通知。
2、获取mount的通知。
mount的实现和通知都是在FSD中实现的。FSD中Export出去的函数中,有一个是XXX_MountDisk函数,如MyFSD_MountDisk函数,该函数中通过向设备驱动发送命令实现mount,然后
调用函数FSDMGR_AdvertiseInterface通知mount。
获取mount的通知是在应用程序或者专门的监听程序中实现的,具体实现方法是:
1、创建一个message queue。
2、通过函数RequestDeviceNotifications将设备的GUID和message queue进行注册。
3、等待message queue中的消息,并进行处理。
示例代码如下:
// Define and set a queue options
MSGQUEUEOPTIONS sQueOpts;
sQueOpts.dwSize = sizeof( MSGQUEUEOPTIONS );
sQueOpts.dwFlags = MSGQUEUE_NOPRECOMMIT;
sQueOpts.dwMaxMessages = 0;
sQueOpts.cbMaxMessage = sizeof( DEVDETAIL );
sQueOpts.bReadAccess = TRUE;
// Create message queue
HANDLE hQueue = ::CreateMsgQueue( NULL, &sQueOpts );
// Requests notifications for the appearance and disappearance of device interfaces.
HANDLE hHandle = ::RequestDeviceNotifications( &UDFS_MOUNT_GUID, hQueue, TRUE );
if ( INVALID_HANDLE_VALUE == hHandle ) {
// Error process
return;
}
// Wait for event
DWORD dwRet = ::WaitForSingleObject( hQueue, INFINITE );
if ( WAIT_OBJECT_0 != dwRet ) {
// Error process
return;
}
// Normal process
四、wince write through
以前写过一个wince下面的性能测试工具,在进行文件读写操作的时候,创建文件,我同事使用了FILE_FLAG_WRITE_THROUGH和FILE_FLAG_NO_BUFFERING两个标志。后来有同事提出,wince下面不支持FILE_FLAG_NO_BUFFERING标志,所以也不支持文件的直接读写。
我当时的理解是,不支持FILE_FLAG_NO_BUFFERING标志,也就是说读写的时候一定有缓存区,也就没办法保证写入文件的数据会直接写到文件里面。
后来查了查资料,才发现自己理解有问题。虽然wince不支持FILE_FLAG_NO_BUFFERING,但是wince下面支持FILE_FLAG_WRITE_THROUGH,也就是说,虽然写的时候使用了缓存区,但是也可以保证写入的数据马上写入到了文件,而没有使用懒惰算法在那儿等待。MSDN中对FILE_FLAG_WRITE_THROUGH标志的说明如下:
Instructs the system to write through any intermediate cache and go directly to disk. The system can still cache write operations, but cannot lazily flush them