Lotus Domino/Notes是美國蓮花公司出的企業通訊和羣件服務平臺。但由於其本身提供的開發工具的限制,在Notes中實現系統級功能十分困難。比如在Notes中,不能通過公式或腳本來得到一個數據庫的未讀文檔的數量和其內容。但這個未讀文檔數的小功能在做有些方面是十分有用的,例如我們可以根據這個未讀文檔數來做個提醒功能,提醒用戶該進行某類工作如文件簽發等。Notes系統本身有個Minder的程序,它是在有新郵件來到的時候,提醒用戶,並可提供一些基本的信息:來信人,標題等。我們也可以這樣做(當然利用未讀文檔數來做不是完美,如果你有興趣,你可以試試做個數據庫鉤子程序來實現,但總的來說,利用未讀文檔數來做較爲簡單。)。
本文就是討論如何利用Notes提供的C API來實現讀取一個Notes數據庫的未讀文檔數和其信息。因爲利用的是C API,所以我們的開發語言是C。開發工具我們選用的是VC++ 6.0。我們需要藉助的是Notes本身提供的C API函數。Notes的大部分API都封裝在nNotes.dll文件中。其中包括有ACL,Database,User,Document,Item等各個方面的API函數。它不光能實現幾乎所有在Notes中實現的功能,它還提供了其他在Notes中難以想象的功能(換句話說,你可以自己寫自己特有的Notes桌面程序而不再使用Notes.exe。當然它的功能還遠不止這點)。利用Notes API包,我們可以做以下的程序:
1、獨立應用程序。
2、DOMINO 服務器的擴展插入服務(add-in tasks)。
3、NOTES 客戶機的菜單擴展插入(menu add-ins)。
4、NOTES 客戶機可動態加載的函數庫。
5、數據庫的鉤子驅動程序(HOOK Drivers)。
6、擴展管理程序的鉤子函數庫。
7、非NOTES數據庫的驅動程序。
下面簡單介紹一下我們後面會涉及的主要的Notes API函數:
NotesInitExtended:初始化Notes環境,應在所有Notes API函數調用前初始化系統。
NSFDbOpen:打開指定的Notes數據庫。
NSFDbClose:關閉指定的Notes數據庫。
NSFDbGetUnreadNoteTable:取得指定數據庫內的未讀文檔列表。
NSFDbUpdateUnread:更新數據庫的未讀文檔列表。
NIFFindView:取得數據庫內的指定視圖或文件夾。
NIFOpenCollection:取得指定視圖或文件夾的所有文檔。
NIFUpdateCollection:更新指定視圖或文件夾的所有文檔。
NIFCloseCollection:關閉文檔集。
NIFReadEntries:讀取文檔集的指定文檔。
NSFNoteOpen:打開指定文檔。
NSFItemGetText:取得文檔的指定字段值。
程序流程:
數據庫中有張類型爲IDTable的未讀文檔列表,其中包含了該數據庫的帶有未讀標誌的文檔號。這張表存儲在數據庫中和客戶機的Desktop.dsk文件中。當然,在數據庫和文件中的這張表是一樣的。當他們不一致時,則在你打開數據庫時,它們會自動同步,使他們保持一樣。
我們就是要取得這張未讀文檔表,再統計一下這張表中有多少項,就知道了數據庫中多少文檔帶有未讀標誌。我們還可以在此基礎上取得該文檔的一些具體信息。但這張表是整個數據庫的未讀文檔列表,我們怎麼得到某個視圖或文件夾的未讀文檔數和信息呢?實際上,這纔是我們真正關心的。我們可以再找到某個視圖和文件夾的文檔列表,再與上面的未讀文檔列表進行一一比較,相同的則是該視圖或文件夾的未讀文檔列表。
主要程序如下:
//////////////////////////////////////////////////////
// InitNotes:初始化Notes環境,打開數據庫
// szServerName:服務器名
// szDBName:數據庫名
// szDirectory:Notes系統目錄
// 返回值:1 - 成功
// 0 - 失敗
int CNotes::InitNotes(char *szServerName,char *szDBName,char *szDirectory)
{
STATUS status;
char szPathName[MAX_PATH];
char szpInitPara[1][260];
// 數據庫路徑名=服務器名+“!!”+數據庫名
if (strlen(szServerName)==0)
strcpy(szPathName,szDBName);
else {
strcpy(szPathName,szServerName);
strcat(szPathName,"!!");
strcat(szPathName,szDBName);
}
strcpy(szpInitPara[0],szDirectory);
if (!m_bOpened)
NotesInitExtended(1,(char**)szpInitPara); // 初始化Notes環境
status=NSFDbOpen(szPathName,&hDb); // 打開數據庫
if (status!=NOERROR) {
m_bOpened=false;
return 0;
}
m_bOpened=true;
return 1;
}
///////////////////////////////////////////////////
// GetUnread:取得指定視圖或文件夾中的未讀文檔數
// szViewName:視圖或文件夾名
// 返回值:-1 - 失敗
// 其他 - 未讀文檔數
int CNotes::GetUnread(char *szViewName)
{
STATUS status;
char szUserName[MAX_PATH];
status=SECKFMGetUserName(szUserName); // 得到當前用戶名
if (status!=NOERROR) {
m_bGetUnread=false;
return -1;
}
status=NSFDbGetUnreadNoteTable(hDb,szUserName,_
strlen(szUserName),true,&hTable);
// 取得數據庫的未讀文檔列表
if (status!=NOERROR) {
m_bGetUnread=false;
return -1;
}
if (hTable==NULL) {
m_bGetUnread=false;
return -1;
}
status=NSFDbUpdateUnread(hDb,hTable); // 更新未讀文檔列表
if (status!=NOERROR) {
OSMemFree(hTable);
m_bGetUnread=false;
return -1;
}
status = NIFFindView(hDb, szViewName, &ViewID); file://得到數據庫的某視圖或文件夾
if (status!=NOERROR) {
OSMemFree(hTable);
m_bGetUnread=false;
return -1;
}
status=NIFOpenCollection(hDb,hDb,ViewID,0,hTable,_
&hCollection,NULL,NULL,NULL,NULL);
if (status!=NOERROR) {
OSMemFree(hTable);
m_bGetUnread=false;
return -1;
}
status =NIFUpdateCollection(hCollection);
if (status!=NOERROR) {
NIFCloseCollection(hCollection);
OSMemFree(hTable);
m_bGetUnread=false;
return -1;
}
COLLECTIONPOSITION CollPosition;
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 0;
HANDLE hBuffer;
DWORD NotesFound;
WORD SignalFlags;
Status=NIFReadEntries(hCollection,&CollPosition,_
NAVIGATE_NEXT,1L,NAVIGATE_NEXT,0xFFFF,READ_MASK_NOTEID,_
&hBuffer,NULL,NULL,&NotesFound,&SignalFlags);
if (status!=NOERROR) {
NIFCloseCollection(hCollection);
OSMemFree(hTable);
m_bGetUnread=false;
return -1;
}
int iViewUnread=0;
NOTEID NoteID;
BOOL fFirst=TRUE;
unsigned int i;
NOTEID* IdList;
if (hBuffer != NULLHANDLE)
{
IdList = (NOTEID far *)OSLockObject(hBuffer);
while(IDScan(hTable, fFirst, &NoteID)) // 依次取得hTable表中的文檔號
{
fFirst = FALSE;
for (i=0; i
if (NoteID==IdList[i]) {
iViewUnread++;
break;
}
}
OSUnlockObject(hBuffer);
OSMemFree(hBuffer);
}
NIFCloseCollection(hCollection);
OSMemFree(hTable);
m_bGetUnread=true;
return iViewUnread;
}
//////////////////////////////////////////
// CloseNotes:關閉Notes數據庫
void CNotes::CloseNotes()
{
if (m_bOpened)
NSFDbClose(hDb);
m_bOpened=false;
m_bGetUnread=false;
}
經驗:
1、在用NSFDbGetUnreadNoteTable函數取得未讀文檔列表時,發現在讀取本地數據庫時,未讀文檔列表是正確的,而當讀取服務器上數據庫時(即使你在本地做個複本,再讀本地複本的未讀文檔列表也是一樣),總是返回總文檔數,即使在用NSFDbUpdateUnread函數更新了未讀文檔列表後仍是如此,只有在用文檔集函數NIFUpdateCollection更新後才能得到真正的未讀文檔數。
2、在上面得到的未讀文檔數是整個數據庫的全部未讀文檔,應和視圖文檔進行對比後才真正得到某視圖或文件夾的未讀文檔。
3、Notes在處理中文時,要求每個中文前都必須有0x13字符才行。所以在處理中文數據庫方面,自己還要自行處理中文名問題。
4、要進一步得到文檔的字段內容,可以用將以下函數段加入上述函數中。
BOOL fFirst = TRUE;
int j=0;
NOTEHANDLE noteHandle;
while(IDScan(hTable, fFirst, &NoteID))
{
fFirst = FALSE;
for (i=0; i
if (NoteID==IdList[i]) {
if (NSFNoteOpen(hDb, NoteID,0, ?eHandle)==NOERROR) {
NSFItemGetText(noteHandle,szItemName,Buffer[j],MAX_PATH);
}
j++;
break;
}
}
5、本文是實現該功能的主要函數,你可以將其寫成一個DLL程序,那麼就可以在你的Notes Script腳本程序中來使用它。你也可以利用它寫成一個獨立的應用程序,你就可以在Notes外部運行它了。
本程序在Windows2000 Server,Visual C++ 6.0下調試通過。如果本文有任何問題,請與作者聯繫。
參考文獻:
Lotus C API 5.0.7 User Guide
Lotus C API 5.0.7 Reference