OracleDeveloper/2000是Oracle的微機開發工具,由於它與Oracle數據庫的緊密連接,比用PowerBuilder或其它高級語言采用ODBC與Oracle的連接享有得天獨厚的優點,越來越在Windows95和WindowsNT平台上得到廣泛應用,筆者在用其進行程序設計時感到,既然是在Windows平台上開發程序,如果能在其中應用一些WindowsAPI函數,將使Developer/2000有如虎添翼的感覺,可以大大彌補它與底層操作系統的聯系能力差、控制實時硬件設備功能差的缺點,開發出集成性更好的應用程序。
所有用第三方語言編寫的子程序對Developer/2000都稱為外部函數,WindowsAPI函數也是外部函數。這些外部函數必須包含在一個動態庫中。例如Windows操作系統下的動態鏈接庫或UNIX系統下的共享庫等。Developer/2000通過為每一個外部函數產生一個PL/SQL接口,它使用PL/SQL的語法,在程序中調用這一接口程序就可以激活這一外部函數。
對一個外部函數產生一個PL/SQL接口,需要用到內建軟件包ORA-FFI,它包含一些PL/SQL的子程序用來對外部函數生成PL/SQL接口,實際操作時可以用ProcedureBuilder產生一個程序庫,在程序庫中建立一個程序包(Package),在這個包中實現對外部函數建立連接。下面介紹這一過程的具體步驟:
1.初始化外部函數
就是說明包含外部函數的動態鏈接庫的位置,並從中分離出外部函數的原型,並將外部函數中主語言的數據類型和PL/SQL數據類型做一一對應的匹配。這是在包體(PackageBody)中進行的。具體分以下幾步:
(1)用OQA_FFI.LOAD_LIBRARY得到包含外部函數的動態鏈接庫的庫柄,此時需提供動態鏈接庫的名字和位置。
(2)用ORA_FFI.REGISTER_FUNCTION得到外部函數的函數柄,這時需提供動態鏈接庫的庫柄和外部函數名。
(3)用ORA_FFI.REGISTER_PARAMETER來注冊外部函數的參數類型,對每一個參數都要提供它的外部函數柄和相應的PL/SQL數據類型。參數注冊的順序必須與它們出現在外部函數原型中的順序一致。
(4)用ORA_FFI.REGISTER_RETURN來注冊外部函數的返回值類型,這時需要提供它的外部函數柄和相應的PL/SQL數據類型。
2.將外部函數和一個PL/SQL子程序相關聯
一個和外部函數建立關聯的PL/SQL子程序,實際上指明了外部函數的內存地址,每次調用這個子程序,實際上是調用與它相對應的外部函數。具體步驟為:
(1)用ORA_FFI.FIND_FUNCTION或ORA_FFI.REGISTER_FUNCTION得到一個函數柄。
(2)在PL/SQL包體的聲明部分,定義一個PL/SQL子程序,它的第一個參數是類型為ORA_FFI.FUNCHANDLETYPE,接下來是依次對應外部函數參數的PL/SQL數據類型的參數。
(3)在這個PL/SQL子程序中加入一個PRAGMA接口。PRAGMA聲明就是通過將控制轉到一個內存地址,來激活這個外部函數。
3.生成一個模仿外部函數的原型的PL/SQL子程序。
這個子程序就是用戶可見的外部函數的PL/SQL接口,用戶按照它的參數類型和返回值類型來使用外部函數,具體步驟為:
(1)在包體的聲明部分,定義一個PL/SQL子程序,它的參數和返回值是和外部函數對應的PL/SQL類型。這就是模仿外部函數原型的一個子程序。
(2)在這個子程序中調用與上步生成的與外部函數相關聯的PL/SQL子程序。
(3)在PL/SQL包的說明(PackageSpefication)部分,輸入這個PL/SQL子程序的原型。
下面是一個完整的為WindowsAPI函數winexec建立PL/SQL接口的例子:
PACKAGEWinExecIS FUNCTIONWinExec(ExecfileINVARCHAR2, commandINPLS_INTEGER) RETURNPLS_INTEGER; END;/*在包說明部分,是模仿外部 函數原型的PL/SQL函數原型說明*/ PACKAGEBODYWinExecIS lh_USERora_ffi.libHandleType;/*定義庫柄類型變量*/ fh_WinExecora_ffi.funcHandleType;/*定義函數柄類型變量*/ FUNCTIONi_WinExec(funcHandleINora_ffi.funcHandleType, ExecfileINOUTVARCHAR2, commandINPLS_INTEGER) RETURNPLS_INTEGER; PRAGMAINTERFACE(C,i_WinExec,11265); /*步驟2將一個PL/SQL子程序與外部函數相關聯*/ FUNCTIONWinExec(ExecfileINVARCHAR2, commandINPLS_INTEGER) RETURNPLS_INTEGER IS execfile_lVARCHAR2(512):=Execfile; rcPLS_INTEGER; BEGIN rc:=i_WinExec(fh_WinExec, execfile_l, command); RETURN(rc); END; /*步驟3中PL/SQL模仿函數的定義, 它實際上就是調用步驟2中與外部函數建立關聯的那個函數*/ BEGIN BEGIN lh_USER:=ora_ffi.find_library('Kernel32.dll'); EXCEPTIONWHENora_ffi.FFI_ERRORTHEN lh_USER:=ora_ffi.load_library(NULL,'kernel32.dll'); END;/*得到動態鏈接庫的庫柄*/ fh_WinExec:=ora_ffi.register_function (lh_USER,'WinExec',ora_ffi.PASCAL_STD); /*得到外部函數的函數柄*/ ora_ffi.register_parameter(fh_WinExec, ORA_FFI.C_CHAR_PTR);/*參數注冊,原類型為LPCSTR*/ ora_ffi.register_parameter(fh_WinExec, ORA_FFI.C_INT);/*參數注冊,原類型為UINT*/ ora_ffi.register_return(fh_WinExec, ORA_FFI.C_INT);/*返回值注冊,原類型為BOOL*/ ENDWinExec;
可以將多個外部函數的PL/SQL接口放在一個包內。要在Developer/2000的FormDesigner中使用這些外部函數,只要把包含這一程序包的程序庫(.PLL)附加進來,使用包名.函數名就可激活這個外部函數。
例如:WinExec.WinExec('c:\Windows\notepad.exe',0)
具體WindowsAPI函數數據類型和PL/SQL數據類型的轉換可參照Developer/2000中ProcedureBuilder幫助文件中對ORA_FFI軟件包的詳細介紹。