VFP 愛用者社區 首頁 VFP 愛用者社區
本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入

Visual FoxPro擴展程序庫(.FLL)的編寫要點

 
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區
上一篇主題 :: 下一篇主題  
發表人 內容
garfield
Site Admin


註冊時間: 2003-01-30
文章: 2157


第 1 樓

發表發表於: 星期四 四月 07, 2005 6:49 pm    文章主題: Visual FoxPro擴展程序庫(.FLL)的編寫要點 引言回覆

http://foxpro.myrice.com/article/kzcxk.htm

Visual FoxPro擴展程序庫的編寫要點

(150001 哈爾濱工程大學計算機系 井衛軍)

  摘要:本文介紹用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定義的數據結構見下表:
Visual FoxPro API數據類型
結構說明
EventRec 一個結構,用於描述在某個給定的時刻系統正在進行的操作。
FoxInfo 前面已介紹
FoxTable 前面已介紹 
Locator 在「數據交換」中詳細介紹 
ParamBlk 在「數據交換」中詳細介紹 
Parameter 在「數據交換」中詳細介紹 
Point 一個結構,定義了屏幕上一個點的水平和垂直坐標。坐標按行號和列號指定。 
Rect 一個結構,定義了屏幕上一個矩形的坐標。該矩形的左上角由 (top,left)定義,右下角由(bottom-1,right-1)定義。坐標按 行號和列號指定。 
Value 在「數據交換」中詳細介紹
Visual FoxPro API數據結構 

三、擴展程序庫與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_sub 0為內存變量,或為一下標數(如是數組)
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擴展程序庫的基本知識,讀者如想處理自己的實際問題,還需要根據情況仔細分析。

(150001哈爾濱工程大學計算機系井衛軍)

********************************************************************
MSDN 說明:
第二十八章:存取 Visual FoxPro API
如果 Visual FoxPro 還沒有包含您的應用程式需要的特性,您可以使用一個 32 位元編譯器延伸它的功能,例如 Microsoft Visual C++& 4.0 或更高版本,建立一個 ActiveX 控制項(.ocx 檔案)或專用於 Visual FoxPro 的函數庫檔案(.fll 檔案)。本章將討論這兩種程式。

附註 如果您使用 Visual C++ 2.x 來開發 ActiveX 控制項,需要 Control Development Kit。本章假定您使用的是 Visual C/C++ 4.0 版本。

有關使用 ActiveX 控制項或 FLL 的詳細內容,請參閱第二十七章<使用外部函數庫延伸 Visual FoxPro 的功能>。

本章內容要點︰

建立一個函數庫或者 ActiveX 物件


新增 Visual FoxPro API 呼叫


傳遞和接收參數


傳回值給 Visual FoxPro


向 Visual FoxPro API 函數傳遞參數


存取 Visual FoxPro 變數和欄位


管理記憶體


編譯、除錯函數庫與 ActiveX 控制項
建立一個函數庫或者 ActiveX 物件
您可以延伸 Visual FoxPro 的功能,方法是用 C 或 C++ 建立程式,完成您的應用程式需要的任務。例如,如果您的應用程式需要直接存取 Windows 工具,您可以撰寫一個 C 或 C++ 程式呼叫 Windows API,然後向 Visual FoxPro 傳回訊息。

要想存取 Visual FoxPro API,您可以建立三種類型的程式︰

ActiveX 控制項(.ocx 檔案)。


COM 物件(.ocx 檔案)。


專用於 Visual FoxPro 的 DLL 檔案。因為這種 DLL 檔案只能被 Visual FoxPro 呼叫,習慣上用 .fll 作為副檔名。
每種類型的程式都具有優點。一個 ActiveX 控制項︰

可以使用標準的物件導向技術存取,例如設定屬性和呼叫方法程序。


可以產生次類別,並且可以涵蓋它的方法程序。


可以封裝,可以多次呼叫(範例化),而不用進行複雜的環境管理來保留使用者的狀態。


可以進行簡便的參數傳遞。


可以在其他 Windows 程式中呼叫,如果在設計時就考慮這一點的話。
COM 物件的優點︰

可以使用標準的物件導向技術存取,例如設定屬性和呼叫方法程序。


可以產生次類別,並且可以涵蓋它的方法程序。


可以封裝,可以多次呼叫(範例化),而不用進行複雜的環境管理來保留使用者的狀態。


可以進行簡便的參數傳遞。
可以在其他 Windows 程式中呼叫,如果在設計時就考慮這一點的話。

在另一方面,是一個 .fll 函數庫:

可能對此會很熟悉,如果您使用過Visual FoxPro 的先前版本。
附註 如果您想在早於 Visual FoxPro 5.0 版本中使用一個舊版本的 Visual FoxPro 的 .fll 函數庫,必須在 Visual FoxPro 6.0 先編譯該函數庫。

建立一個基本的 ActiveX 物件
您可以使用 Microsoft Visual C++ 5.0 提供的[ActiveX Template Library]來建立 COM 物件。有關使用 Visual C++ 5.0 建立 COM 物件的詳細內容,請在 MSDN 函數庫中搜索[ATL]。

與其他類似的控制項一樣,您也可以建立專用於 Visual FoxPro 的 ActiveX 控制項。您可以使用大多數 C++ 編譯器來建立該控制項的架構,也可以用 Microsoft Visual Basic& Control Creation Edition 5.0 版建立。

以下的章節將會介紹如何使用Microsoft Visual C++來建立在 Visual FoxPro 中所使用的 ActiveX 控制項的一些步驟。

如何為 ActiveX 控制項建立一個專案

啟動 Microsoft Visual C++。


在[File]功能表中,選取[New]。


在[New]對話方塊中選取[Project Workspace]。


在[New Project Workspace]對話方塊中指定專案的名稱。


在[Type]清單中選取[OLE ControlWizard]。


選取[Create],然後按照精靈的步驟動作。
當精靈結束時,您可以立即產生 ActiveX 控制項。但是,您還需要定義該控制項的屬性和方法程序。

如何為 ActiveX 控制項新增屬性和方法程序

在[View]功能表中選取[ClassWizard]。


選取[OLEAutomation]標籤。


選取[Add Method]或者[Add Property]。


填入您建立元件需要的名稱、參數和其他訊息,然後按下[OK]按鈕。


選取[Edit Code]顯示編輯程式,然後輸入定義屬性或方法程序的程式碼。
例如,要想建立一個 Version 屬性,以整數傳回一個 .ocx 檔案的版本編號(例如 101),您可以使用長整數型態傳回建立該屬性,並新增如下的程式碼︰

#define VERSION 101

long CPyCtrl::GetVersion()
{
// 在此設定版本編號
return VERSION;
}

由於通常版本編號是唯讀的,您不需建立一個 SetVersion( ) 函數。

建立一個基本的 FLL 函數庫
實際上,FLL 函數庫就是呼叫 Visual FoxPro API 的 DLL,因此您可以在開發環境中根據以下建立 DLL 的步驟建立一個 FLL 函數庫。

如何建立一個FLL 函數庫專案

啟動 Microsoft Visual C/C++。


在[File]功能表中,選取[New]。


在[New]對話方塊中選取[Project Workspace]。


在[Project Workspace]對話方塊中指定專案的名稱。


在[Type]清單中選取[Dynamic-Link Library]。
在建立了 DLL 的基本結構以後,您可以新增能從 Visual FoxPro 中呼叫的函數。下面幾節概觀使用 C 和 C++ 建立函數的方法。

設定一個函數庫範本
要建立的每個函數庫都有相同的基本結構。在建立函數庫程式時,只需借助函數庫結構範本進行修改即可。

Visual FoxPro 函數庫範本有五個要素:

#include 敘述


函數定義


函數程式碼


FoxInfo 結構


FoxTable 結構
C 範本
可用下列範本建立用 C 語言撰寫的函數庫:

#include <Pro_ext.h>

void Internal_Name(ParamBlk *parm)
{
// 該處填寫函數程式碼。
}

FoxInfo myFoxInfo[] = {
{"FUNC_NAME", (FPFI) Internal_Name, 0, ""},
};

FoxTable _FoxTable = {
(FoxTable *)0, sizeof(myFoxInfo)/sizeof(FoxInfo), myFoxInfo
};

C++ 範本
對於 C++ 程式,可用下列範例。與 C 語言範例不同的是它把 FoxTable 結構宣告為 extern。

#include <Pro_ext.h>

void Internal_Name(ParamBlk *parm)
{
// 該處填寫函數程式碼。
}

FoxInfo myFoxInfo[] = {
{"FUNC_NAME", (FPFI) Internal_Name, 0, ""},
};

