明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

用Visual C++增強(qiáng)Notes打印技巧

[摘要]Lotus公司推出的Lotus Domino/Notes作為辦公自動(dòng)化系統(tǒng)的平臺(tái)近年來(lái)在國(guó)內(nèi)得到了廣泛的應(yīng)用,許多的政府主管部門、金融單位、企事業(yè)單位都使用了Notes以及在Notes上開發(fā)的各種辦公系統(tǒng),工作效率得到了極大的提高! ≡趯(shí)際的應(yīng)用中,為了存檔以及供沒(méi)安裝Notes系統(tǒng)的部門傳閱,...
Lotus公司推出的Lotus Domino/Notes作為辦公自動(dòng)化系統(tǒng)的平臺(tái)近年來(lái)在國(guó)內(nèi)得到了廣泛的應(yīng)用,許多的政府主管部門、金融單位、企事業(yè)單位都使用了Notes以及在Notes上開發(fā)的各種辦公系統(tǒng),工作效率得到了極大的提高。

  在實(shí)際的應(yīng)用中,為了存檔以及供沒(méi)安裝Notes系統(tǒng)的部門傳閱,許多在Notes系統(tǒng)中流轉(zhuǎn)的電子文檔需要打印出來(lái)。不幸的是,Notes提供的打印功能很弱,一個(gè)文檔只能按照給定表單的版式進(jìn)行打印。但在實(shí)際的使用中,如政府部門,內(nèi)容相同的一個(gè)文檔,其上行公文和下行公文的版式是不一樣的,這就需要將同一文檔用多種樣式打印。最直接的想法當(dāng)然是在Designer中修改表單的版式,但由于應(yīng)用系統(tǒng)一般是隱藏設(shè)計(jì)的,表單無(wú)法修改。還有就是最終用戶的計(jì)算機(jī)水平有限,直接修改表單從技術(shù)上講也行不通。

  這時(shí)一個(gè)可行的做法就是:用VC++給用戶提供一個(gè)"所見(jiàn)即所得"的編輯界面,并列出Notes文檔中各部分的內(nèi)容,讓用戶以拖放的方式將相關(guān)內(nèi)容放到適當(dāng)?shù)奈恢蒙,同時(shí)還可以加入文字、圖片等修飾內(nèi)容,然后按照最終的版式在Notes外部直接生成一個(gè)Notes表單,并用此表單進(jìn)行打印。這種方法既繞過(guò)了隱藏設(shè)計(jì)的障礙,又降低了對(duì)最終用戶的技術(shù)要求。當(dāng)然這一切都得益于Notes提供的API函數(shù)。

  由于只需一個(gè)NSFItemScan函數(shù)就能收集到Notes文檔中所有的域,而又有多種靈活的方式實(shí)現(xiàn)"所見(jiàn)即所得"的排版功能,因此在提出上述的思路后,本文將主要介紹如何構(gòu)造Notes表單。
  一 Notes表單結(jié)構(gòu)簡(jiǎn)介

  一個(gè)表單中有三個(gè)必需的域:$TITLE、$INFO和$BODY,輔助性的還有$FIELDS域及屬性為placeholder的各域。

  1.$TITLE域

  $TITLE域的類型為TYPE_TEXT,其中保存表單的名稱,Notes客戶端窗口中"創(chuàng)建"菜單下列出的各表單名即為各表單note中$TITLE域的值。在Notes提供的C API頭文件"stdnames.h"中有預(yù)定義的常量ITEM_NAME_TEMPLATE_NAME代表表單note的名稱域,為保證程序的向后兼容,建議使用常量而避免直接使用$TITLE。

  2.$INFO域

  由于表單和文檔的創(chuàng)建有關(guān),$INFO域定義了通過(guò)此表單創(chuàng)建的文檔的一些屬性。實(shí)際上$INFO域中存儲(chǔ)的是一個(gè)名為CDDOCUMENT的結(jié)構(gòu)體,對(duì)生成文檔屬性的設(shè)定就是通過(guò)對(duì)該結(jié)構(gòu)體中各分量的不同賦值實(shí)現(xiàn)的。結(jié)構(gòu)體CDDOCUMENT 的定義及說(shuō)明見(jiàn)Lotus C API 的參考文檔。

  $INFO域的類型為TYPE_COMPOSITE,對(duì)應(yīng)的預(yù)定義常量為ITEM_NAME_DOCUMENT。

  3. $BODY域

  $BODY域是表單note中的核心域,整個(gè)表單顯示和打印時(shí)的格式,還有通過(guò)此表單生成的文檔所包含的域及其類型,都是在本域中定義的。由于$BODY域的結(jié)構(gòu)非常復(fù)雜,本文將在第二部分專門介紹。$BODY域也是TYPE_COMPOSITE類型的,名稱預(yù)定義常量為ITEM_NAME_TEMPLATE。

  4. $FIELDS域

  $FIELDS域是一個(gè)TYPE_TEXT_LIST類型的域,其中包含了用此表單生成的文檔包含的所有域。但專為打印生成的表單中可以沒(méi)有此域。

  5. "placeholder"域

  對(duì)$BODY域中定義的將來(lái)文檔中要含有的每一個(gè)域,在表單中都對(duì)應(yīng)一個(gè)類型為TYPE_INVALID_OR_UNKNOWN而標(biāo)志為ITEM_PLACEHOLDER的域,域名和$BODY域中定義的一樣,而其值為NULL。
