Visual FoxPro擴展程序庫的編寫要點
發(fā)布時間:2008-08-09 閱讀數(shù): 次 來源:網(wǎng)樂原科技
摘要:本文介紹用C/C++編制Visual FoxPro擴展程序庫的基本要點,并給出一些參數(shù)傳遞的例子。
關(guān)鍵詞:Visual FoxPro擴展程序庫</P><P> Visual FoxPro的擴展程序庫由C或C++編寫,可以訪問Visual FoxPro的“應(yīng)用程序接口”(API),大大擴展了Visual FoxPro的原有功能。本文即介紹編制擴展程序庫的基本要點。
編制擴展程序庫有一定的軟件要求。首先,由于Visual FoxPro是一個32位的應(yīng)用程序,所以必須使用一32位編譯器來連編該程序庫,筆者推薦使用Microsoft VisualC++TM4.1版。其次需要Visual FoxPro“應(yīng)用程序接口”的頭文件(PRO_EXT.H)以及導(dǎo)入庫(WINAPIMS.LIB),這兩個文件均在Visual FoxPro的API子目錄下。
對于有C語言編程經(jīng)驗的程序員來說,寫擴展程序庫的難點在于要搞清:擴展程序庫本身的框架、數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)以及擴展程序庫與Visual FoxPro環(huán)境的數(shù)據(jù)交換約定。下面主要介紹這三點。</P><P>一、 擴展程序庫的基本結(jié)構(gòu)</P><P>程序庫由四部分組成:</P><P>
1、#include 語句</P><P>
#include <pro_ext.h>;
2、函數(shù)定義
void Function _ Name (ParamBlk*parm)
{
\\函數(shù)代碼
}
3、FoxInfo結(jié)構(gòu)
FoxInfo myFoxInfo[]\{
{"FUNCTION_N",(FPFI)Function_Name,
ParmCount,ParmTypes},
};
FoxInfo結(jié)構(gòu)用于在Visual FoxPro和庫之間傳遞函數(shù)名和參數(shù)描述信息?!癿yFoxInfo"為FoxInfo型的變量。注意在該數(shù)組中可以包含多個FoxInfo結(jié)構(gòu)行。ParmCount指定在ParmTYpes字符串中描述的參數(shù)個數(shù),或者下列標(biāo)志值之一:
值說明
INTERNAL 指明該函數(shù)不能直接從Visual FoxPro調(diào)用
CALLONLOAD 指明該函數(shù)在加載時調(diào)用。
CALLONUNLOAD 指明該函數(shù)的卸載庫,或發(fā)出VisualFoxPro的QUIT命 令時調(diào)用
注:CALLONLOAD和CALLONUNLOAD均不能調(diào)用那些返回結(jié)果給Visual FoxPro的函數(shù)。
ParmTYpes描述每個參數(shù)的數(shù)據(jù)類型。下表列出ParmTYpes的有效值。
值描述
““ 無參數(shù)
“?” 能傳遞任意類型
“C” 字符型參數(shù)
“D” 日期型參數(shù)
“I” 整型參數(shù)
“L” 邏輯型參數(shù)
“N” 數(shù)值型參數(shù)
“R” 引用
“T” 日期時間型參數(shù)
“Y” 貨幣型參數(shù)
4、Foxtable 結(jié)構(gòu)
FoxTable myFoxTable={
(FoxTable *)0,sizeof(myFoxInfo) /
sizeof(FoxInfo),myFoxInfo
}
該結(jié)構(gòu)第一個參數(shù)是Visual FoxPro內(nèi)部使用的一個指針,必須初始化為0;第二個參數(shù)是該程序庫定義的Visual FoxPro外部例程數(shù)目;第三個參數(shù)實際為該程序庫FoxInfo結(jié)構(gòu)的變量名。如讀者的FoxInfo型變量名為myFoxInfo,建議讀者直接使用上面這個例子。</P><P>二、Visual FoxPro API數(shù)據(jù)類型與數(shù)據(jù)結(jié)構(gòu)</P><P>1、數(shù)據(jù)類型
Visual FoxPro API定義的數(shù)據(jù)類型見下表
數(shù)據(jù)類型說明
EDLINE 用于編輯窗口中打開的文件,指明文件中某一行的行號,首行為1。
EDPOS 用于編輯窗口中打開的文件,指明文件中某個字符的偏移位置 。
FCHAN 文件通道。每個由Visual FoxPro打開的文件,或通過API用 _FCreate()和_FOpen()打開的文件,都被分配一個FAHAN FPFI 指向一個返回一個整數(shù)值的函數(shù)的32位指針。
ITEMID 為菜單中某一命令指定的唯一標(biāo)識。
MENUID 指定給一個菜單的唯一標(biāo)識。
MHANDLE 一個唯一標(biāo)識,每一個由Visual FoxProw分配的內(nèi)存塊,或通過API用_AllocHand()分配的內(nèi)存塊都具有這樣一個標(biāo)識。可以使用_HandToPtr()返回引用到它的指針。
NTI 名稱表索引。每個內(nèi)存變量和表字段的名稱在該表中都有一項 。
WHANDLE 窗口句柄。每一個由Visual FoxPro打開的窗口,或者通過API 用_Wopen()打開的窗口都有這樣一個唯一的標(biāo)識。
2、數(shù)據(jù)結(jié)構(gòu)
Visual FoxPro API定義的數(shù)據(jù)結(jié)構(gòu)見下表:
Visual FoxPro API數(shù)據(jù)類型
結(jié)構(gòu)說明
EventRec 一個結(jié)構(gòu),用于描述在某個給定的時刻系統(tǒng)正在進行的操作。
FoxInfo 前面已介紹
FoxTable 前面已介紹
Locator 在“數(shù)據(jù)交換”中詳細介紹
ParamBlk 在“數(shù)據(jù)交換”中詳細介紹
Parameter 在“數(shù)據(jù)交換”中詳細介紹
Point 一個結(jié)構(gòu),定義了屏幕上一個點的水平和垂直坐標(biāo)。坐標(biāo)按行號和列號指定。
Rect 一個結(jié)構(gòu),定義了屏幕上一個矩形的坐標(biāo)。該矩形的左上角由 (top,left)定義,右下角由(bottom-1,right-1)定義。坐標(biāo)按 行號和列號指定。
Value 在“數(shù)據(jù)交換”中詳細介紹
Visual FoxPro API數(shù)據(jù)結(jié)構(gòu) </P><P>三、擴展程序庫與Visual FoxPro環(huán)境的數(shù)據(jù)交換</P><P> 擴展程序庫與Visual FoxPro環(huán)境的數(shù)據(jù)交換分兩部分:程序庫從Visual FoxPro接受參數(shù);程序庫返回值給Visual FoxPro。
1、擴展程序庫從Visual FoxPro接受參數(shù)
程序庫中定義的函靈敏實際上只接受一個參數(shù):一個指向參數(shù)塊的指針。該參數(shù)塊在ParamBlk結(jié)構(gòu)中定義,保存了有關(guān)Visual FoxPro函數(shù)傳遞來的參數(shù)的全部信息。所以函數(shù)申明必須是如下格式:
void FunctionName(ParamBlk*parm)
ParamBlk結(jié)構(gòu)定義包含在PRO_EXE.H中:
/*庫函數(shù)的參數(shù)列表*/
typedef struct{
short int pCount:/*傳遞的參數(shù)個數(shù)*/
Paramneter[1]:/* pCount個參數(shù)*/
}ParamBlk;
包含在ParamBlk結(jié)構(gòu)中的parameter數(shù)據(jù)類型是一個含有一個Value結(jié)構(gòu)和一個Locator結(jié)構(gòu)的聯(lián)合。當(dāng)函數(shù)被Visual FoxPro調(diào)用時,可用這些結(jié)構(gòu)來訪問傳遞給它的參數(shù)。Parametet數(shù)據(jù)類型、Value結(jié)構(gòu)和Locator結(jié)構(gòu)都在PRO_EXT.H中定義:
/*給庫函數(shù)的參數(shù)*/
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;
/*一個表或內(nèi)存變量的引用*/
typedef struct{
char 1_type;
short 1_where
l_NTI,
l_offset,
l_subs,
l_subl,l_sub2;
}Locator
Visual FoxPro程序可按值或引用將變量傳給庫函數(shù)。默認時,內(nèi)存變量的傳遞方式取決于SETUDFPARMS。其他變量(比如數(shù)組或字段)和表達通過值來傳遞。強制一個變量按引用傳遞,可在該變量引用之前加上@操作符。要強制一個變量按值傳遞,可把該變量用括號括起來。每個參數(shù)的信息保存在一個Value或者一個Locator結(jié)構(gòu)中,按值的調(diào)用由value結(jié)構(gòu)處理;按引用的調(diào)用則由Locator結(jié)構(gòu)處理。下表說明了Value結(jié)構(gòu)中各域與參數(shù)類型的對應(yīng)關(guān)系:
數(shù)據(jù)類型 ev_type ev_width ev_length ev_long
ev_real ev_handle ev_currency
字符型 ‘C’ 字符串長度 字符串的
MHANDLE
數(shù)值型 `N' 顯示寬度 小數(shù)位 雙精度
整型 `I’ 顯示寬度 長整型
日期型 `D' 日期
日期時間型 `T' 日期+(秒/86400.0)
貨幣型 `Y' 顯示寬度 貨幣值
邏輯型 `L'
備注型 `M' FCHAN 0或1 備注字 備注字段編
段長度 移量
通用型 `G' FCHAN 備注字 備注字段編
段長度 移量
Null `O' 數(shù)據(jù)類型
下表說明了Locator結(jié)構(gòu)中各域的含義:
結(jié)構(gòu)元素 用法
l_type `R'
l_where -1表示內(nèi)存變量,或為一工作區(qū)號
l_NTI 名稱表索引
l_offset 字段偏移量
l_sub 0為內(nèi)存變量,或為一下標(biāo)數(shù)(如是數(shù)組)
l_sub1 第一下標(biāo)(如果數(shù)組)
l_sub2 第二下標(biāo)(如果維數(shù)組)
下面是接收參數(shù)的幾個例子:
(1)接收一個數(shù)型參數(shù)
long long_var;
long_var=pann->P[0].Val.ev_long;
(2)接收一個日期型參數(shù)
double date;
date=parm->P[0]val.ev_real;
(3)通過傳值方式接收一個字符串
char buf[256];
MHANDLE pvar;
pvar=parm->P[0]val.ev_handle;
_HLock(pvar); </P><P>_MemMove(buf,HandToPtr(pvar),parm->;
P[0].val.ev_length)
HUnlock(pvar)
為確保該字符串以‘\0’結(jié)尾,可令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’結(jié)尾,要加1字節(jié)的空間
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</P><P>
_HUnLock(pvar)
2、返回值給Visual FoxPro
返回值給Visual FoxPro,可以使用在PRO_EXT.H中說明的API函數(shù);
函數(shù)說明
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結(jié)構(gòu)構(gòu);利用此函數(shù),除備 注之外的任何Visual FoxPro數(shù)據(jù)類型都可返回。必須調(diào)用 _RetValo來返回一個包含內(nèi)嵌null字符的字符串,或返回一個 NULL值。
這些API函數(shù)十分好用,但有一個缺點;一個函數(shù)只能有一個返還信息。作為一個C語言程序員,對函數(shù)原型中形參的作用一定不陌生。究其根本,形參其實指示了一片內(nèi)存區(qū)域,被調(diào)函數(shù)對該區(qū)域操作。函數(shù)結(jié)束后,信息保留在此內(nèi)存區(qū)域,“返還”給主調(diào)函數(shù)。Visual FoxPro中按引用傳遞參數(shù)與之很相似。筆者根據(jù)此原理,成功的編寫了幾個引用返還信息的子程序。見示例;
(1)通過引用方式返回一個整型數(shù)
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)//內(nèi)存不夠
_Hlock(temp.ev_handle;//string為返回字符串指針
_MemMove(HandToPtr(temp.ev_handle)stringlength);
_HUnLock(temp.ev_handle);
if((errorcode=_store(lo,&temp))!=-
_Error(-errorcode)</P><P> 以上只介紹了編制Visual FoxPro擴展程序庫的基本知識,讀者如想處理自己的實際問題,還需要根據(jù)情況仔細分析。