extern "C" {
FoxTable _FoxTable = {
(FoxTable *)0, sizeof(myFoxInfo)/sizeof(FoxInfo), myFoxInfo
};
}

使用範本
要想使用標頭檔並建立一個已編譯的函數庫,您需要︰

標頭檔 Pro_ext.h。可以列印該檔案檢視函數定義、型態定義,以及在 Visual FoxPro API 中使用的結構。


WINAPIMS.LIB 檔案。
在安裝 Visual FoxPro 時,這兩個檔案都安裝在 API 子目錄下。

函數定義傳回 void ,並需要下列參數: ParamBlk *parm。ParamBlk 結構將在本章稍後的<傳遞和接收參數>中討論。

除了標頭檔之外,Visual FoxPro 函數庫還有其他兩個必需的要素是 FoxInfo 和 FoxTable 結構。

使用 FoxInfo 和 FoxTable 結構
函數庫函數透過 FoxInfo 結構與 Visual FoxPro 進行溝通。Visual FoxPro 可以透過這個結構確定函數名、參數的個數和類型。FoxTable 結構是一個連結清單,保持對 FoxInfo 結構的追蹤。有關 FoxInfo 和 FoxTable 結構的定義,請參閱 Visual FoxPro 在 API 目錄中的 Pro_ext.h 檔案。

FoxInfo 結構
FoxInfo 結構用於在 Visual FoxPro 和函數庫之間傳遞函數名和參數描述訊息。一個通用的 FoxInfo 結構如下所示:

FoxInfo arrayname[]= {
{funcName1, FPFI function1, parmCount1, parmTypes1}
{funcName2, FPFI function2, parmCount2, parmTypes2}
. . .
{funcNameN, FPFI functionN, parmCountN, parmTypesN}
};

其中的各個引數定義如下:

arrayname

一個資料型態為 FoxInfo 的變數。注意在該陣列中可以包含多個 FoxInfo 結構列。

funcName

供 Visual FoxPro 使用者呼叫時使用的函數名稱(大寫字母並且不得超過 10 個字元)。

function

您的 C 語言程式的位址。這是函數的真正名稱(大/小寫需符合)。

parmCount

指定在 parmTypes 字串中描述的參數個數,或者是下列記號值之一。

值 描述
INTERNAL 指明該函數無法直接從 Visual FoxPro 呼叫。
CALLONLOAD 指明該函數在載入函數庫時呼叫。CALLONLOAD可以呼叫那些傳回結果給 Visual FoxPro 的函數。
CALLONUNLOAD 指明該函數在解除安裝函數庫時,或者執行Visual FoxPro 的 QUIT 指令時被呼叫。CALLONUNLOAD 無法呼叫那些傳回結果給 Visual FoxPro 的函數。


parmTypes

描述每個參數的資料型態。下表列出 parmTypes的有效值。

值 描述
""
無參數
"?"
能傳遞任意型態。在函數體中,必須驗證傳遞過來的參數型態。
"C"
字元型態參數
"D"
日期型態參數
"I"
整數參數
"L"
邏輯型態參數
"N"
數值型態參數
"R"
參考
"T"
日期時間型態參數
"Y"
貨幣型態參數
"O"
物件型態參數


應該為每個傳遞給函數庫的參數指定一個型態值。例如,若建立的函數接受是字元型態和數值型態參數,那麼可用“CN”作為 parmType。

附註 要標明一個參數是可選的,請在前面加上一個句點“.”。只有後面的參數才能省略。

下列 FoxInfo 結構定義了只有一個函數的函數庫,內部叫“dates”,外部用“DATES”來存取,並且接受一個字元型態的參數:

FoxInfo myFoxInfo[] = {
{ "DATES", (FPFI) dates, 1, "C" }
};

編譯具有這個 FoxInfo 結構的函數庫,並且在 Visual FoxPro 中使用 SET LIBRARY TO 指令載入該函數庫之後,便可在 FoxPro 中用下列程式碼列來呼叫該函數:

=DATES("01/01/95")

FoxTable 結構
FoxTable 是一個資料結構的連結清單,儲存了指定函數庫中所有 FoxInfo 結構的訊息:

FoxTable _FoxTable = {nextLibrary, infoCount,infoPtr};

其中各引數定義如下:

nextLibrary

Visual FoxPro 內部使用的一個指標,必須起始化為 0。

infoCount

在本函數庫中定義的 Visual FoxPro 外部程式數目。

infoPtr

FoxInfo 結構中第一個陣列元素的位址。這個名稱必須與 FoxInfo 敘述中列出的陣列名稱相符合。

下面是 FoxTable 敘述的一個範例。如果您的 FoxInfo 陣列名稱是 myFoxInfo,那麼您將不必變更這個敘述,就可以使用:

FoxTable _FoxTable = {
(FoxTable *) 0,
sizeof( myFoxInfo) / sizeof( FoxInfo ),
myFoxInfo
};

新增Visual FoxPro API 呼叫
為了將您的程式與 Visual FoxPro 彙整,您可以呼叫 Visual FoxPro API 程式。這些 API 程式是可以從任何 C 或 C++ 程式中呼叫的函數,包括 .ocx 或 .fll 檔案,它們可以使您存取變數,管理資料庫動作,並且完成很多其他 Visual FoxPro 特定的任務。

下表列出了 Visual FoxPro 中 API 呼叫的常用分類。有關每個 API 函數的詳細內容,請參閱[API 函數庫常式 A-Z]或[API 函數庫常式的分類]。

若要使用 Visual FoxPro API 程式,您必須包含 Visual FoxPro API 目錄下的 Pro_ext.h 檔案。該檔案包含了允許您與 Visual FoxPro 共用資訊的函數和結構的原型。

如果您想撰寫一個 ActiveX 控制項,您也必須新增呼叫來起始化和清除 API。

如何在您的 ActiveX 物件中新增 Visual FoxPro API 程式

使用 #INCLUDE 包含 Pro_ext.h 檔案,以及其他必須的標頭檔。


在控制項的 Constructor (Init) 方法程序中,使用如下程式碼呼叫 _OCXAPI( ) 來起始化與 Visual FoxPro 的界面︰
_OCXAPI(AfxGetInstanceHandle(),DLL_PROCESS_ATTACH);

在您的物件中,根據需要含入對 Visual FoxPro API 的呼叫。


在物件的 Destructor (Destroy) 方法程序中,使用如下程式碼再次呼叫 _OCXAPI( ),來釋放在 Constructor 中建立的程序︰
_OCXAPI(AfxGetInstanceHandle(),DLL_PROCESS_DETACH);

有關包含對 Visual FoxPro API 呼叫的 .ocx 檔案的範例,請參閱[Foxtlib.ocx]。有關包含對 Visual FoxPro API 呼叫的 .fll 函數庫的範例,請參閱 Vfp98\Api\Samples 目錄下具有 C 附加名的範例程式︰ EVENT.C,HELLO.C 等等。

如果在您的 ActiveX 控制項,COM 物件或 .fll 函數庫中使用 Visual FoxPro API 呼叫,則包含這個呼叫的程式碼與其他應用程式是不相容的。因此,或多或少您需要在程式中進行測試,來確定該物件是否可以從 Visual FoxPro 中呼叫。

例如,如果您使用 Microsoft Foundation Classes 建立了一個 ActiveX 控制項,您可以改變該控制項的構建程式碼來包含一個測試,然後,如果該控制項已被一個不是 Visual FoxPro 的程式呼叫,則警告使用者︰

if (!_OCXAPI(AfxGetInstanceHandle(),DLL_PROCESS_ATTACH))
{
::MessageBox(0,"This OCX can only be hosted by Visual Foxpro","",0);
//當 host 不是 Visual FoxPro 時,您可以在此書寫您所需要的程式:
// 您可以拒絕載入或
// 設定屬性
// 來說明host 不是 Visual FoxPro,
// 而且控制項將使用其他模式來達到目的。
}

如果您使用 Microsoft ActiveX Template Library 建立 ActiveX 控制項,請使用下列程式碼:

if (!_OCXAPI(_Module.GetModuleInstance(),DLL_PROCESS_ATTACH))
{
::MessageBox(0,"This OCX can only be hosted by Visual Foxpro","",0);
//當 host 不是 Visual FoxPro 時,您可以在此書寫您所需要的程式:
// 您可以拒絕載入或
// 設定屬性
// 來說明host 不是 Visual FoxPro,
// 而且控制項將使用其他模式來達到目的。
}