標(biāo)志為ITEM_PLACEHOLDER的域?qū)⒈患尤氲?quot;域名表"中,這樣當(dāng)用戶選擇了客戶端中的"設(shè)計(jì)"菜單中的"視圖"子菜單后,在彈出的對(duì)話框中選擇"添加域"時(shí),該域名才會(huì)被顯示出來(lái)。
同樣,這些域在打印的表單中不是必需的。

二 $BODY域詳解

  $BODY域中可以包含各種Notes對(duì)象,如文本、域、圖像、熱點(diǎn)、鏈接等,還有一些輔助性對(duì)象,如段定義、段引用等。為方便管理,所有這些對(duì)象的定義都是通過(guò)不同的結(jié)構(gòu)體實(shí)現(xiàn)的。Notes中定義對(duì)象的結(jié)構(gòu)體都以"CD"開頭,如CDTEXT定義靜態(tài)文本、CDFIELD定義域等,其他對(duì)象的具體定義請(qǐng)查閱Lotus C API 的參考文檔。

  通常,一個(gè)$BODY域的整體結(jié)構(gòu)是這樣的:

  CDPABDEFINITION
  CDPABDEFINITION
  ...
  CDPARAGRAPH
  CDPABREFERENCE
  CDTEXT
  text
  ...
  CDPARAGRAPH
  CDPABREFERENCE
  CDBEGINRECORD
  CDFIELD
  CDBEGINRECORD
  ...

  下面對(duì)其中的各部分分別予以說(shuō)明。

  1.段落預(yù)定義部分

  CDPABDEFINITION定義頁(yè)面上一個(gè)段落的屬性,在這個(gè)結(jié)構(gòu)體中我們可以定義段落的對(duì)齊方式、頁(yè)邊距、段間距、行間距等。在后面的某個(gè)具體段落中,如果定義了到此段定義的引用,則該段落就具有了此處定義的各屬性。

  段落的定義可以放在$BODY域的開頭,也可以放在中間,只要保證序號(hào)PABID不重復(fù)就可以了。

  2.靜態(tài)文本的定義

  上述總體結(jié)構(gòu)的中間部分定義了一段文本:CDPARAGRAPH定義一段的開始,類似文本串中的一個(gè)回車換行符;CDPABREFERENCE定義一個(gè)到段定義的引用,從而本段就具有了前面定義的各種屬性;CDTEXT是文本的頭部,包含有文本的長(zhǎng)度、字體、顏色等信息;text是實(shí)際的文本。

  3.域的定義

  對(duì)域的定義也是以CDPARAGRAPH和CDPABREFERENCE開始,但與文本不同的是,像域、圖像等對(duì)象的定義,除了有作為頭部的結(jié)構(gòu)體外,還要有一對(duì)界定結(jié)構(gòu)體CDBEGINRECORD和CDENDRECORD放在對(duì)象定義的前后兩端。

  有時(shí)在域的前面還要有一些提示性文字,如一個(gè)用于接收姓名的域name,通常在其前面要有"姓名"兩個(gè)字,以便具體操作者知道此處要輸入姓名。具體創(chuàng)建域時(shí),這部分內(nèi)容以文本形式放在CDBEGINRECORD之前,格式如上一步中所述。

  在貨幣型或數(shù)值型的域中,為了對(duì)數(shù)據(jù)的格式進(jìn)行更進(jìn)一步的控制,在CDBEGINRECORD和CDFIELD中間還要插入一個(gè)CDEXT2FIELD結(jié)構(gòu),該結(jié)構(gòu)提供了附加的格式定義。

  域中的其他元素,如默認(rèn)值計(jì)算公式、輸入變換公式、域名、描述字串等放在CDFIELD后面,排列順序和其長(zhǎng)度值在CDFIELD結(jié)構(gòu)體中的位置順序一致。當(dāng)然除域名外,其他元素如不是必要可以省略。

  在本部分中,以文本和域?yàn)槔,介紹了$BODY域中各對(duì)象的具體定義方式,其他對(duì)象與此類似。

  三 創(chuàng)建Notes表單

  在了解了Notes表單結(jié)構(gòu)的基礎(chǔ)上,通過(guò)API函數(shù)建立表單就很容易了。

  首先打開一個(gè)數(shù)據(jù)庫(kù),然后在其中新建一個(gè)空白note,接下來(lái)就可以向其中添加各域了。像$TITLE這樣的單一類型的域,可以直接調(diào)用NSFItemSetText函數(shù)創(chuàng)建。而像$INFO和$BODY這樣的復(fù)合類型的域,就比較麻煩一些。通常的做法是,先申請(qǐng)一塊足夠大的內(nèi)存,然后順序?qū)懭敫鞑糠謨?nèi)容,最后調(diào)用NSFItemAppend函數(shù)創(chuàng)建域。

  在向復(fù)合域中寫入數(shù)據(jù)時(shí),文本、域名等一般字符串可以直接寫入,而各種結(jié)構(gòu)體需調(diào)用ODSWriteMemory函數(shù)以Domino規(guī)范的形式寫入,另外就是域定義中用到的各種公式,在寫入前要經(jīng)過(guò)NSFFormulaCompile變換。

