Lotus Notes/Domino 的C API程式設計
瞭解使用 Lotus Notes/Domino C API 進行程式設計的來龍去脈。本文將解釋 C API 工具箱中發現的一些重要特性,並提供一些可以用來滿足您需求的應用示例。
使用 Lotus C API for Lotus Notes/Domino 常常使人想起一把方便好用的老式瑞士軍刀:一個時髦的小工具箱,包含許多沒有書面文件的(undocumented)有用部件!本文旨在重點介紹 Lotus C API for Lotus Notes/Domino 的一些功能,幫助開發人員重新發現其無限的潛在用途。對 Lotus Notes/Domino 有基本的瞭解並熟悉程式語言就足以應付本文的內容。C 程式語言的應用知識可以幫助您更好地理解我們討論的一些概念。
可以通過訪問 Toolkits & Drivers page 下載 Lotus C API toolkit for Lotus Notes/Domino。本文的目的是想將該工具箱用於 Windows 平臺上的 Lotus Notes/Domino 6.5。在將下載的檔案檔案中的這些檔案解壓縮之後,就可以獲得文件、標頭檔案、庫檔案、已編譯的 OBJ 檔案、示例程式和示例中使用的資料庫。
文件中包括一個使用者指導和一個參考指導,它們都是以單獨 Notes 資料庫的形式出現的。您可以從文件中獲得許多資訊。同時,使用者指導中包含可以使用該工具箱完成哪些任務以及如何完成這些任務的介紹,而參考指導記錄了所有可用功能。請仔細考慮一下這些資料庫中包含的大量資訊,這對為資料庫建立全文(full-text)索引很有用,這樣就可以快速準確地進行查詢。
標頭檔案通常可以在 Include 資料夾中找到。它們包含用於所有可作為該工具箱的一部分的常數、結構、巨集、公共函式的定義。您需要根據程式中使用的 API 呼叫在原始碼中包含相應的標頭檔案。庫檔案和已編譯的 OBJ 檔案通常可以在不同作業系統的特定資料夾下的 Lib 資料夾中找到。因為 LIB 檔案是需要連結到 API 程式的 DLL 匯入庫,所以 OBJ 檔案是使用 NotesMain 入口點的程式或完成外掛伺服器任務所需的載入程式物件。(我們將在文章的後面部分再次回顧這些內容。)
示例資料夾中提供了一個詳盡的示例程式列表。notedata 資料夾通常包含示例程式中用到的所有資料庫。參考指導中描繪了每個函式或符號值,它們至少可以被一個示例程式引用,您可以檢視該參考指導,以便了解如何在實際程式中使用即將檢查的函式。
在明白了我們必須做什麼之後,繼續研究該工具箱的最好辦法就是鑽研一個實際的程式。在下一節中,我們將通過遍歷兩個不同的程式來研究該工具箱。
讓我們從一個簡單的程式開始:一個輸出 Notes 資料目錄的完全路徑的程式。首先,讓程式中所需的 C 庫中包含標頭檔案:
#include接下來,新增來自 Lotus C API for Lotus Notes/Domino 的標頭檔案:
#include現在,主函式的任務是呼叫 NotesInitExtended() 函式來初始化 Notes 執行庫。除非使用的是 NotesMain() 函式而不是 main() 函式,否則必須顯式呼叫 NotesInitExtended() 函式:
int main(int argc, char *argv[]) { char DataDir[256]; STATUS error = NOERROR; WORD wlength; if (error = NotesInitExtended (argc, argv)) { printf("\n Unable to initialize Notes.\n"); return (1); } |
最後,我們獲得資料目錄並輸出它。OSGetDataDirectory() 是這個程式中使用的主要 Lotus C API 函式。顧名思義,OSGetDataDirectory() 包含資料目錄的完全路徑。NotesTerm() 函式關閉了 Notes 執行庫,以結束函式的執行。只有在使用 NotesInitExtended() 啟動執行庫的時候,我們才必須顯式呼叫該函式:
wlength = OSGetDataDirectory(DataDir); if (wlength > 0) printf("\n The data directory is %s", DataDir); NotesTerm(); return (0); } |
接下來,我們要編譯和連結剛才編寫的程式。為此,需要確保已正確地建立了使用環境。當然,最重要的要求是安裝 Lotus Notes 和 Lotus C API toolkit for Lotus Notes/Domino 的匹配版本。此外,還需要 Microsoft Visual C++ 開發環境,以及隨該環境一起提供的 Microsoft C/C++ 編譯器和庫。最後,我們需要設定三個環境變數:
- PATH 變數值應該包含 Notes 程式目錄和 Microsoft C Compiler 所在的目錄。
- INCLUDE 變數應該包含 Lotus C API 安裝所需的 Include 目錄和 Microsoft C Include 目錄。
- LIB 變數應該包含 Lotus C API 安裝所需的用於 Windows 32 平臺的 Lib 目錄和 Microsoft C Lib 目錄。
如果您喜歡動態地安裝環境變數,那麼可以使用批處理檔案。以下是一個示例批處理檔案:
@echo off rem *** Comments: rem *** C:\Lotus\Notes is the program directory for Lotus Notes 6.5; rem *** C:\Program Files\Microsoft Visual Studio\VC98\ is the rem *** directory where Microsoft Visual C++ is installed; and rem *** c:\notesapi is the directory where the Lotus C API for rem *** Lotus Notes/Domino 6.5 is installed. set Path=.;C:\Program Files\Microsoft Visual Studio\VC98\bin; C:\Program Files\Microsoft Visual Studio\VC98\..\Common\MSDEV98\bin; C:\Program Files\Microsoft Visual Studio\VC98\..\Common\Tools;c:\Lotus\Notes set LIB=C:\Program Files\Microsoft Visual Studio\VC98\lib; C:\Program Files\Microsoft Visual Studio\VC98\Platformsdk\Lib; C:\Program Files\Microsoft Visual Studio\VC98\mfc\lib;C:\notesapi\lib\mswin32 Set INCLUDE=.;C:\Program Files\Microsoft Visual Studio\VC98\PlatformSDK\include; C:\Program Files\Microsoft Visual Studio\VC98\include; C:\Program Files\Microsoft Visual Studio\VC98\atl\include; C:\Program Files\Microsoft Visual Studio\VC98\mfc\include;C:\notesapi\include |
在執行該批處理檔案之後,也就準備好了用於編譯和連結程式的環境。nmake 工具是 Microsoft Visual C++ 安裝的一部分,在這裡用起來非常得心應手。為該工具提供一個 MAK 檔案,以便為您“製造”應用程式。MAK 檔案指定可交付使用的產品、它們的從屬性和構建這些可交付使用產品的命令(如果它們不存在或者比它們所從屬的產品還要老的話)。讓我們來呼叫已經構造好的程式 simple.c。以下是可以用來構建 simple.exe 的 MAK 檔案的一個示例:
# Comment: # The MAK file for simple.c - a simple Notes API program !include |
為了檢查可與 nmake 工具一起使用的選項,可以使用命令 nmake -help。用來構建輸出資料目錄的 simple.exe 程式的命令如下所示:
nmake /f simple.mak /a其中 simple.mak 是我們前面建立的 MAK 檔案,/a 選項指出了我們想構建的所有東西:
可以使用 NotesMain() 函式作為入口點來編寫相同的程式。惟一不同的是,我們不必像在前面的例子中那樣呼叫 NotesInitExtended() 和 NotesTerm()。以下就是這個函式:
/* Simple program to find the data directory using the Lotus C API for Lotus Notes/Domino Using NotesMain() as the entry point*/ /* Include header files that we need from the C library */ #include |
如果您認為該函式改變了 MAK 檔案,那麼您是對的。還記得我們前面談過的載入程式物件嗎?在這裡,我們需要使用這個物件。因此,MAK 檔案使載入程式變成以下這樣:
# Comment: # The MAK file for simplever2.c - a simple Notes API program that uses NotesMain() !include |
讓我們轉移到稍大一點的一個程式上來,該程式使用了比簡單例子中更多的 Lotus C API。該程式將查詢本地地址簿中的一個名稱,如果該名稱是有效的,則返回辦公室電話和地址。這聽起來是不是很有趣?與平時一樣,我們將從程式中需要的 C 庫的標頭檔案開始,然後是來自 Lotus C API 的標頭檔案:
#include |
在這個程式中,我們新增了另一個用於錯誤處理的函式。在這裡,要宣告其原型並從 main() 函式開始。當然,在 main() 函式中,是從宣告所需的所有本地變數開始的。要在構建程式時查明每個變數的用途。接下來要初始化 Notes 執行庫:
void APIErrHandler (STATUS); int main(int argc, char *argv[]) { char *dbname = "names.nsf"; char *viewname = "($users)"; char firstname[256] = ""; char lastname[256] = ""; char key[256]; DBHANDLE dbhandle; NOTEHANDLE notehandle; NOTEID viewid; HCOLLECTION collhandle; COLLECTIONPOSITION collpos; HANDLE bufferhandle; NOTEID *nid; DWORD count; DWORD matches; DWORD whichnote = 0; STATUS error = NOERROR; WORD flg; BOOL found; char *itemname = ""; char itemvalue[256]; WORD itemlen; if (error = NotesInitExtended (argc, argv)) { printf("\n Unable to initialize Notes.\n"); return (1); } |
我們需要用於該程式的命令列,以便查詢
if (argc != 3) { printf("The syntax is: lookup |
接下來,需要開啟地址簿,並對它進行處理。NSFDbOpen() 函式如下所示:
if (error = NSFDbOpen (dbname, &dbhandle)) { APIErrHandler (error); NotesTerm(); return (1); } |
在處理資料庫之後,需要使用 NIFOpenCollection() 函式獲得檢視($users)的設計記錄。NIFOpenCollection() 函式根據檢視記錄處理文件集。如果在這兩個操作中的任何一個操作中出現錯誤,則需要關閉資料庫並退出:
if (error = NIFFindView (dbhandle, viewname, &viewid)) { NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } if (error = NIFOpenCollection( dbhandle, dbhandle, viewid, 0, NULLHANDLE, &collhandle, NULLHANDLE, NULL, NULLHANDLE, NULLHANDLE)) { NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } |
現在我們需要查詢想要在集合中檢視的名稱。NIFOpenCollection() 根據主要分類鍵來搜尋集合,該鍵是檢視的第一個列。(必須對檢視進行分類。)如果找到該名稱,則將它放在指向接受檢查的 COLLECTIONPOSITION 的指標之前。如果該函式在執行期間出錯,則意味著該名稱不存在,或者出現了其他一些錯誤:
error = NIFFindByName ( collhandle, key, FIND_CASE_INSENSITIVE | FIND_FIRST_EQUAL, &collpos, &matches); if (ERR(error) == ERR_NOT_FOUND) { printf ("\nNo such name in the address book.\n"); NIFCloseCollection (collhandle); NSFDbClose (dbhandle); NotesTerm(); return (0); } if (error) { NIFCloseCollection (collhandle); NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } |
通過所獲得的 COLLECTIONPOSITION,可以呼叫 NIFReadEntries() 函式得到我們感興趣文件的 NoteID。該函式將所需資訊放置在 bufferhandle 中,我們將允許其指標進入。此外,我們將忽略一些上下文中不需要的引數(比如 count 和 flg)。然而,如果期望在緩衝區中返回的資訊在大小上並不是微不足道的,那麼需要在一個迴圈中封閉對 NIFReadEntries() 的呼叫,並測試 flg 引數的值。如果有太多的資料而無法將它們都放入緩衝區中,那麼要在 flg 引數中設定 SIGNAL_MORE_TO_DO 位。如果在函式返回之後,緩衝區為 NULL,則需要退出:
if (error = NIFReadEntries( collhandle, &collpos, (WORD) (NAVIGATE_CURRENT), 0L, NAVIGATE_NEXT, matches - whichnote, READ_MASK_NOTEID, &bufferhandle, NULL, NULL, &count, &flg)) { NIFCloseCollection (collhandle); NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } if (bufferhandle == NULLHANDLE) { NIFCloseCollection (collhandle); NSFDbClose (dbhandle); printf ("\nEmpty buffer returned by NIFReadEntries.\n"); NotesTerm(); return (0); } |
既然已經獲得了我們想要獲得的記錄的 NoteID,接下來就可以開啟它。首先,需要使用 OSLockObject() 函式鎖定記憶體中的緩衝區並獲得其地址。我可以將 NoteID 強制轉換為 NOTEID:
nid = (NOTEID *) OSLockObject (bufferhandle); if (error = NSFNoteOpenExt( dbhandle, nid[0], 0, ¬ehandle)) { OSUnlockObject (bufferhandle); OSMemFree (bufferhandle); NIFCloseCollection (collhandle); NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } |
差不多完成了!現在,我們所需要做的一切就是檢查地址和電話號碼是否存在,如果存在,則輸出它們。可以用 NSFItemIsPresent() 檢查這些項是否存在,並用 NSFItemGetText() 獲得這些項的值:
found = FALSE; itemname = "MailAddress"; found = NSFItemIsPresent (notehandle, itemname, (WORD)strlen (itemname)); if (found) { itemlen = NSFItemGetText ( notehandle, itemname, itemvalue, sizeof (itemvalue)); printf("\nMail Address: %s", itemvalue); } else { printf("\nNo Mail Address found"); } found = FALSE; itemname = "OfficePhoneNumber"; found = NSFItemIsPresent (notehandle, itemname, (WORD)strlen (itemname)); if (found) { itemlen = NSFItemGetText ( notehandle, itemname, itemvalue, sizeof (itemvalue)); printf("\nOffice Phone Number: %s", itemvalue); } else { printf("\nNo Office Phone Number found"); } |
通過解除緩衝區的鎖定並釋放其記憶體,然後關閉記錄、集合和資料庫,來結束函式的執行:
OSUnlockObject (bufferhandle); OSMemFree (bufferhandle); if (error = NSFNoteClose (notehandle)) { NIFCloseCollection(collhandle); NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } if (error = NIFCloseCollection(collhandle)) { NSFDbClose (dbhandle); APIErrHandler (error); NotesTerm(); return (1); } if (error = NSFDbClose (dbhandle)) { APIErrHandler (error); NotesTerm(); return (1); } NotesTerm(); return (0); } |
最後一道難題是 APIErrHandler() 函式。該函式獲得與傳遞的錯誤有關的字串,並輸出這些字串。
void APIErrHandler (STATUS error) { STATUS errorid = ERR(error); char errorstring[200]; WORD len; len = OSLoadString (NULLHANDLE, errorid, errorstring, sizeof(errorstring)); printf ("Encountered this error : %s", errorstring); } |
您可能已經注意到以 Lotus C API 函式命名的模式。所有名稱以 NSF 開頭的函式都必須使用資料庫、記錄或項。而那些名稱以 NIF 開頭的函式通常用來處理檢視和集合。處理作業系統級資訊(比如說記憶體中的鎖定物件)的函式名是以 OS 開頭的。在查詢與想歸檔的資訊匹配的函式時,這種命名約定非常有用。
可以從 Sandbox 下載這一節中描述的完整程式。
Lotus C API 在客戶端和伺服器端的一些上下文中都很有用。在這一節中,我們將重點介紹一些可用的選項。
通過使用 Lotus C API,就有可能建立並操縱諸如代理、表單、檢視和導航器之類的設計元素。在建立設計元素時,NOTE_CLASS_xxx 值很重要,因為它會識別我們將建立的記錄的型別。NOTE_CLASS_DOCUMENT 用於文件,NOTE_CLASS_FORM. 用於表單,NOTE_CLASS_VIEW 用於檢視,NOTE_CLASS_FILTER 用於代理和巨集,等等。例如,您可以使用以下函式呼叫來建立一個檢視設計記錄:
WORD ClassView = NOTE_CLASS_VIEW; NSFNoteCreate(hDB, &hNote); NSFNoteSetInfo(hNote, _NOTE_CLASS, &ClassView);您甚至可以使用 NSFFormulaCompile() 和 NSFComputeEvaluate() 函式編譯和評估公式。
可以建立一個在伺服器上執行的伺服器任務,就像建立其他任務那樣。儘管可以讓外掛任務(add-in task)執行某一項操作並退出,但外掛任務通常用於需要定期執行的操作。Lotus C API 提供了一些用來構建外掛任務的特定函式。該程式的主要入口點是 AddInMain() 函式。函式 AddInIdle() 用於控制程式中的主迴圈。
AddInDayHasElapsed()、AddInMinutesHaveElapsed() 和 AddInSecondsHaveElapsed() 可以幫助使用者判斷是否是時候執行定期的操作。可以使用負載
您可以將自己的操作新增到 Notes 客戶機的選單選項 Actions 中。為了做到這一點,入口點必須是一個具有以下格式的函式:
NAMRESULT LNCALLBACK FunctionName (WORD wMsg, LONG lParam)該函式可以擁有任何名稱,但必須在模組定義(DEF)檔案的 EXPORTS 函式中用序數值 1 來宣告它。第一個引數指出將執行的操作,第二個引數是特定於操作的資訊。這項操作可以擁有以下這些值:
NAMM_INIT NAMM_INITMENU NAMM_COMMAND NAMM_TERM |
NAMM_INIT 指出現在可以新增一個 Action 選單項。NAMM_INITMENU 允許程式修改選單項,比如說允許使用或禁用的那些選單項。NAMM_COMMAND 指出 Action 選單項已經選定,而且現在您可以執行相關的操作。NAMM_TERM 提供了一個執行結束操作(比如釋放記憶體)的機會。
Lotus C API 提供了執行日曆和排程操作的能力,比如說建立日曆條目或查詢業務繁忙時段。建立日曆條目(比如會議、約會、備忘錄和全天的事件)涉及到使用 NSFNoteCreate() 函式在所需的郵件資料庫中建立一條記錄,並將所需的日曆項新增到該記錄中。
可以使用 SchRetrieve() 函式來檢索某一使用者特定時間的時間表。在檢索時間表時,可以使用 SchContainer_GetFirstSchedule() 函式來獲得第一個時間表物件。然後使用 Schedule_ExtractFreeTimeRange() 函式檢索時間表物件範圍內的空閒時間,或者使用 Schedule_ExtractBusyTimeRange() 函式獲得時間表物件範圍內的繁忙時間。
以下是 Lotus C API 提供的值得特別關注的一項服務:Extension Manager。它允許您在通過註冊回撥例程來執行某些 Notes 或 Domino 操作之前或之後執行定製程式。該程式的入口點應該是具有以下格式的一個函式:
STATUS LNPUBLIC FunctionName(void)該函式可以擁有任何名稱,但必須在模組定義(DEF)檔案的 EXPORTS 函式中用序數值 1 來宣告它。回撥函式必須具有以下格式:
STATUS LNPUBLIC FunctionName(EMRECORD FAR * pExRecord);在註冊回撥例程之前,使用 EMCreateRecursionID() 函式獲得一個遞迴 ID 很有用。如果已經呼叫擴充套件,那麼這樣做可以防止相同的擴充套件再次被呼叫,所以我們推薦您這樣做。EMRegister() 函式用於註冊回撥例程。這可以用一個例子來很好地說明:
EMRegister ( EM_NSFDBCLOSE, EM_REG_BEFORE, (EMHANDLER)gHandlerProc, gRecursionID, &hHandler); |
第一個引數是 EM_NSFDBCLOSE,它將識別我們想註冊回撥的操作。第二個引數是 EM_REG_BEFORE,它指出我們想在呼叫操作之前執行該程式。因此,只要呼叫 NSFDBClose() 操作,就會呼叫該程式,NSFDBClose() 操作用於關閉資料庫。有許多可以為其註冊回撥例程的操作,這個引數值指出了每個以 EM_ 開頭的操作(完整列表可以從 API 參考指導中獲得)。第三個引數是想要呼叫的定製函式。第四個引數是遞迴 ID(如果有的話),最後一個引數是由取消註冊時需要使用的函式返回的控制程式碼。
在結束該程式時,要使用 EMDeregister() 函式取消對回撥例程的註冊。要指定構建到 Lotus Notes/Domino 的擴充套件,則需要使用伺服器或客戶機的 Notes.ini 檔案中的 EXTMGR_ADDINS 變數(這取決於執行該擴充套件的位置)。
我們的示例程式碼之一展示瞭如何通過使用結束特定郵件檔案的日曆配置檔案更新的例程來使用 Extension Manager。該程式為 NSFNoteUpdateExtended() 註冊了一個回撥例程。在這個回撥例程中,我們將檢視即將更新的記錄是否是我們感興趣的郵件檔案,以及該記錄是否是一個日曆配置檔案。如果是,則將日期和時間記錄到一個日誌檔案中。在編譯並連結該程式之後,需要使用以下格式在伺服器的 Notes.ini 檔案中列出它:
EXTMGR_ADDINS=可以從 Sandbox 中下載該程式的完整程式碼(包括 MAK 檔案和模組定義檔案)。
文中所介紹的基礎知識只是 Lotus C API for Lotus Notes/Domino 必須提供哪些功能的一個示例。通過展示 Lotus C API for Lotus Notes/Domino 的一些功能,我希望本文能夠成為 Notes/Domino 使用者和開發人員研究和完全開發該工具箱的潛在功能的一個起點。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14751907/viewspace-405470/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- c++stl notesC++
- 最簡單的C程式設計--順序程式設計C程式程式設計
- 如果今天沒有API介面,今天的程式設計師如何程式設計?API程式設計師
- C程式設計題C程式程式設計
- c#程式設計C#程式設計
- Windows 程式設計簡介從C/C++到Windows程式設計Windows程式設計C++
- Linux C/C++程式設計中的多執行緒程式設計基本概念LinuxC++程式設計執行緒
- 程式設計師必看:免費好用的api程式設計師API
- 程式設計師朋友推薦的好用API程式設計師API
- 【混合程式設計】C/C++呼叫Fortran的DLL程式設計C++
- C++核心程式設計C++程式設計
- 基本TCP套接字程式設計APITCP程式設計API
- 併發程式設計Thread的常用API有哪些?程式設計threadAPI
- 程式設計師都在用的免費常用API程式設計師API
- 程式設計師,請保護好你的 API!程式設計師API
- Domino整合Portlet開發---安裝和配置Domino 6.5伺服器伺服器
- API(Application Programming Interface,應用程式程式設計介面)APIAPP程式設計
- c語言程式設計題C語言程式設計
- C#非同步程式設計C#非同步程式設計
- C++提高程式設計C++程式設計
- C++ 提高程式設計C++程式設計
- C# 管道式程式設計C#程式設計
- C++程式設計實現C++程式設計
- C# 併發程式設計C#程式設計
- C# 非同步程式設計C#非同步程式設計
- 程式設計競賽中 C/C++ I/O 的使用程式設計C++
- OC/Swift/C/C++混合使用的程式設計姿勢SwiftC++程式設計
- nb!程式設計師都在用的免費好用api程式設計師API
- 每個程式設計師都在推薦的好用api程式設計師API
- 程式設計師都在收藏的免費好用API介面程式設計師API
- C#並行程式設計:Parallel的使用C#並行行程程式設計Parallel
- C++的函數語言程式設計C++函數程式設計
- 非同步 API 的設計非同步API
- 【Linux網路程式設計】Socket Api函式Linux程式設計API函式
- Windows API視窗程式設計 - 空白視窗WindowsAPI程式設計
- Flink實戰(六) - Table API & SQL程式設計APISQL程式設計
- C/C++ 踩過的坑和防禦式程式設計C++程式設計
- C++提高程式設計-模板C++程式設計
- C++提高程式設計-STLC++程式設計