在本範例中,控制項並不結束,而是在通知使用者後繼續執行。您所要選取的方法取決於您想怎樣使用該控制項。例如,如果您檢測到該控制項正在 Visual FoxPro 之外被使用,您可以先設定一個記號,然後在控制項中每次呼叫 Visual FoxPro API 的地方測試這個記號。如果記號表示該控制項正在 Visual FoxPro 之外執行,您可以在 API 呼叫前利用條件分支去呼叫其它方法程序完成相同的任務。

傳遞和接收參數
當從 Visual FoxPro 呼叫您的程式時,它可以接收參數。例如,當您呼叫其中一個方法程序時,一個 ActiveX 控制項可以接收參數。相同地,一個 Visual FoxPro 程式也可以呼叫您的 FLL 函數庫中的一個函數,並且向它傳遞參數。

Visual FoxPro 可以向您的應用程式以傳值或傳址的方式傳遞參數。在預設情況下,參數遵守 SET UDFPARMS 的設定。其他變數(例如陣列或欄位)和運算式依傳值方式傳遞。

要想使一個參數強制依傳址方式傳遞,請指定在變數前加上 @ 運算子。要想使一個參數強制依傳值方式傳遞,請將它放在括號裡。

附註 在 Visual FoxPro 中,單一的陣列元素都是依傳值方式傳遞的。當 SET UDFPARMS 設定為 VALUE,並且沒有指定陣列元素時,陣列名稱本身是指陣列的第一個元素(除非有字首 @)。

由於 ActiveX 控制項和 COM 物件是標準的 Windows 程式,所以從 Visual FoxPro 和您的程式傳遞參數不需特別的機制。您可以像從任何 C 或 C++ 程式接收參數那樣撰寫程式。

相反,FLL 函數庫中的函數使用 FoxInfo 結構來接收來自 Visual FoxPro 的資料。FoxInfo 結構列出了您的函數庫函數以及它們需要的參數的個數和型態。例如,下面的 FoxInfo 結構屬於一個函數庫,該函數庫中包含一個函數,這個函數內部稱之為 dates,該函數接收一個字元型態參數︰

FoxInfo myFoxInfo[] = {
{ "DATES", (FPFI) dates, 1, "C" }
};

在您的函數庫裡定義的函數實際上只接收一個參數,也就是參數區塊的指標。這個參數區塊是在 ParamBlk 結構中定義的,它包含了從 Visual FoxPro 函數呼叫中傳遞來的所有參數訊息。您的函數宣告採用如下模式︰

void function_name(ParamBlk *parm)

例如,dates 函數的定義是︰

void dates(ParamBlk *parm)

ParamBlk 結構包含了一個整數,它代表了參數的數目,在它後面緊接著一個參數連合的陣列。該結構定義包含在 Pro_ext.h 中︰

/* 函數庫函數的參數清單。*/
typedef struct {
short int pCount; /* 傳遞的參數個數 */
Parameter p[1]; /* pCount 個參數 */
} ParamBlk;

在 ParamBlk 結構中包含的 Parameter typedef 是一個 Value 結構和 Locator 結構的聯合。依傳值方式傳遞時按照 Value 結構處理;依傳址方式傳遞時,則按照 Locator 結構處理。當 Visual FoxPro 呼叫您的函數時,您使用這些結構來存取傳遞給函數的參數。

下面的訊息是從 Pro_ext.h 檔案中提取出來的,顯示了 Parameter 型態的定義:

/* 給函數庫函數的參數。*/
typedef union {
Value val;
Locator loc;
} Parameter;

Value 結構的定義
如果依值向您的函數傳遞一個參數,則使用 Value 結構來存取這個參數。下面的 Value 結構定義是從 Pro_ext.h 檔案中提取出來的︰

// 一個運算式的值。
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;


Value 結構的欄位
下表說明了對於不同資料型態,您可以在 Value 結構中傳遞和接收的值。只有一個資料型態後面所列的結構欄位才能用於這種資料型態。

不同資料型態的 Value 結構內容

資料型態 結構欄位 值
字元型態 ev_type
'C'
ev_length
字串長度
ev_handle
指向字串的 MHANDLE
數值型態 ev_type
'N'
ev_width
顯示寬度
ev_length
小數
ev_real
雙精準度
整數 ev_type
'I'
ev_width
顯示寬度
ev_long
長整數
日期型態 ev_type
'D'
ev_real
日期1
日期時間型態 ev_type
'T'
ev_real
日期 + (秒/86400.0)
貨幣型態 ev_type
'Y'
ev_width
顯示寬度
ev_currency
貨幣值2
邏輯型態 ev_type
'L'
ev_length
0 或1
附註型態 ev_type
'M'
ev_wdith
FCHAN
ev_long
附註欄位的長度
ev_real
附註欄位的位移
通用型態 ev_type
'G'
ev_wdith
FCHAN
ev_long
通用型態欄位的長度
ev_real
通用型態欄位的位移
物件型態 ev_type
'O'
ev_object
物件識別器
Null ev_type
'0'
ev_long
資料型態


1 日期以雙精準度浮點Julian日期數型態表示,使用“Collected Algorithms of the ACM”的“演算法 199”計算。
2 貨幣值為長整數值,在最後四位數字前有一個隱藏的小數點。

附註 ev_length 是字串長度的真正指示器。字串可以 null 作為終止器,因為字串可以包含內嵌的 null 字元。

Locator 結構的定義
使用 Locator 結構可以處理依傳址方式傳遞的參數。下列的 Locator 結構定義是從 Pro_ext.h 檔案中分離出來的。

typedef struct {
char l_type;
short l_where, /* 資料庫數值, 如果是記憶體變數則為 -1。 */
l_NTI, /* 變數名稱資料表格的位移。*/
l_offset, /* 在資料庫中的索引。*/
l_subs, /* # 指定的註標 0 <= x <= 2 */
l_sub1, l_sub2; /* 註標整數值。 */
} Locator;

Locator 結構的欄位
下表說明了 Locator 結構中的欄位。

Locator 欄位 欄位的用途
l_type
'R'
l_where
包含此欄位的資料表格的數字,-1 代表一個記憶體變數。
l_NTI
名稱資料表格的索引。Visual FoxPro 內部使用。
l_offset
資料表格中欄位的數值。Visual FoxPro 內部使用。
l_subs
只用於記憶體變數,註標的數目 (0 - 2)。
l_sub1
只用於記憶體變數,若 l_subs 非 0,則代表第一個註標。
l_sub2
只用於記憶體變數,若 l_subs 為 2,則代表第二個註標。


附註 最好驗證 ev_type 中的參數型態,因為這樣可以確定要透過 Value 結構存取的欄位是否正確。

存取 FLL 函數庫中參數的範例
下列範例使用 _StrCpy( ) 傳回一個字串給 Visual FoxPro,該字串是兩個字元參數的連結。必須注意的是,雖然對每個參數的 Value 結構是使用記憶體控制碼進行連結動作,但是對該記憶體分配的變更並不影響依傳值方式傳遞的 Visual FoxPro 參數。

有關使用 Locator 結構來管理依傳址方式傳遞的參數的範例,請參閱本章稍後的<從一個 FLL 函數庫傳回值>。

#include <Pro_ext.h>

Example(ParamBlk *parm)
{
// 使用 #define 可以使 paramBlk 結構易於管理
#define p0 (parm->p[0].val)
#define p1 (parm->p[1].val)

// 確保有足夠的記憶體
if (!_SetHandSize(p0.ev_handle, p0.ev_length + p1.ev_length))
_Error(182); // "記憶體不足"

// 鎖定控制碼
_HLock(p0.ev_handle);
_HLock(p1.ev_handle);

// 將控制碼轉換成指標並確保字串是以 null 結尾的
((char *)_HandToPtr(p0.ev_handle))[p0.ev_length] = '\0';
((char *)_HandToPtr(p1.ev_handle))[p1.ev_length] = '\0';

// 用 API 函數 _StrCpy 連結字串
_StrCpy((char *)_HandToPtr(p0.ev_handle) + p0.ev_length,
_HandToPtr(p1.ev_handle));

// 向 Visual FoxPro 傳回已連結的字串
_RetChar(_HandToPtr(p0.ev_handle));

// 解除控制碼鎖定
_HUnLock(p0.ev_handle);
_HUnLock(p1.ev_handle);
}

FoxInfo myFoxInfo[] = {
{"STRCAT", Example, 2, "CC"},
};

FoxTable _FoxTable = {
(FoxTable *) 0, sizeof(myFoxInfo)/sizeof(FoxInfo), myFoxInfo
};

傳回值給 Visual FoxPro
從您的程式中用來向 Visual FoxPro 傳回值的方法取決於您建立的是 ActiveX 控制項還是 FLL 函數庫。