四 例程

  下面的程序段定義了一個(gè)帶有默認(rèn)值公式的名為"TextField"的域:

  char TextFieldName[] = "TextField";
  char TextDescription[] = "This is a Simple Text Field";
  char TextDefValFormula[] = "\"Default\"";
  char far *pBufferStart, far *pBuffer;
  HANDLE hMem;
  CDPABREFERENCE CDPabRef;
  CDPARAGRAPH CDPara;
  CDBEGINRECORD CDBegin;
  CDENDRECORD CDEnd;
  CDEXT2FIELD CDExt2Field;
  CDFIELD CDField;
  FONTIDFIELDS *pFontFields;

// 申請(qǐng)內(nèi)存并鎖定內(nèi)存,獲得指向該塊內(nèi)存的指針
  OSMemAlloc (0, wCDBufferLength, &hMem);
  pBufferStart = (char far *)OSLockObject(hMem);
  memset( pBufferStart, 0, (size_t) wCDBufferLength );
  pBuffer = pBufferStart;

// 填寫 PARAGRAPH 結(jié)構(gòu)
  // 結(jié)構(gòu)體的長(zhǎng)度
  CDPara.Header.Length = (BYTE) ODSLength(_CDPARAGRAPH);
  // 結(jié)構(gòu)體的類型
  CDPara.Header.Signature = (BYTE)SIG_CD_PARAGRAPH;
  // 轉(zhuǎn)換為Domino規(guī)范的形式寫入申請(qǐng)的內(nèi)存
  ODSWriteMemory( (void far * far *)&pBuffer, _CDPARAGRAPH, &CDPara, 1 );

// 填寫 PABREF 結(jié)構(gòu)
  CDPabRef.Header.Signature = (BYTE)SIG_CD_PABREFERENCE;
  CDPabRef.Header.Length = (BYTE) ODSLength(_CDPABREFERENCE);
  // 要引用的段定義的序號(hào)
  CDPabRef.PABID = wPabDefNumber;
  ODSWriteMemory( (void far * far *)&pBuffer, _CDPABREFERENCE, &CDPabRef, 1 );

// 填寫CDBEGINRECORD 結(jié)構(gòu)
  CDBegin.Header.Length = (BYTE)ODSLength(_CDBEGINRECORD);
  CDBegin.Header.Signature = SIG_CD_BEGIN;
  CDBegin.Version = 0;
  CDBegin.Signature = SIG_CD_FIELD;
  ODSWriteMemory( (void far * far *)&pBuffer, _CDBEGINRECORD,(void far *) &CDBegin, 1 );

