//
/*
这个例子比较复杂,需要放到专门的编译器中去看,建议使用VS查看
在后面的帖子中有一个简单的例子说明回调函数的用法,比较清楚,可以参看
*/
//主函数调用:
int _tmain(int argc, _TCHAR* argv[])
{
Init();
........
AddFileDriver(MiddleWare,NULL);
......
_getch();
return 0;
}
//
//AddFileDriver的代码
//加载底层驱动程序。典型的回调函数使用<驱动程序DiskCommand通过AddFileDriver获取参数Parameter信息>
//个人认为可以改成更通用的形式:AddFileDriver(int8 (* DiskCommand)(void *Parameter), void *RsvdForLow)
//其中参数:Parameter可以获取调用时的动态信息,比如:命令字、要操作的扇区
// RsvdForLow可以获取程序运行过程中的静态信息,比如:固定的磁盘信息
// 注意:Parameter,RsvdForLow传递到DiskCommand函数中具体使用时都要强制类型转化
//Parameter 用于向驱动函数<DiskCommand指向的函数>传递信息,Parameter->RsvdForLow 获取外部的其他辅助信息
void AddFileDriver(int8 (* DiskCommand)(int8 Command, void *Parameter), void *RsvdForLow)
{
//1.检测是否有初始化程序<防止传递空参数>,初始化是否成功<物理磁盘是否可操作>
//2.获取当前第一个空闲逻辑盘并挂接<也就是将物理磁盘转化为系统内部表示法以便操作>
//3.检测是否挂接成功。失败:退出。成功:读取物理磁盘0扇区(启动扇区)的值
//4.根据启动扇区数据重新设置逻辑盘参数(第一次有意义的初始化)
//**此时需要判断磁盘是否正确格式化了,如果没有格式化(Format),那么此时需要运行Format程序
int8 Buf[SECSIZE] = {0}; //存储一个扇区的内容
Disk_Info *Disk = NULL;
Disk_RW_Parameter Pa;
Pa.TempVal = 0; //初始化,无意义
Pa.SectorIndex = 0; //初始化,无意义
Pa.RsvdForLow = RsvdForLow; //相关辅助信息,有可能用到,如果调用函数RsvdForLow = NULL,那么这个参数也就无意义
Pa.Buf = Buf; //便于调用驱动函数运行时产生的数据,一般是磁盘读写数据的缓存
Pa.Drive = EMPTY_DRIVE; //初始化,当前使用的逻辑盘符
if (DiskCommand == NULL) // 参数无效退出
{
return;
}
//先挂接再初始化,把流程中所说的1和2有所颠倒,为了统一接口
Disk = GetEmptyDiskInfoAddr();
if (Disk == NULL)
{
return;
}
//Disk是指向全局变量DiskInfo_G的指针,对其赋值可以把信息保留到程序运行完毕
//因此把程序运行过程中一直需要使用的信息传给Disk->RsvdForLow和Disk->DiskCommand
//Disk->DiskCommand 一般指向驱动函数,Disk->RsvdForLow 指向主函数中传递过来的信息
Disk->RsvdForLow = RsvdForLow; //接收辅助信息
Disk->DiskCommand = DiskCommand; //指向驱动程序
Pa.Drive = Disk->Drive;
if (Disk->DiskCommand(DISK_INIT, &Pa) != DISK_INIT_OK) // 底层驱动初始化不成功退出
{
return;
}
//读取0扇区的数据,初始化DiskInfo_G[Drive]
Pa.SectorIndex = 0;
if(Disk->DiskCommand(DISK_READ_SECTOR, &Pa) != DISK_READ_OK)
{
return;
}
#ifdef NF_FORMAT //如果没有没有格式化便格式化
if(FSMount(Disk, Buf) != RETURN_OK)
{
Format(Disk->Drive);
if(FSMount(Disk, Buf) != RETURN_OK)
return;
}
#else
FSMount(Disk, Buf);
#endif
}
//****************Disk_RW_Parameter的结构如下***********************//
typedef struct _Disk_RW_Parameter
{
int32 TempVal; /* 用于传递函数需要的参数或者将函数调用后产生的值传出来 */
/* 常用于传递一个需要操作的函数或者传回函数调用后产生的值*/
uint32 SectorIndex; /* 操作的扇区,当向下传递一个参数的时候也可以使用TempVal替代 */
void *RsvdForLow; /* 保留给底层驱动程序,由_Disk_Info中拷贝过来 */
int8 *Buf; /* 数据存储位置 */
int8 Drive;
}Disk_RW_Parameter;
//************************************************************************************************************************************//
//
//MiddleWare的代码
int8 MiddleWare(int8 Command, void *Parameter)
{
uint8 state; //用于返回值,表示函数操作完毕之后的状态
Disk_RW_Parameter * Dp; //用于接收加载驱动时传递的参数
Dp = (Disk_RW_Parameter *)Parameter;
// 如果所要求的命令没有在这里实现,则state = BAD_DISK_COMMAND
switch (Command)
{
default:
state = BAD_DISK_COMMAND;
break;
case DISK_INIT:
// 初始化驱动程序,必须实现 //
// Parameter没有使用 //
//state= DISK_INIT_OK 或 DISK_INIT_NOT_OK
//state = PHDisk_Initialize();为了明确显示采用以下方式:
if(PHDisk_Initialize() == PH_DISK_INIT_OK)
state = DISK_INIT_OK;
else
state = DISK_INIT_NOT_OK;
break;
case DISK_READ_SECTOR:
// 读物理扇区,必须实现 //
// Dp->Buf:存储读到的数据 //
// Dp->SectorIndex:物理扇区索引 //
// state=DISK_READ_OK或DISK_READ_NOT_OK//
if(PHDiskReadSec(Dp->SectorIndex, Dp->Buf) == PH_DISK_READ_OK)
state = DISK_READ_OK;
else
state = DISK_READ_NOT_OK;
break;
.......
.......
}
return state;
}
注意红色和大字体部分,可以放到VS中去看,网页上显示的比较乱!
之所以贴出代码是因为这段代码实在是太经典了,用好
void AddFileDriver(int8 (* DiskCommand)(int8 Command, void *Parameter), void *RsvdForLow)
中的void *Parameter和void *RsvdForLow,可以实现强大的变参函数。而且函数接口具有良好的扩展性。
//使用函数指针构造回调函数
//在一个单链表中查找一个指定的值(*value)
search_list(Node *node, void const *value, int (*compare)(void const *, void const *) )
{
while(node != NULL)
{
if(compare(&node->value, value) == 0 )
break;
node = node->link;
}
return node;
}
//函数的定义
int compare_ints (void const *a, void const *b)
{
if(*(int*)a == *(int*)b )
return 0;
else
return 1;
}
//回调函数的使用
desired_node = search_list(root, &desired_value, compare_ints);
***这是一个简单的例子,虽然说明了回调函数的构造方法和使用,但是只是个简单的应用,还没有完全体现出来回调函数的强大功能。这个函数的扩展性很好,大家可以看见传递的参数都是(void*),也就是一个通用性指针,可以指向任意类型。但是没有体现出来被调用函数可以从回调函数接收参数这一点,但是在第一个例子中具有这种思想(在回调函数AddFileDriver(...)中给(Disk_RW_Parameter Pa) 赋值,然后再传给被调用函数MiddleWare(...),也就是*DiskCommand指向的函数)