從一個 ActiveX 控制項傳回值
要從一個 ActiveX 控制項向 Visual FoxPro 傳回值,請使用該控制項的 RETURN 敘述,傳回單一的值,如下例所示︰

#define VERSION 101

// 此處是其他的程式碼

long CPyCtrl::GetVersion()
{
// 在變數 fVersion 中設定版本編號。
return VERSION;
}

從一個 FLL 函數庫傳回值
要從一個 FLL 函數庫傳回值,請使用 API 函數,而不要使用 C 或 C++ 本身的指令。下表所列的函數允許您向 Visual FoxPro 傳回值。

附註 不要使用下列 API 函數從一個 OCX 檔案傳回值;請使用 RETURN 敘述。API 傳回函數只能用在 FLL 函數庫中。

函數 描述
_RetChar(char *string) 將函數的傳回值設定為一個以 null 結尾的字串。
_RetCurrency(CCY cval, int width) 將函數的傳回值設定為一個貨幣值。
_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(long ival, int width) 將函數的傳回值設定為一個整數值。
_RetLogical(int flag) 將函數的傳回值設定為一個邏輯值。零被認為是 FALSE。任何非零的值被認為是 TRUE。
_RetVal(Value *val) 傳遞一個完整的 Visual FoxPro Value 結構;除了附註欄位,任何 Visual FoxPro 資料型態都可以傳回。要傳回一個包含內嵌零字元的字串,或者傳回一個 .NULL. 值,您必須呼叫 _RetVal( )。


附註 要傳回一個物件資料型態的值,請使用 _RetVal() 函數,它會在 Value 結構的 ev_object 欄位中填入物件標示記號。

下面的範例 Sum 接收對某個資料表格中一個數值欄位的參考,並用 _RetFloat 傳回欄位值加總:

#include <Pro_ext.h>

Sum(ParamBlk *parm)
{
// 宣告變數
double tot = 0, rec_cnt;
int i = 0, workarea = -1; // -1 是目前工作空間
Value val;

// 資料記錄指標指向資料表格開頭
_DBRewind(workarea);

// 獲得資料記錄數
rec_cnt = _DBRecCount(workarea);

// 迴圈資料表格
for(i = 0; i < rec_cnt; i++)
{
//將欄位的值放入 Value 結構
_Load(&parm->p[0].loc, &val);

// 加總
tot += val.ev_real;

// 指標指向下一個資料記錄
_DBSkip(workarea, 1);
}

// 將加總值傳回給 Visual FoxPro
_RetFloat(tot, 10, 4);
}
// Sum 函數接收一個參考參數
FoxInfo myFoxInfo[] = {
{"SUM", Sum, 1,"R"}
};
FoxTable _FoxTable = {
(FoxTable *) 0, sizeof(myFoxInfo)/sizeof(FoxInfo), myFoxInfo
};

假定在目前開啟的資料表格中有一個叫 amount 的數值型態欄位,可在 Visual FoxPro 程式中用下列程式碼呼叫該函數;

? SUM(@amount)

向 Visual FoxPro API 函數傳遞參數
Visual FoxPro API 程式經常需要特定 Visual FoxPro 資料結構的參數。下面幾節提供了 Visual FoxPro 資料型態和附加資料結構的清單。有關型態和結構的實際定義,請參閱 Pro_ext.h 檔案。

Visual FoxPro API 資料型態
下列資料型態可在 Visual FoxPro API 函數中使用。

資料型態 描述
EDLINE
用於編輯視窗中開啟的檔案,指明檔案中某一行的行號,首行為1。
EDPOS
用於編輯視窗中開啟的檔案,指明檔案中某個字元的偏移位置。在檔案或說明中,首字元的偏移位置為0。
FCHAN
檔案通道。每個由 Visual FoxPro 開啟的檔案,或者透過 API 用 _Fcreate( ) 和 _FOpen( ) 開啟的檔案,都被分配一個 FCHAN。
FPFI
指向一個傳回整數字的函數的32 位元指標。
ITEMID
為功能表中某一指令指定的獨一識別器。
MENUID
指定給一個功能表的獨一識別器。
MHANDLE
一個獨一標識,每一個由 Visual FoxPro 分配的記憶體區塊,或透過 API 用 _AllocHand( ) 分配的記憶體區塊都具有這樣一個識別器。可以使用 _HandToPtr( ) 反參考到它的指標。
NTI
名稱資料表格的索引。每個記憶體變數和資料表格欄位的名稱在該資料表格中都有一項。
WHANDLE
視窗控制碼。每一個由 Visual FoxPro 開啟的視窗,或者透過 API 用 _Wopen( ) 開啟的視窗都有這樣一個獨一的識別器。


附註 因為 FAR 指標對 32 位元編譯器不適用,請在 Pro_ext.h 檔案中的 #define 敘述中將 FAR,_far 和 __far 作為 null 值重新設定。

Visual FoxPro API 資料結構
下表列出了在 Visual FoxPro API 函數庫中使用的主要資料結構。

結構 描述
EventRec
一個結構,用於描述在某個指定的時期系統正在進行的動作。
FoxInfo
在 FLL 函數庫中使用,用於 Visual FoxPro 與應用程式之間的通訊,無法在 .ocx 檔案中使用。在本章前面<使用 FoxInfo 和 FoxTable 結構>中已討論。
FoxTable
在 FLL 函數庫中使用,用於 Visual FoxPro 與應用程式之間的通訊,無法在 .ocx 檔案中使用。在本章前面<使用 FoxInfo 和 FoxTable 結構>中已討論。
Locator
用於存取參數值 (FLL)、Visual FoxPro 變數或欄位 (FLL 和 .ocx) 的結構。
ParamBlk
在 FLL 函數庫中使用,用於 Visual FoxPro 與應用程式之間的通訊,無法在 .ocx 檔案中使用。在本章前面<使用 FoxInfo 和 FoxTable 結構>中已討論。
Parameter
在 FLL 函數庫中使用,用於 Visual FoxPro 與應用程式之間的通訊,無法在 .ocx 檔案中使用。在本章前面<使用 FoxInfo 和 FoxTable 結構>中已討論。
Point
定義螢幕上一個點的水平和垂直座標的一種結構。座標按列和直欄指定。
Rect
定義了螢幕上一個矩形的座標的一種結構。該矩形的左上角由(top,left)定義,右下角由(bottom-1,right-1)定義。座標按列和直欄指定。
Value
用於存取參數值(FLL)、Visual FoxPro 變數或欄位(FLL 和 .ocx)的結構。


存取 Visual FoxPro 變數和欄位
您可以在您的 ActiveX 控制項或 FLL 函數中存取、讀、設定 Visual FoxPro 變數或欄位。另外,您可以建立 Visual FoxPro 能夠存取的新變數。

變數和欄位儲存在 Visual FoxPro 的一個名稱表中,它是一個陣列,包含了所有目前定義的變數和欄位的名稱。您可以使用名稱資料表格的索引 (NTI) 來存取陣列中的單一元素。一個特殊的 API 函數,_NameTableIndex( ),根據您提供的名稱傳回一個已存在的變數和欄位的索引。當您確定了一個指定變數的 NTI 時,您可以使用 _Load( ) API 函數讀它,或者使用 _Store( ) 函數設定它。若要建立一個新變數,您可以呼叫 API 函數 _NewVar( )。

若要存取 Visual FoxPro 變數或欄位,您可以使用在 Value 和 Locator 中定義的結構。如果您建立一個 FLL 函數庫,您可以使用與存取傳遞給您的函數的參數的相同技術。有關 Value 和 Locator 結構的詳細內容,請參閱本章稍前的<傳遞和接收參數>。

下面的範例是從 Vfp98\API\SAMPLES\Foxtlib 目錄中的 Foxtlibctl.cpp 程式中提取的,它展示了在一個 ActiveX 控制項中,您如何使用 Value 和 Locator 結構來存取 Visual FoxPro 變數︰