// 填寫CDEXT2FIELD 結(jié)構(gòu)
  memset(&CDExt2Field, 0, sizeof(CDEXT2FIELD));
  CDExt2Field.Header.Length = (WORD)ODSLength(_CDEXT2FIELD);
  CDExt2Field.Header.Signature = SIG_CD_EXT2_FIELD;
  ODSWriteMemory( (void far * far *)&pBuffer, _CDEXT2FIELD, (void far *) &CDExt2Field, 1 );

// 填寫CDFIELD 結(jié)構(gòu),定義文本域
  CDField.Header.Signature = SIG_CD_FIELD;
  CDField.Flags = FEDITABLE;
  CDField.DataType = TYPE_TEXT;
  CDField.ListDelim = LDDELIM_SEMICOLON;

  // 本域中不用數(shù)值格式參數(shù),全部清零
  CDField.NumberFormat.Digits = 0;
  CDField.NumberFormat.Format = 0;
  CDField.NumberFormat.Attributes = 0;
  CDField.NumberFormat.Unused = 0;

  file://本域中不用時(shí)間格式參數(shù),全部清零
  CDField.TimeFormat.Date = 0;
  CDField.TimeFormat.Time = 0;
  CDField.TimeFormat.Zone = 0;
  CDField.TimeFormat.Structure = 0;

  // 設(shè)定FontID
  pFontFields = (FONTIDFIELDS *)&CDField.FontID;
  pFontFields->Face = FONT_FACE_ROMAN;
  pFontFields->Attrib = 0;
  pFontFields->Color = NOTES_COLOR_BLACK;
  pFontFields->PointSize = 14;

  // 編譯默認(rèn)值公式
  NSFFormulaCompile(NULL, 0, TextDefValFormula, (WORD) strlen(TextDefValFormula), &hTextDefValFormula, &wTextDefValFormulaLen, &wdc, &wdc, &wdc, &wdc, &wdc))

  // 填寫CDFIELD 結(jié)構(gòu)的其余部分,因?yàn)镈VLength值只有公式編譯后才知道
  CDField.DVLength = wTextDefValFormulaLen;
  CDField.ITLength = 0;
  CDField.TabOrder = 0;
  CDField.IVLength = 0;
  CDField.NameLength = strlen(TextFieldName);
  CDField.DescLength = strlen(TextDescription);
  CDField.TextValueLength = 0;
  CDField.Header.Length = ODSLength(_CDFIELD) +CDField.DVLength +CDField.ITLength +CDField.IVLength +CDField.NameLength +CDField.DescLength +CDField.TextValueLength;

  // 保證CDFIELD域長(zhǎng)度為偶數(shù)
  if (CDField.Header.Length % 2)
    CDField.Header.Length++;
  ODSWriteMemory( (void far * far *)&pBuffer, _CDFIELD, (void far *)&CDField, 1 );

  // 獲取指向編譯后公式的指針
  pTextDefValFormula = OSLock( char, hTextDefValFormula );
  // 寫入公式內(nèi)容到內(nèi)存
  memcpy( pBuffer, pTextDefValFormula, wTextDefValFormulaLen );
  pBuffer += CDField.DVLength;
  // 解鎖并釋放公式占用的空間
  OSUnlockObject(hTextDefValFormula);
  OSMemFree(hTextDefValFormula);

  // 域名部分,直接寫入
  memcpy( pBuffer, TextFieldName, CDField.NameLength );
  pBuffer += CDField.NameLength;

  // 域描述部分,直接寫入
  memcpy( pBuffer, TextDescription, CDField.DescLength );
  pBuffer += CDField.DescLength;

  // 保證整個(gè)域定義的長(zhǎng)度為偶數(shù)
  if ((pBuffer-pBufferStart) %2)
    pBuffer++;

// 填寫CDENDRECORD結(jié)構(gòu)
  CDEnd.Header.Length = (BYTE)ODSLength(_CDENDRECORD);
  CDEnd.Header.Signature = SIG_CD_END;
  CDEnd.Version = 0;
  CDEnd.Signature = SIG_CD_FIELD;
  ODSWriteMemory( (void far * far *)&pBuffer, _CDENDRECORD, (void far *) &CDEnd, 1 );