|
摘要:本文介绍用C/C++编制Visual FoxPro扩展程序库的基本要点,并给出一些参数传递的例子。
关键词:Visual FoxPro扩展程序库
Visual FoxPro的扩展程序库由C或C++编写,可以访问Visual FoxPro的“应用程序接口”(API),大大扩展了Visual
FoxPro的原有功能。本文即介绍编制扩展程序库的基本要点。
编制扩展程序库有一定的软件要求。首先,由于Visual FoxPro是一个32位的应用程序,所以必须使用一32位编译器来连编该程序库,笔者推荐使用Microsoft
VisualC++TM4.1版。其次需要Visual FoxPro“应用程序接口”的头文件(PRO_EXT.H)以及导入库(WINAPIMS.LIB),这两个文件均在Visual
FoxPro的API子目录下。
对于有C语言编程经验的程序员来说,写扩展程序库的难点在于要搞清:扩展程序库本身的框架、数据类型和数据结构以及扩展程序库与Visual
FoxPro环境的数据交换约定。下面主要介绍这三点。
一、 扩展程序库的基本结构
程序库由四部分组成:
1、#include 语句
#include <pro_ext.h>;
2、函数定义
void Function _ Name (ParamBlk*parm)
{
\\函数代码
}
3、FoxInfo结构
FoxInfo myFoxInfo[]\{
{"FUNCTION_N",(FPFI)Function_Name,
ParmCount,ParmTypes},
};
FoxInfo结构用于在Visual FoxPro和库之间传递函数名和参数描述信息。“myFoxInfo"为FoxInfo型的变量。注意在该数组中可以包含多个FoxInfo结构行。ParmCount指定在ParmTYpes字符串中描述的参数个数,或者下列标志值之一:
| 值 |
说明 |
| INTERNAL |
指明该函数不能直接从Visual FoxPro调用 |
| CALLONLOAD |
指明该函数在加载时调用。 |
| CALLONUNLOAD |
指明该函数的卸载库,或发出VisualFoxPro的QUIT命 令时调用 |
注:CALLONLOAD和CALLONUNLOAD均不能调用那些返回结果给Visual FoxPro的函数。
ParmTYpes描述每个参数的数据类型。下表列出ParmTYpes的有效值。
| 值 |
描述 |
| ““ |
无参数 |
| “?” |
能传递任意类型 |
| “C” |
字符型参数 |
| “D” |
日期型参数 |
| “I” |
整型参数 |
| “L” |
逻辑型参数 |
| “N” |
数值型参数 |
| “R” |
引用 |
| “T” |
日期时间型参数 |
| “Y” |
货币型参数 |
4、Foxtable 结构
FoxTable myFoxTable={
(FoxTable *)0,sizeof(myFoxInfo) /
sizeof(FoxInfo),myFoxInfo
}
该结构第一个参数是Visual FoxPro内部使用的一个指针,必须初始化为0;第二个参数是该程序库定义的Visual FoxPro外部例程数目;第三个参数实际为该程序库FoxInfo结构的变量名。如读者的FoxInfo型变量名为myFoxInfo,建议读者直接使用上面这个例子。
二、Visual FoxPro API数据类型与数据结构
1、数据类型
Visual FoxPro API定义的数据类型见下表:
| 数据类型 |
说明 |
| EDLINE |
用于编辑窗口中打开的文件,指明文件中某一行的行号,首行为1。 |
| EDPOS |
用于编辑窗口中打开的文件,指明文件中某个字符的偏移位置 。 |
| FCHAN |
文件通道。每个由Visual FoxPro打开的文件,或通过API用 _FCreate()和_FOpen()打开的文件,都被分配一个FAHAN
FPFI 指向一个返回一个整数值的函数的32位指针。 |
| ITEMID |
为菜单中某一命令指定的唯一标识。 |
| MENUID |
指定给一个菜单的唯一标识。 |
| MHANDLE |
一个唯一标识,每一个由Visual FoxProw分配的内存块,或通过API用_AllocHand()分配的内存块都具有这样一个标识。可以使用_HandToPtr()返回引用到它的指针。 |
| NTI |
名称表索引。每个内存变量和表字段的名称在该表中都有一项 。 |
| WHANDLE |
窗口句柄。每一个由Visual FoxPro打开的窗口,或者通过API 用_Wopen()打开的窗口都有这样一个唯一的标识。 |
2、数据结构
Visual FoxPro API定义的数据结构见下表:
| 数据类型 |
结构说明 |
| EventRec |
一个结构,用于描述在某个给定的时刻系统正在进行的操作。 |
| FoxInfo |
前面已介绍 |
| FoxTable |
前面已介绍 |
| Locator |
在“数据交换”中详细介绍 |
| ParamBlk |
在“数据交换”中详细介绍 |
| Parameter |
在“数据交换”中详细介绍 |
| Point |
一个结构,定义了屏幕上一个点的水平和垂直坐标。坐标按行号和列号指定。 |
| Rect |
一个结构,定义了屏幕上一个矩形的坐标。该矩形的左上角由 (top,left)定义,右下角由(bottom-1,right-1)定义。坐标按
行号和列号指定。 |
| Value |
在“数据交换”中详细介绍 |
三、扩展程序库与Visual FoxPro环境的数据交换
扩展程序库与Visual FoxPro环境的数据交换分两部分:程序库从Visual FoxPro接受参数;程序库返回值给Visual
FoxPro。
1、扩展程序库从Visual FoxPro接受参数
程序库中定义的函灵敏实际上只接受一个参数:一个指向参数块的指针。该参数块在ParamBlk结构中定义,保存了有关Visual FoxPro函数传递来的参数的全部信息。所以函数申明必须是如下格式:
void FunctionName(ParamBlk*parm)
ParamBlk结构定义包含在PRO_EXE.H中:
/*库函数的参数列表*/
typedef struct{
short int pCount:/*传递的参数个数*/
Paramneter[1]:/* pCount个参数*/
}ParamBlk;
包含在ParamBlk结构中的parameter数据类型是一个含有一个Value结构和一个Locator结构的联合。当函数被Visual
FoxPro调用时,可用这些结构来访问传递给它的参数。Parametet数据类型、Value结构和Locator结构都在PRO_EXT.H中定义:
/*给库函数的参数*/
typedefunion{
Value val;
Locator loc;
}Parameter
/*一个表达式的值*/
typedef struct{
char ev_type;
char ev_padding;
short ev_width;
unsigned ev_length;
long ev_long;
double ev_real;
ccy ev_currency;
MHANDLE ev_handle;
ULONG ev_object;
}value;
/*一个表或内存变量的引用*/
typedef struct{
char 1_type;
short 1_where
l_NTI,
l_offset,
l_subs,
l_subl,l_sub2;
}Locator
Visual FoxPro程序可按值或引用将变量传给库函数。默认时,内存变量的传递方式取决于SETUDFPARMS。其他变量(比如数组或字段)和表达通过值来传递。强制一个变量按引用传递,可在该变量引用之前加上@操作符。要强制一个变量按值传递,可把该变量用括号括起来。每个参数的信息保存在一个Value或者一个Locator结构中,按值的调用由value结构处理;按引用的调用则由Locator结构处理。下表说明了Value结构中各域与参数类型的对应关系:
数据类型 ev_type ev_width ev_length ev_long
ev_real ev_handle ev_currency
字符型 ‘C’ 字符串长度 字符串的
MHANDLE
数值型 `N' 显示宽度 小数位 双精度
整型 `I’ 显示宽度 长整型
日期型 `D' 日期
日期时间型 `T' 日期+(秒/86400.0)
货币型 `Y' 显示宽度 货币值
逻辑型 `L'
备注型 `M' FCHAN 0或1 备注字 备注字段编
段长度 移量
通用型 `G' FCHAN 备注字 备注字段编
段长度 移量
Null `O' 数据类型
下表说明了Locator结构中各域的含义:
| 结构元素 |
用法 |
| l_type |
`R' |
| l_where |
-1表示内存变量,或为一工作区号 |
| l_NTI |
名称表索引 |
| l_offset |
字段偏移量 |
| l_sub0 |
为内存变量,或为一下标数(如是数组) |
| l_sub1 |
第一下标(如果数组) |
| l_sub2 |
第二下标(如果维数组) |
下面是接收参数的几个例子:
(1)接收一个数型参数
long long_var;
long_var=pann->P[0].Val.ev_long;
(2)接收一个日期型参数
double date;
date=parm->P[0]val.ev_real;
(3)通过传值方式接收一个字符串
char buf[256];
MHANDLE pvar;
pvar=parm->P[0]val.ev_handle;
_HLock(pvar);
_MemMove(buf,HandToPtr(pvar),parm->;
P[0].val.ev_length)
HUnlock(pvar)
为确保该字符串以‘\0’结尾,可令buf[255]=‘\0’;
(4)通过引用方式接收一个字符串
char buf[256];
Value val,*pval;
Locator *loc;
int errcode;
loc=&parm->p[0].loc;
pval=&val;
if(((errcode=_lode(loc,pvar))!=0);
_Error(-errcode);
//为确保以‘\0’结尾,要加1字节的空间
if (!_SetHandSize(pvar->ev_handle,pvar->
ev_length+1))
_Error(182)_;
//字符串尾加‘\0’
*((char*)_HandToPtr(pvar->ev_handle)+pvar->
ev_length)=`\0'
_HLock(pvar);
_MernMove(buf,_HandToPtr(pvar),pvar->
ev_length+1
_HUnLock(pvar)
2、返回值给Visual FoxPro
返回值给Visual FoxPro,可以使用在PRO_EXT.H中说明的API函数;
函数说明
RetCHar(char*string) 返回一个以null终止的字符串。
_RetDateStr(char*string) 返回一个日期值。日期格式是mm/dd/yy[yy]。
_RetDateTimeStr(Char*string) 返回一个日期时间值。格式为mm/dd/yy[yy]hh:mm:ss。
_RetFloat(double flt int width int dec 返回一个浮点值。
_RetInt(longival int width) 返回一个整型值
_RetCurrency(CCY cval int width) 返回一个货币值。
_RetLogical(int flag) 返回一个逻辑值。0为“假”;非0为真。
_RetVal(Value*val) 传递一个完整的Visual FoxPro Value结构构;利用此函数,除备 注之外的任何Visual
FoxPro数据类型都可返回。必须调用 _RetValo来返回一个包含内嵌null字符的字符串,或返回一个 NULL值。
这些API函数十分好用,但有一个缺点;一个函数只能有一个返还信息。作为一个C语言程序员,对函数原型中形参的作用一定不陌生。究其根本,形参其实指示了一片内存区域,被调函数对该区域操作。函数结束后,信息保留在此内存区域,“返还”给主调函数。Visual
FoxPro中按引用传递参数与之很相似。笔者根据此原理,成功的编写了几个引用返还信息的子程序。见示例;
(1)通过引用方式返回一个整型数
Locator*lo
Value temp
int errorcode
lo=&parm->p[0].loc
temp.ev_long=num//num
temp.ev_type=`I'
temp.ev_width=10;
if((errorcode=Stroe(lo,&temp))!=0
_Error(-errorcode)
(2)通过引用方式返回一个字符串
Locator*lo;
Vahue temp
int errcode
lo=&parm-P[0].loc
temp.ev_type=`C',
temp.ev_length=tength;//length为字符串长度
if((temp.ev_handle=_AllocHand(length)=0)
(Error(182)//内存不够
_Hlock(temp.ev_handle;//string为返回字符串指针
_MemMove(HandToPtr(temp.ev_handle)stringlength);
_HUnLock(temp.ev_handle);
if((errorcode=_store(lo,&temp))!=-
_Error(-errorcode)
以上只介绍了编制Visual FoxPro扩展程序库的基本知识,读者如想处理自己的实际问题,还需要根据情况仔细分析。
|