long CFoxtlibCtrl::TLGetTypeAttr(long pTypeInfo, LPCTSTR szArrName)
{
int nResult = 1;
TYPEATTR *lpTypeAttr;
Locator loc;
Value val;
OLECHAR szGuid[128];
char *szBuff;
__try {
if (_FindVar(_NameTableIndex(( char *)szArrName),-1,&loc)) {
((ITypeInfo *)pTypeInfo)->GetTypeAttr(&lpTypeAttr);
if (_ALen(loc.l_NTI, AL_ELEMENTS) < 16) {
_Error(631); //Array argument not of proper size.
}

//1 = Guid
StringFromGUID2(lpTypeAttr->guid,
(LPOLESTR )&szGuid,sizeof(szGuid));
OLEOleToAnsiString(szGuid,&szBuff);
val.ev_type = 'C';
val.ev_length = strlen(szBuff);
val.ev_handle = _AllocHand(val.ev_length);
_HLock(val.ev_handle);
_MemMove((char *) _HandToPtr( val.ev_handle ), szBuff,
val.ev_length);
OLEFreeString((void **)&szBuff);
_HUnLock(val.ev_handle);
loc.l_sub1 = 1;
_Store(&loc,&val);
_FreeHand(val.ev_handle);

//2 = LCID
loc.l_sub1 = 2;
val.ev_type = 'I';
val.ev_long = lpTypeAttr->lcid;
_Store(&loc,&val);

// code for values 3 - 16 here
((ITypeInfo *)pTypeInfo) -> ReleaseTypeAttr(lpTypeAttr);
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
nResult = 0;
}
return nResult;

管理記憶體
Visual FoxPro API 提供了對 Visual FoxPro 動態記憶體管理員的直接存取。對於請求記憶體分配的 API 函數,傳回一個記憶體識別器或為控制碼。Visual FoxPro 分段載入結構使用控制碼而不是指標,這樣可以更有效地管理記憶體。

附註 本節所述的 Visual FoxPro API記憶體管理的技術,可以用於 ActiveX 控制項和 FLL 函數庫。

使用控制碼
這裡的控制碼是指一個記憶體控制碼,本質上是對一個指標陣列的索引。陣列中的這些指標指向由 Visual FoxPro 掌握的各記憶體塊。在 API 中幾乎所有對記憶體的參考都透過控制碼來製作, 而不是傳統的 C 指標。

如何在函數庫中分配並使用記憶體

用 _AllocHand( ) 分配一個控制碼。


用 _HLock( ) 鎖定該控制碼。


用 _HandToPtr( ) 把控制碼轉換成一個指標。


使用該指標指向記憶體。


用 _HUnLock( ) 解除鎖定控制碼。
秘訣 為了避免破壞附註檔,於呼叫 _AllocMemo( ) 之前不要對附註檔進行寫入動作。

為了確定分配記憶體的位址,API 函數必須呼叫 _HandToPtr( ) 函數把控制碼轉換成指標。也就是使 Visual FoxPro 記憶體管理員重新組織記憶體,以便讓後來的記憶體在請求更多的連續記憶體時,控制碼也能保持不變。同時還提供了增加、減少、釋放和鎖定記憶體分配的程式。

在建立外部函數時,應儘量減少記憶體使用。如果建立一個動態配置記憶體的外部函數,則請儘量少使用記憶體。在長時間鎖定一個大的記憶體區塊時要特別小心。在記憶體不再需要鎖定時,請記住用 _HUnLock( ) 解除鎖定記憶體控制碼,因為鎖定記憶體控制碼會對 Visual FoxPro 的效能有不利的影響。

注意 過份使用動態記憶體會減少 Visual FoxPro替緩衝區、視窗、功能表及其他系統資源配置的記憶體,並且降低 Visual FoxPro 的效能。為 API 程式分配的記憶體由 Visual FoxPro 記憶體管理員進行管理。分配大量的控制碼並且一直保留這些控制碼會引起 Visual FoxPro 記憶體不足並異常終止。

Visual FoxPro 環境沒有記憶體保護。外部 API 函數無法提供驗證,而這種驗證在一個標準 Visual FoxPro 程式中是內建的。如果記憶體崩潰,就會得到一些錯誤訊息,比如“越界控制碼”、“內部一致性錯誤”和“壓縮程序出現越界節點”。

下面的 FLL 函數庫中的函數展示了記憶體是如何分配的。假定範例中的字元型態參數是個正確的日期值,下面使用 _RetDateStr( ) 傳回一個 Visual FoxPro 日期型態值:

#include <Pro_ext.h>

void dates(ParamBlk *parm)
{
MHANDLE mh;
char *instring;

if ((mh = _AllocHand(parm->p[0].val.ev_length + 1)) == 0) {
_Error(182); // "記憶體不足"
}
_HLock(parm->p[0].val.ev_handle);
instring = _HandToPtr(parm->p[0].val.ev_handle);
instring[parm->p[0].val.ev_length] = '\0';
_RetDateStr(instring);
_HUnLock(parm->p[0].val.ev_handle);
}
FoxInfo myFoxInfo[] = {
{"DATES", (FPFI) dates, 1, "C"}
};
FoxTable _FoxTable = {
(FoxTable *) 0, sizeof(myFoxInfo)/sizeof(FoxInfo), myFoxInfo
};

瞭解堆疊
由使用者建立並賦予 .fll 副檔名的函數庫本質上是一個 .dll 檔案,根據定義它並不具有自己的堆疊。相反,它使用呼叫程式的堆疊。.fll 檔案使用 Visual FoxPro 的堆疊。使用者無法控制 Visual FoxPro 堆疊的大小,或者影響對一個 .fll 檔案可用的堆疊空間計算。

在正常情況下,這個差別並不重要。Visual FoxPro 的堆疊通常很大,足以儲存一個 .fll 檔案中需要分配記憶體的自動變數。如果遇到溢位的問題,您可以動態地分配堆疊附加記憶體。

遵守控制碼規則
下面說明了獲取控制碼和釋放控制碼的規則:

使用者必須負責釋放他們分配的所有控制碼,包括由 _Load() 這樣的函數分配的控制碼。


_Load() 只有當載入的記憶體變數是一個字串(也就是 ev_type = ‘C’)時才建立一個控制碼。所有其他資料型態把它們的值存在 Value 結構本身中,而載入一個字串則把一個 MHANDLE 放在 Value 結構的 ev_handle 中。


在 FLL 函數庫中 Visual FoxPro 負責釋放所有由 _RetVal( ) 傳回的控制碼。即使這些控制碼由使用者分配,他們也無法釋放這些控制碼。


使用者不可以釋放在 ParamBlk 中傳遞來的控制碼。
注意 在撰寫一個呼叫別的函數的外部程式時, 要注意遵守所有規則並驗證傳回結果。一個錯誤的指標或控制碼參考可能損壞 Visual FoxPro 的內部資料結構,立刻造成異常終止或者留下隱患,甚至可能遺失資料。

編譯、除錯函數庫與 ActiveX 控制項
在建立了一個專案之後,您就可以對它編譯並且除錯。

編譯專案
在編譯專案之前,您需要編譯專案的設定。有些設定取決於您想建立控制項或函數庫的測試版還是發行版。通常,在程式正常執行,並且您也感到滿意前建立程式的測試版,然後再建立一個發行版。

如何指定測試版或發行版

在[Build]功能表中,選取[Set default Configuration]。


選取建立控制項的測試版還是發行版。


選取[OK]。
如何建立專案設定

從[Build]功能表中選取[Settings]指令。


在[Settings]下,選取建立程式的測試版還是發行版。


按一下[C/C++]標籤,然後進行下列設定︰
在[Category]清單中,選取[Code Generation]。


在[Calling Convention]清單中,選取[_fastcall]。


在[Use run-time library]清單中,選取[Multithreaded DLL]。
選取[Link]標籤,然後在[Object/Library Modules]文字輸入方塊中新增下列函數庫︰
如果您建立一個 .ocx 檔案,請新增 Visual FoxPro API 目錄中的 OCXAPI.LIB。


如果您建立一個 .fll 檔案,請新增 Visual FoxPro API 目錄中的 WINAPIMS.LIB。
取消核取[Ignore all default libnraries]。


選取[OK]。
如何保證編譯工具能找到所需檔案

從[Tools]功能表選取[Options]。


按一下[Directories]標籤。


在[Directories]列示方塊中選取[Include files]。


在[Directories]工具列中,按一下[Add]按鈕。


新增具有 Pro_ext.h 的目錄。


在[Show directories for]列示方塊中選取[Library files]。


在[Directories]工具列中,按一下[Add]按鈕。


當建立一個控制項時,新增 Visual FoxPro API 目錄中帶有 Ocxapi.lib 檔案的目錄,或者當建立一個 FLL 函數庫時,新增 Visual FoxPro API 目錄中的 Winapims.lib 檔案。


在[Options]對話方塊中選取[OK]。
在指定了這些設定之後,您可以編譯並連結您的程式。

如何編譯並連結一個 .ocx 檔案

在[Build]功能表中,選取[Build projname.ocx]。
當您編譯並連結 .ocx 檔案時,Visual C++ 自動在建立此控制項的電腦上註冊該控制項。如果由於某些原因您必須手動註冊該控制項,您可以採用下列程序︰

如何註冊 ActiveX 控制項

在 Visual C++ Developer Studio 中的[Tool]功能表中,選取[Register Control]。
- 或者 -

在您的程式中宣告並呼叫 DLLRegisterServer( )。
建立和除錯 ActiveX 控制項或 FLL 函數庫
在一個完整的 Visual FoxPro 應用程式中除錯一個控制項或函數庫,通常比單獨地除錯控制項或函數庫更為困難。一種較好的方法是建立一個簡單的測試程式來測試控制項或函數庫。

用 Microsoft Visual C++ 除錯
Microsoft Visual C++ 4.0 版提供一個彙整除錯環境,可以方便地設定中斷點並逐行除錯程式碼。甚至可從 Visual C++ 中執行 Visual FoxPro。

如何啟動 Microsoft Visual C++ 的除錯功能

從 [Build]功能表選取[Setting]指令。


在[Project Settings]對話方塊中按一下[Debug]標籤。


在[Executable for debug session]文字輸入方塊中,輸入路徑和Vfp6.exe。
例如,輸入
C:\Program Files\Microsoft Visual Studio\Vfp98\Vfp6.exe

選取[OK]。


在函數庫中設定一個中斷點。


在[Build]功能表中,選取[Debug]。然後,在功能表列中選取[Go]。


當 Developer Studio 顯示訊息[Vfp6.exe doesn't contain debugging information]時,選取[Yes]繼續。
有關在 Visual C++ 中除錯的詳細內容,請參閱 Visual C++ 文件。

用其他除錯工具進行除錯
您可以用任何除錯工具來除錯一個函數庫,只要該除錯工具能夠正確處理程式中的 INT 3 (_BreakPoint( ))。如果除錯工具能夠做到下列幾點,那麼便可用來進行符號除錯:

從一個映象檔案製作一個符號表。


獨立於程式載入該符號表。


重新給這些符號分配一個新位址。
如何除錯一個函數庫

在函數要開始除錯的地方新增一個 _BreakPoint( ) 呼叫。


建立該控制項或函數庫。


啟動除錯工具。


如果除錯工具支援符號除錯,請載入函數庫的符號表。


啟動 Visual FoxPro。


從 Visual FoxPro 呼叫函數庫程式。


當達到中斷點時,調整符號基址,把符號與函數庫的實際載入位置對齊。


給指令指標 (IP) 暫存器加 1,超過 INT 3 指令。


如同除錯普通程式一樣繼續除錯。
附註 在分送您的產品之前,一定要移除您的除錯工具中所有指定的中斷點。

********************************************************************
http://www.dfpug.de/konf/konf_1995/oop/SessionE-C++.htm


The Library Construction Kit



The Library Construction Kit (LCK) that comes with the Professional Version of Visual Foxpro allows you to write C and C++ programs to extend the capabilities of your Foxpro programs. You can directly control hardware, improve performance, or do other tasks not possible within a Foxpro program.

The LCK consists of only 2 necessary files: PRO_EXT.H which defines the LCK to the Visual C compiler, and WINAPIMS.LIB, which is the library file that contains the interface code to Visual Foxpro. Other files are included as samples. To use it, you'll need Visual C 2.x.

An FLL is a DLL that includes two Foxpro specific structures. A DLL is the same as an EXE file, except that it can't run by itself. It contains routines and data that can be used by any number of clients.

Welcome to the 32 bit world

Visual Foxpro is a 32 bit product throughout. Foxpro 2.x for Windows is also a 32 bit product internally, but it was written for the 16 bit Win API, which means that 2.x FLLs are 16 bit.

A 16 bit application can only address 2^16, or 65536 bytes directly. It uses the microprocessor in 16 bit mode, where each machine register is 16 bits wide. In order to handle applications that require more memory, Intel implemented a segmented addressing scheme, whereby memory is addressed in 64K segments. This limitation makes it much more difficult to develop programs, which have to handle memory addresses as pairs of 16 bit numbers.

A 32 bit application uses the microprocessor in 32 bit mode, which means that all registers are 32 bits wide. Directly addressing 2^32, or 4 Gigabytes makes it much easier to write complicated applications.

All FLLs that worked with 2.x will have to be recompiled to work with Visual Foxpro. The LCK has not changed much from 2.x, so many libraries will work unmodified after recompilation.

For your first FLL, create a file called LCK.CPP with these contents:



#include <pro_ext.h>

void MyFunc(ParamBlk *p) {

_Execute("wait window nowait 'Hello world'");

}



FoxInfo myFoxInfo[] = {

{"MYFUNC" , (FPFI) MyFunc,2,".?.?"}

};



extern "C" FoxTable _FoxTable = {

(FoxTable FAR *)0, sizeof(myFoxInfo)/ sizeof(FoxInfo), myFoxInfo

};



Start MS VC and Choose FILE\NEW\Project from the VC main menu and choose to create a DLL. Add LCK.CPP to your project.

Change the following settings:

Set the "Project\Settings\Link\OutputFileName" to LCK.FLL
Add "WINAPIMS.LIB" to the "Project\Settings\Link\ObjectLibrary modules"
"Project\Settings\C/C++\Category=CodeGeneration\Calling Convention" = _FastCall
"Project\Settings\C/C++\Category=CodeGeneration\RunTimeLibrary" = Multithreaded Using DLL
"Tools\Options\Directories\IncludeFiles" - add an entry pointing to PRO_EXT.H
"Tools\Options\Directories\LibraryFiles" - add an entry for the directory containing WINAPIMS.LIB
Choose "Project\RebuildAll" and VC will start compiling your FLL.
From within Visual Foxpro, change to the appropriate directory and type:
SET LIBRARY TO lck
=MyFunc()
If everything goes well, you've successfully created your first FLL!

Every FLL must #INCLUDE the file PRO_EXT.H, and every FLL must have the last two structures in LCK.CPP. The first structure FoxInfo is a list of all functions in the FLL that will be callable from Visual Foxpro. It also specifies the corresponding C function name, number and types of parameters passed to each function.

The second structure FoxTable has a single entry which points to the FoxInfo structure and indicates the number of entries to be found in there.

If you name your program with a .C extension, the C compiler will treat it as a C program. The .CPP extension indicates a C++ program. Since Visual Foxpro expects the FoxTable structure as a C exported name, 'extern "C"' is necessary to tell the compiler to name the FoxTable structure according to the C rules, rather than the C++ rules.

The FoxInfo structure for our sample indicates that our function, MYFUNC(), can take up to two parameters, of any type. If a funtion were to take 3 parameters, 2 of which were required, it might look something like:

{"MYFUNC" , (FPFI) MyFunc,3,"CD.N"}

The letters indicate the type of parameter passed (Character, Date), and the "." precedes the optional third numeric parameter.

Foxpro variables within an FLL are represented by a Value structure, which is defined in PRO_EXT.H as:

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;

Not all the fields in the Value structure are used simultaneously. The ev_type member contains the type of the variable, as returned by the TYPE() function: C for character, etc. So, if ev_type = 'I', then the value of the variable is in ev_long.

Character variables are a little more complex. When the ev_type = 'C', the ev_handle is a handle to the string. A handle is just a number, which is used as an index into a table to find the address of the string. Since strings can be of any length, they can take quite a bit of memory, and that memory can be moved around or swapped out to disk.

To obtain the actual string, first you need to lock the handle using _HLock(), then call a function to convert the handle to a pointer _HandToPtr().

When a parameter is passed by reference, the Locator structure is used:

typedef struct {

char l_type;

short l_where, /* Database number or -1 for memory*/

l_NTI, /* Variable name table offset */

l_offset, /* Index into database */

l_subs, /* # subscripts specified 0 <= x <= 2*/

l_sub1, l_sub2; /* subscript integral values */

} Locator;



NTI is an index into the Name Table, which holds information about user symbols. If it’s an array, then l_subs indicates the number of subscripts. If it’s an array element, then l_sub1 and l_sub2 indicate the subscript values.

The _Load() and _Store() functions allow your FLL program to read and write values directly into Foxpro variables. They take a Value and a Locator as parameters, and load or store one into the other.

There are dozens of other callback functions that allow your FLL program to call back into Foxpro to accomplish tasks. For example:



_Execute("Create table names (name c(100))");

_Execute("index on name tag name");



You could write your whole app in C, making callbacks!

Run your FLL with VC

You can use VC to examine Foxpro variables very easily. Change "Project\Settings\Debug\Executable for Debug session" to c:\fox30\vfp.exe or wherever you've installed VFP. You can specify the working directory and additional program arguments from the same options dialog.

Highlight a line of source code in your FLL and hit the F9 key which sets a breakpoint on that line. Choose Debug\Go. A dialog correctly indicates that VFP.EXE doesn't contain debug information. Since we're not debugging VFP.EXE, which has no bugs in it, choose to continue. When execution reaches your breakpoint, VC automatically comes to the foreground, and you can inspect variables, memory, registers, the call stack, etc.



Why would you want to use the LCK?

Executing C code is inherently much faster than executing Foxpro code. In fact, every Foxpro statement causes multiple lines of C code to be executed. Visual Foxpro itself is written in C and C++, as is the majority of commercially available software, including operating systems like Windows.

Foxpro allows you to call C code easily. If it's your own C code, you can use the LCK. If it's C code inside another DLL, you can use Foxtools or the DECLARE DLL command. However, sometimes it's easier to call C code from within a C program. For example, your PRG can call WIN API routines and pass parameter types that Foxpro supports, but passing structures is not as easy as in C.

Here's a simple example. A graphics program allows the user to draw lines and set pixels on a form. Suppose you want a program that will paint an area delimited by black pixels to be filled in black. Given a two dimensional array of pixels which represent the bitmap, and a single point within a shape in the bitmap, how do we toggle the pixels within the shape so as to do an area fill?

This is a great interview question, and it turns out there's an elegant 8 line solution.

FILL(x,y)

IF point(x,y) # 0 && if it's not filled

Set(x,y) = 0 && fill it

Fill(x+1,y) && fill the point to the East

Fill(x-1,y) && fill the point to the West

Fill(x,y-1) && fill the point to the North

Fill(x,y+1) && fill the point to the South

ENDIF



This recursive algorithm makes many calls to itself, and thus eats up a lot of stack space. If the line to be filled contains 100 pixels that are not filled yet, the program will call itself 100 times.

Visual Foxpro allows 128 DO levels, so this algorithm will only work for small areas. Using the LCK, creating an example that correctly fills areas is pretty straightforward, and it executes much faster than the non LCK solution. Not only do we get a performance gain, but it's impossible to run the algorithm as written with VFP's stack limitation.

Modifying the program to keep track of maximum stack depth, moderately sized shapes to fill can take tens of thousands of recursive stack levels!

The sample program below creates and displays a form. Two simple shapes are added to the form to create outlines bounding areas to be filled. There are 2 fill routines called for comparison: 1 in Foxpro and 1 written via the LCK.

The FillX method is a recursive method that just implements the simple area fill algorithm above. It’s called first to fill a small box. Because of Foxpro’s limit on the number of DO levels, this routine can’t be used to fill very large areas without running into stack overflow problems.

The Fill method calls the dofill C routine in the LCK below. It also implements the same recursive fill algorithm above, but it’s written in C and will use the C stack, which is limited only by memory.

The other methods such as MouseDown, etc. are used so you can use your mouse to draw your own shape on the form to be filled. Shift-Click in the center of an area to be filled, and the DoFill algorithm will be called. Summary statistics on the number of recursive levels used and the time taken are displayed as well.

Beware that you don’t try to paint an unbounded area: there is no bounds checking and your program will go off to never never land.

In the FLL, there are actually two functions to do the Fill: one called Fill, and the other called FillFast. The first does the same as the PRG: it calls the VFP PSET and POINT methods to set and get pixel values.

FillFast bypasses VFP altogether and uses the WIN API to Get and Set the pixels directly, and is much faster. However, it doesn't respect things like the object's foreground/background color for the fill. This demonstrates that even though it’s written in C, a program won’t necessarily be faster.

clea all

declare integer GetTickCount in win32api

PUBLIC ox

ox = Create("myForm")

ox.show

ox.addobject("shp","myshape")

ox.addobject("shp2","myshape")

ox.shp2.top = 70

ox.shp2.width = 20

ox.shp2.height = 10

wait wind "" time .1

ox.fillx(102,52)

ox.fill(102,72)



DEFINE CLASS myshape AS shape

visible = .t.

left = 100

top = 50

width = 6

height = 9

proc mouseup(btn,shft,m.x,m.y)

thisform.mouseup(btn,shft,m.x,m.y)

proc mousedown(btn,shft,m.x,m.y)

thisform.mousedown(btn,shft,m.x,m.y)

proc mousemove(btn,shft,m.x,m.y)

thisform.mousemove(btn,shft,m.x,m.y)

ENDDEFINE



DEFINE CLASS myForm AS FORM

pendown = .f.

left = 100

add object cmdQuit as Commandbutton WITH ;

caption= "Quit",cancel=.t.

add object cmdErase as Commandbutton WITH ;

caption= "Erase",left = 120

proc init

set library to fill.fll

proc destroy

release library fill.fll

proc fill(m.x,m.y)

LOCAL mx,my,start,max

start = GetTickCount()

max=dofill(m.x,m.y)

wait wind nowait "LCK Fill #levs = " + str(max) + ;

" secs "+ str( GetTickCount() - start)

proc fillx(m.x,m.y)

IF this.point(m.x,m.y) # 0

this.pset(m.x,m.y)

this.fillx(m.x + 1, m.y)

this.fillx(m.x - 1, m.y)

this.fillx(m.x , m.y - 1)

this.fillx(m.x , m.y + 1)

ENDIF

proc mousemove(btn,shft,m.x,m.y)

if this.pendown

thisform.line(m.x,m.y)

endif

proc mouseUp(btn,shft,m.x,m.y)

this.pendown = .f.

proc mousedown(btn,shft,m.x,m.y)

IF shft>0

this.fill(m.x,m.y)

ELSE

this.pendown = .t.

this.currentx = m.x

this.currenty = m.y

ENDIF

proc cmdquit.click

thisform.release

proc cmdErase.click

thisform.cls

ENDDEFINE



//Fill.CPP:



#include <pro_ext.h>



int MaxLev,CurLev;

NTI mxNTI,myNTI;

Locator mxLoc,myLoc;

Value val;

void fill(int x,int y) {

CurLev++;

if (CurLev > MaxLev) MaxLev = CurLev;

_Evaluate(&val,"inkey()");

if (val.ev_long != 0) {

_UserError("abort");

}



val.ev_type = 'I';

val.ev_long = x;

_Store(&mxLoc,&val);

val.ev_long = y;

_Store(&myLoc,&val);

_Evaluate(&val,"this.point(mx,my)");

if (val.ev_long == 16777215) {

_Evaluate(&val,"this.pset(mx,my)");

fill(x+1,y);

fill(x-1,y);

fill(x,y+1);

fill(x,y-1);

}

CurLev--;

}



HDC hdc;

HWND hwnd;



void fillfast(int x,int y) {

CurLev++;

if (CurLev > MaxLev) MaxLev = CurLev;

if (GetPixel(hdc,x,y) != 0) {

SetPixelV(hdc,x,y,0);

fillfast(x+1,y);

fillfast(x-1,y);

fillfast(x,y+1);

fillfast(x,y-1);

}

CurLev--;

}



void fillt(int x,int y) {

hwnd = _WhToHwnd(_WFindClientTitle("Myform1"));

if (!hwnd ) {

_UserError("no hwnd");

}

hdc = GetDC(hwnd);

MaxLev = 0;

fillfast(x,y);

ReleaseDC(hwnd,hdc);

_RetInt(MaxLev,10);

}



void DoFill(ParamBlk *p) {

int x,y;

mxNTI = _NameTableIndex("mx");

myNTI = _NameTableIndex("my");

_FindVar(mxNTI,0,&mxLoc);

_FindVar(myNTI,0,&myLoc);

x= p->p[0].val.ev_long;

y= p->p[1].val.ev_long;

MaxLev = 0;

fillt(x,y);

_RetInt(MaxLev,10);

}



FoxInfo myFoxInfo[] = {

{"DOFILL" , (FPFI) DoFill,2,"N,N"}

};



extern "C" FoxTable _FoxTable = {

(FoxTable FAR *)0, sizeof(myFoxInfo)/ sizeof(FoxInfo), myFoxInfo

};

Number Crunching

Another example of a gain in performance from the LCK is in number crunching. A perfect number is defined as a number N that is equal to the sum of all of its divisors. The first part of this VFP program calculates the perfect numbers below 1000 in 13 seconds on my Pentium 90 under NT. The second part uses the LCK and gets the same results in less than 1 second.

Note: in order for this sample to work, the FLL must be written in C++, and not in C, because the code takes advantage of some of the C++ extensions to C, such as in line declaration of variables.



#define END 1000

clear

Declare integer GetTickCount in win32api

start = GetTickCount()

FOR n = 1 to END

s = 0

FOR j = 1 to n - 1

IF n / j = int(n / j)

s = s + j

ENDIF

ENDFOR

IF s = n

?n

ENDIF

ENDFOR

? str(END,6)+ " VFP done in " + str((GetTickCount() - start) / 1000,5,3)

?

start = GetTickCount()



SET LIBRARY TO fill.fll

=perf(END)

SET LIBRARY TO

? str(END,6)+ " LCK done in " + str((GetTickCount() - start) / 1000,5,3)

return



// FLL function Perf to find perfect numbers

void Perf(ParamBlk *p) {

int max = p->p[0].val.ev_long;

char buf[100];

for (int n = 1 ; n < max ; n++) {

int s = 0;

for (int j = 1 ; j < n ; j++) {

if ( n == j * ( n / j)) {

s+=j;

}

}

if (s == n) {

sprintf(buf,"%d\n",n);

_PutStr(buf);

}

}

}

SAMPLE C++ CLASSES

The below samples show how to integrate C++ classes into an LCK module. Strings are a common sample class when dealing with C++, and for the LCK, it's a great example of how to create a class that is very useful and it hides the complexities of string handling.

A Foxpro string is represented in a Value structure, with the ev_type = 'H' and the ev_handle being a handle (an identifier) with which to refer to the string. The ev_length member is the length of the string. For a C program to access this string, the handle has to be locked, using _HLock(), then converted to a pointer, using _HandToPtr(), and then unlocked. Creating a new string requires a call to _AllocHand to get a new handle.

The CString class in the sample below is a very simple string class with just 2 members: m_len (the length of the string) and m_ptr (a pointer to the string).

The CLckString class inherits from the CString class, and has some more useful members and member functions (methods, in VFP parlance). Some of the basic methods include multiple constructors for the various ways to initialize a string, and various operator overloads, so we can easily write MyStrobj1 = MyStrobj2 + MyStrobj3, and have it work.

Fancier methods are GetFPVar and PutFPVar, which will get a Foxpro variable name and store the string value into a CLckString object, or take the string object and put it into a Foxpro variable name.

The Foxapp class is instantiated at FLL load time, even before the CALLONLOAD function Initialize. This can be verified by placing a breakpoint on the Initialize function and the Foxapp constructor function. This class has a single member function Executef, which will execute any single line Foxpro function. You can add more member functions to this framework.

CODE: SEE COMPANION DISK

New LCK Functions in Visual Foxpro 3.0

There are eight new LCK functions in Visual Foxpro that were added to support the new Object type. The Professional Edition of Visual FoxPro contains the following additional API routines:



_FreeObject( )

_GetObjectProperty( )

_ObjectCmp( )

_ObjectReference( )

_ObjectRelease( )

_SetObjectProperty( )

_WGetObjectClientWindow( )

_WGetObjectWindow( )



These are described in the Readme.hlp file. The Value structure was also changed to accomodate object references as parameters.



Calling other DLLs

You can use the DECLARE DLL command to call most of the thousands of Win API functions or any other functions that are exported by DLLs. The professional version of Visual Foxpro includes a help file called WIN32API.HLP which documents the Win32 API. For example, you can call the Win32 API directly to find the title of the currently active window:



DECLARE INTEGER GetActiveWindow IN win32api

DECLARE INTEGER GetWindowText IN win32api Integer, String, Integer

hwnd = GetActiveWindow()

buf = space(100)

=GetWindowText(hwnd,@buf,len(buf))

?buf

The GetUserName function returns the name of the user currently logged into the system.

declare integer GetUserName in win32api string, integer @

buf = space(100)

slen = len(buf)

=GetUserName(@buf,@slen)

?buf



Here's a way to bring another application to the foreground:

declare integer FindWindow in win32api string,string

declare integer SetForegroundWindow in win32api integer



clear

ll=FindWindow(0,"Mail")

if ll>0

lw=SetForegroundWindow(ll)

endif

clear dlls



Using the "win32api" keyword in the Declare DLL command is a shortcut. Normally, a user has to know in which DLL a particular function resides. The Win32api functions reside in several DLLs: Kernel32.DLL, GDI32.DLL, etc. The Win32API shortcut tells VFP to search through all these DLLs, and thus keeps the user from having to know in which DLL the function lives. This is especially useful since although there is plenty of documentation for the Win32API, none of it indicates in which DLL a function resides.

The new Declare DLL command is quite powerful, but you can't call 16 bit DLLs with it. You can use Foxtools to call 32 or 16 bit DLLS, using the RegFN() and CallFN() functions. There's a new function called RegFN32(), which registers a 32 bit DLL. RegFN() registers a 16 bit DLL

Another limitation of the DECLARE DLL and Foxtools way of calling DLLs is that functions that require complex parameters may be difficult or impossible to call from within VFP directly. These parameters might be structures of arrays, arrays of structures, pointers, or some combination of these. Calling them from within an FLL is easy.

If you attend my OCX session, you’ll see how you can extend Visual Foxpro using C and C++ via OCXs very easily. An FLL is specific to Visual Foxpro, but an OCX can be used in Visual Basic, Visual C++, and any other language that can host an OLE Custom Control.

The LCK allows Visual Foxpro users to extend their apps in many ways. We’ve looked at performance, hardware control, and access to DLLs with complex parameters. Using VC with the LCK makes it easy to write C and C++ programs to explore this very powerful programming tool.


***************************************************************************************************
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnarfoxgen/html/msdn_lck.asp

Creating ActiveX Components with the Visual FoxPro API/LCK
Calvin Hsia
Microsoft Corporation

September 2, 1998

Introduction
MicrosoftR Visual FoxProR 5.0 and its ancestors such as MicrosoftR FoxPro? for MS-DOS and MicrosoftR FoxBASE+R, have always included a way to extend programmability with extensions to other languages. Developers can take advantage of this extensibility to directly address machine hardware, call operating system functions, create exceptionally fast low-level routines, and so on.

The FoxBASE+ LOAD and CALL functions let developers create functions written in Assembly code (.COM or .BIN modules) to do specialized tasks such as take a string as a parameter and display it on the screen in a much larger font (no small feat in the pregraphical user interface MS-DOSR era). The LOAD and CALL functions had many drawbacks: the Assembly code had to be very carefully written, parameter passing was extremely limited, it was difficult to write in C, and it could not be used by products other than FoxBASE+.

FoxPro for MS-DOS later introduced the Library Construction Kit (LCK). The LCK consists of two key files: a header file included in a C program and a LIB file with which the C program is linked. The LCK allows functions that can be called from a FoxPro program, just as any user-defined function (UDF) is called, to be written in C and C++. Argument passing is the same as a FoxPro UDF, allowing complex UDFs to be created. The FoxPro LCK is a vast improvement over the FoxBASE+ .COM modules that were LOADed and CALLed.

One of the most powerful features of the FoxPro LCK is the ability to create functions written in C and C++ that are callable from FoxPro. Another powerful feature is the ability of the same functions to call back into FoxPro to manipulate records in a table, the editing environment, FoxPro variables, and so on. There are over a hundred callback functions within FoxPro that the C and C++ programs can call. FOXTOOLS.FLL uses several of these callback functions.

Visual FoxPro Version 5.0 extends the capabilities of the LCK one step further. It enables C and C++ programmers to create ActiveXR controls that can take advantage of the hundreds of Visual FoxPro callback functions. An ActiveX control can be written in several ways so that it:

works with all products that can host an ActiveX control
only works within Visual FoxPro 5.0
has two different modes depending upon whether Visual FoxPro hosts the ActiveX control or not
Creating an ActiveX Control
It's easy to create an ActiveX control because Visual CR version 2.0 and later provide the OLE Control Wizard now integrated into the Application Wizard.

To create an ActiveX control:

Choose New from the File menu.
Choose Project workspace.
Give the project a name, then type it in.
Choose OLE Control as the project type.
Answer the Wizard's questions and click Finish

_________________
利用>>搜尋<<的功能會比問的還要快得到答案.


garfield 在 星期一 四月 11, 2005 3:56 pm 作了第 1 次修改
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
garfield
Site Admin


註冊時間: 2003-01-30
文章: 2157


第 2 樓

發表發表於: 星期五 四月 08, 2005 11:19 am    文章主題: FLL 樣版檔 引言回覆

謝天謝地, 終於找到了樣版檔, 不然help檔看了一堆還是不知道如何寫一支fll檔.

原始下載處:
http://www.fastwrite.com/Dvlonly/downloads/ThisDownload.cfm?RID=9

_________________
利用>>搜尋<<的功能會比問的還要快得到答案.
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
從之前的文章開始顯示:   
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區 所有的時間均為 台北時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
無法 在這個版面附加檔案
無法 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作