天天看點

PB程式使用序列槽

PB下從序列槽通信擷取程控交換機計費資料的API調用 

我是通過調用API實作的: 如你用的是二進制的,請把緩沖區改成BLOB型的。

首先定義外部函數: 

Function Boolean CloseHandle(ulong hObject ) Library "kernel32.dll" 

FUNCTION boolean ReadFile(ulong fhand, 

& ref string lpbuffer, 

& ulong numbyte, 

& ref ulong bytesread, 

& ulong lpover) LIBRARY "kernel32.dll" 

FUNCTION ulong CreateFileA(ref string fname, 

& ulong f_access, 

& ulong f_share, 

& ulong f_sec, 

& ulong f_create, 

& ulong f_flag, 

& ulong f_attrib) LIBRARY "kernel32.dll" 

Function Boolean WriteFile(uLong handle,

& ref string lpbuffer, 

& ulong numbytes, 

& ref ulong bytesread, 

& ulong lpOverLaped) Library "Kernel32.dll" 

Function Boolean GetCommProperties(ulong hFile,

& ref COMMPROP lpCommProp ) Library "Kernel32.dll" 

Function Boolean BuildCommDCBA(ref string lpDef,

& ref DCB lpDCB ) Library "Kernel32.dll" 

Function Boolean SetCommState(ulong hCommDev,

& ref DCB lpdcb ) Library "Kernel32.dll" 

Function Boolean GetCommState(ulong hCommDev,

& ref DCB lpdcb ) Library "Kernel32.dll" 

Function ulong GetLastError() Library "Kernel32.dll" 

Function Boolean SetCommTimeouts(ulong hCommDev,

& ref COMMTIMEOUTS lpctmo ) Library "Kernel32.dll"

Function Boolean PurgeComm(ulong hCommDev, 

& ulong fdwAction ) Library "Kernel32.dll" 

執行個體變量定義: 

ulong iu_file 

string is_buffer//資料緩沖 

string is_valid_num = "123" //有效資料

第二是初始設定 

string ls_com,ls_commset 

dcb lst_dcb 

ls_com = "COM1" //

ib_reading = true //打開序列槽 

iu_file = CreateFileA(ls_com,3221225472,0,0,3,128,0) 

if (iu_file < 0) then 

messagebox("錯誤","無法打開" + ls_com + " #" + string(getlasterror ( )),StopSign!) 

end if //初始化DCB 

ls_commset = "4800,N,8,1" 

if (Not BuildCommDcbA ( ls_commset, lst_dcb )) then 

messagebox("錯誤","無法建立DCB" + " #" + string(getlasterror ( )),StopSign!) 

end if 

//設定序列槽 

if (Not setcommstate ( iu_file, lst_dcb )) then 

messagebox("錯誤","無法設定序列槽"+ ls_com + " #" + string(getlasterror ( )),StopSign!) 

end if

//設定逾時 

commtimeouts lst_to lst_to.readintervaltimeout = 4294967295 //MAXDWORD //

lst_to.readtotaltimeoutconstant = 60000 //

lst_to.readtotaltimeoutmultiplier = 10 

SetCommTimeouts(iu_file, lst_to)

第三步:讀或寫(例子中的是讀,寫可用writefile) 

ulong lu_bytesread, lu_numbytes 

string ls_buff 

ulong lstr_locstruct //注意!這是ULONG 而不是STRUCT 

ls_buff = space(100) 

setnull(lstr_locstruct) 

lu_numbytes = 100 

if (not readfile ( iu_file, ls_buff, lu_numbytes, & lu_bytesread, lstr_locstruct)) 

then 

messagebox("錯誤","無法讀取 #" + string(getlasterror ( )),StopSign!) 

timer(0) 

else

if( lu_bytesread > 0) then 

is_buffer += trim(ls_buff) mle_1.text += trim(ls_buff) //處理資料 

this.wf_is_valid_receieve ( ) //檢驗函數 

end if 

end if

第四步:完成後釋放端口 

closehandle ( iu_file )

具體函數使用方法可參見MSDN中的TAPI。 有時可能用控件做起來更簡單一些(如SCOMM、SAX COMM等)。 

設計序列槽通訊程式 

  PB是一種面向對象的、具有可視圖形界面的、快速的互動式開發工具,它通過不同資料庫采用各自的專用接口或通過ODBC接口,同時支援多種關系資料庫系統、支援多文檔界面(MDI)、對象嵌入與連結(OLE)、動态資料交換(DDE)。利用其獨特的資料視窗對象,無須編寫SQL語句,便可直接對資料庫進行查詢、修改、插入、删除、浏覽、列印,以多種檔案格式打開和存儲資料,是以深受廣大使用者的歡迎。在實際應用過程中經常遇到PowerBuilder與其它裝置通過序列槽進行通訊的程式設計如IC卡應用系統中需通過序列槽與IC卡讀寫器進行通訊;在控制系統中,需通過序列槽與下位機進行通訊。下面介紹PowerBuilder5.0中常用的兩種序列槽通訊設計方法。 

一、調用Windows SDK函數進行序列槽通訊

1、Windows SDK函數介紹 

OpenComm

int OpenComm(LpszDevControl,

CbInQueue,cbOutQueue)

LPCSTR lpszdevcontro

l 裝置控制資訊的位址

UINT CbInQueue

接受隊列的大小(以位元組為機關)

UINT cbOutQueue

發送隊列的大小

傳回:如調用成功,傳回值标示此打開的裝置否則其傳回值小于0

·CloseComm

Int CloseComm(idComDev)

Int idComDey 要關閉的裝置

傳回值:調用成功傳回0,否則傳回負值

·WriteComm

int WriteComm(idComDev,lpvBuf,cbWrite)

int idComDev 通訊裝置标示符

const void FAR * lpvBuf 資料緩存區位址

int ,cbWrite 要寫的長度

傳回值:如果成功傳回所寫的位元組數,否則傳回值小于0

·ReadComm

Int ReadComm(idComDev,lpvBuf,cbRead)

int idComDev 通訊裝置标示符

const void FAR * lpvBuf 資料緩存區位址

int cbRead 要讀的位元組數

傳回值:如果成功傳回所讀的位元組數,否則傳回值小于0

·FlushComm

Int FluseComm(idComDev,fnQueue)

Int idComDev 通訊裝置标示符

Int fnQueue 要重新整理的隊列

傳回值:成功時傳回0,否則傳回為負

2、示例: 

  圖一(略)為一人事管理系統中的查詢視窗。如果想與被查詢人撥打電話,可輸入該人姓名,在輸入過程中,資料視窗會顯示滿足要求的所有人姓名,輕按兩下該行即将該人電話号碼顯示于單行編輯窗内,然後按“撥号”按鈕即可。 

程式設計如下: 

在視窗設計菜單中選取:Declare菜單?Declare External Function 輸入: 

Function int OpenComm(String Comm,

Uint Inqueue,Uint Outqueue)Library

“USER.EXE”

Function int CloseComm(int lpt)Library

“USER.EXE”

Function int WriteComm(int lpt,String

buf,int Size) Library “USER.EXE”

Function int FlushComm(int lpt,

int no_que)Library “USER.EXE”

“撥号”按鈕的”Clicked” 事件程式設計如下:

int ret

String port_2,ph_code

port_2=”Com2”

//取單行編輯框内容,并用atdt撥号

ph_code=”atdt”+sle_code+”~r~n”

//打開序列槽

ret=OpenComm(port_2,128,128)

//撥号開始

FlushComm(ret,0)

FlushComm(ret,1)

WriteComm(ret,ph_code,len(ph_code))

WriteComm(ret,”~r~n”,2)

CloseComm(ret)

二、 利用Microsoft公司提供的通訊控件

  利用Microsoft公司提供的通訊控件(Mscomm.vbx,用于16位通訊程式、Mscomm32.ocx用于開發32位通訊程式)可友善實作序列槽通訊。

1、常用屬性 

CommPort:設定或傳回串行端口号,預設為1。 

Setting:設定或傳回串行端的波特率、奇偶校驗位、資料位數、停止位。預設值為"9600,N,8,1"。 

PortOpen:設定它為True則打開端口,設定它為False則關閉端口。 

InBufferSize:設定或傳回接收緩沖區的大小,預設為1024 字 節。 

InBufferCount:傳回接收緩沖區内的等代讀取的位元組個數,設屬性為0清除接收緩沖區。 

OutBufferSize:設定或傳回發送緩沖區,預設為512位元組。 

OutBufferCounter:傳回發送緩沖區内等待發送的字元數,可用0來清空緩沖區。 

Output:向發送緩沖區傳送資料 

RThreshold: 該屬性确定當接收緩沖區内位元組個數達或超過該值後就産生代碼為ComEventReceive的OnComm事件,設定位0,則不産生OnComm事件。 

CommEvent:有通訊錯誤或事件發生時産生OnComm事件,CommEvent事件的值可以用來确定引發OnComm事件的具體的錯誤或事件常用的有以下幾種(更詳

細的資料可參考MSComm控件幫助檔案) 

ComEventbreak:接受到中斷信号

ComEventFrame:硬體檢測到幀錯誤。

ComEventRxOver:接收緩沖區溢出。

ComEventTxFull:發送緩沖區溢出。

ComEventReceive:接受到規定的字元數。

InputLen:設定或傳回接收緩沖區内用Input讀入的個數。若取0,則讀取整個緩沖區的内容。 

Input:傳回并删除接受緩沖區的資料。 

2、 示例: 

  下面舉一接收程式示例:制作一通訊接收視窗,選擇菜單Controls→OLE→Insert Control→Microsoft Communications Control,在視窗中出現通信控件圖示單擊滑鼠右鍵,選擇OCX Properties設定常用屬性,也可在程式中進行設定視窗的Open事件程式如下

ole_1.object.CommPort=2

ole_1.object.Settings="9600,N,8,1"

ole_1.object.PortOpen=ture

ole_1.object.Rthreshold=10

ole_1.object..Inputlen=0

.

.

通信控件的oncomm事件的程式如下

choose case ole_1.object.CommEvent

case comEventBreak //接收到中斷信号

case comEventCDTO //處理CD逾時

.

.

.

case comEvReceive

sle_1.text=ole_1.object.Input

.

.

end choose

以上是一個基本的例子,在實際應用過程中應根據不同的情況進行不同的設計,如波特率、幀格式等。 

總之,利用以上方法可以友善的在PowerBuilder中進行序列槽通訊,并對接收的資料利用PowerBuilder進行資料處理。 

PB中資料視窗的精确頁面列印技術 

  原著:國永傑、張穎,中國計算機世界。

  摘要本文詳細介紹了PowerBuilder中資料視窗列印輸出技術,并給出了一個通用的資料視窗列印控制程式。

  關鍵詞:PowerBuilder DataWindow Print

  1、引言

  自PowerBuild問世以來,以其簡潔高效的內建開發環境、強大的資料視窗技術、(幾乎)無所不能的資料庫通路能力,越來越受到程式設計人員的青睐。據Sybase自己的統計,目前全球有60萬程式員和系統分析人員在使用他們的Powerbuilder和S-designer,進行各種類型的應用程式開發。最新釋出的PowerBuilder6.0族系列開發工具,直接支援ActiveX技術、ServerPush技術,對分布式計算模型的定義更加明确,實作更為簡便,并可以利用資料視窗直接生成HTML格式檔案,等等。是以,PowerBuilder已成為C/S模式應用和基于InterNet模式應用的主要開發工具之一。

  資料視窗(DataWindow)是PowerBuilder的專利,也是PowerBuilder應用程式的核心和精華所在.PowerBuilder通過豐富的屬性和函數來控制資料視窗的顯示和資料操縱,但對資料視窗的列印支援似乎過于簡單,隻有一個Print()視窗函 數和一個PrintDataWindowPowerScript函數,并且這兩個函數的功能幾乎都是一樣,都隻簡單地将標明資料視窗原樣送入列印隊列,本身不具備頁面控制功能。為此很多程式員抱怨這是PowerBuilder的一個缺陷,其實,PowerBuilder對列印功能的支援一樣十分周到全面,隻不過應用場合不同,需要使用者自行加以選擇。

  以下是對PowerBuilder列印控制功能的詳盡分析,并介紹一個實用的資料視窗頁面控制程式。

  2、Powerbuilder實作動态頁面控制的途徑

  PowerBuilder資料視窗有一對函數Describe 和Modify,用于動态描述和修改資料視窗結構,與其它相關函數結合可以完成動态生成資料視窗、任意改變資料視窗顯示方式、修改列印屬性等。這兩個函數是控制與修改資料視窗的核心函數,其使用方法如下:

  1)、Describe擷取資料視窗特定屬性值

  文法:dwcontrol.Describe(propertylist)

  參數:dwcontrol資料視窗(或datastore)控 件名。

  propertylist用字元串表示的資料視窗屬性。

  傳回值:傳回一個表示屬性的字元串。

  資料視窗屬性值也可以用dwcontrol.object.Datawindow.property來完成直接取得。

  2)、Modify修改資料視窗特定屬性

  文法:dwcontrol.Modify(modstring)

  參數:dwcontroldwcontrol資料視窗(或datastore)控 件名。

  modstring用字元串表示的資料視窗屬性。

  傳回值:如果函數執行成功傳回“1”。

  與Describe類似, 修改數 據視窗 屬性可 以用:

  dwcontrol.object.Datawindow.property=value直 接指派。

  3)、與打 印有關 的資料 視窗屬 性

  資料視窗屬性中與列印有關的有24個,其中實作列印頁面控制的幾個屬性是:

  Copies:列印份數。

  Filename:如果不為空,表示輸出到檔案的檔案名。

  Orientation:列印方向1=橫向,2=縱 向

  Page.Range:輸出頁範圍,要列印1,2,和5到10 頁,輸入: "1,2,5-10"。Page.RangeInclude:本 

次列印範圍,0=全部,1= 偶數頁,2= 奇數頁。Paper.Size:紙張大小。

  Scale:列印比例。 

  程式中利用Modify函數設定好這些屬性後,即可實作動态修改資料視窗的目的,再調用datawindow.print()函數,完成最後的列印輸出。

  一個通用Datawindow列印控制程式

  将資料視窗中的報表在列印機上輸出是PowerBuilder應用程式開發過程中必不可少的功能,作為例子,這裡提供一個使用上述方法研制的通用列印控制視窗,用以替代Prompt屬性所提供的Print視窗,實作漢化界面,并且可被自行修改擴充。為了書寫簡單,程式中采用直接指派的方式修改屬性。

  執行個體變量:

  datawindowdw_print

  stringprintername,name,port

  視窗open事件腳本:

  dw_print=Message.PowerObjectParm

  printername=dw_print.Object.Datawindow.Printer

  name=left(printername,pos(printername,"on")-1)

  port=right(printername,len(printername)-pos(printername,"on")-1)

  plb_printername.additem(name,1)

  st_portname.text=port

  "設定" 按鈕clicked事件腳本

  Integercode

  Code=printSetup()

  If code = 1 then

    printername=dw_print.Object.Datawindow.Printer

    name=left(printername,pos(printername,"on")-1)

    port=right(printername,len(printername)-pos(printername,"on")-1)

    plb_printername.additem(name,1)

    st_portname.text=port

  endif

  列印範圍組中"全部"選擇鈕clicked事件腳本

  dw_print.object.DataWindow.Print.Range=''

  sle_1.enabled=false

  sle_2.enabled=false

  sle_3.enabled=false

  "頁數"欄後sle_2單行文本編輯框Modified事件腳本

  dw_print.object.DataWindow.Print.Page.Range=sle_1.text+"-"+sle_2.text

  "自定義"欄後sle_3單行文本編輯框Modified事件腳本

  dw_print.object.DataWindow.Print.Page.Range=sle_3.text

  列印份數組中份數單行文本編輯框Modified事件腳本

  dw_print.Object.DataWindow.Print.Copies=integer(this.text)

  "全部"選擇鈕Cliecked事件腳本

  dw_print.Object.DataWindow.Print.Page.Rangeinclude = 0

  "奇數"選擇鈕Cliecked事件腳本

  dw_print.Object.DataWindow.Print.Page.Rangeinclude = 1

  "偶數"選擇鈕Cliecked事件腳本

  dw_print.Object.DataWindow.Print.Page.Rangeinclude = 2

  "确認"指令按鈕Clicked事件腳本

  longjob

  if IsValid(dw_print) then

    job = PrintOpen()

    PrintDataWindow(job,dw_print)

    PrintClose(job)

    close(parent)

  endif

  "取消"指令按鈕Clicked事件腳本

  close(parent)

  視窗調用方法:在其它帶有資料視窗的視窗中,使用OpenWithParm(w_print_set,dwname)即可,其中w_print_set為本視窗名,dwname為要列印的資料視窗。該程式是一個通用列印控制程式,可在任何版本的PowerBuilder應用中使用。 

如何在PB中定制列印頁長 

  在使用連續紙列印資料視窗的情況下,需要定制列印的頁長,以保證列印機走紙正确,不用人工幹預,實作連續列印。在PB中須調用外部函數來自定義紙張長度,比較繁瑣。本文介紹一種直接對列印機的控制方法,簡單實作對頁長的設定。 

  一、預備知識 

  計算機與列印機的通訊使用ASCII碼進行,其中标準ASCII碼包括可列印字元及非列印字元(控制碼),列印機使用控制碼來定制列印機。大多數列印機指令使用控制碼escape作為其指令序列的第一個序列碼。下面介紹本文用到的幾個指令碼序列: 

  設定換行量(行距)1/8 英寸

  ASCII碼 ESC 0

  十進制碼 27 48

  設定以行為機關的頁長

  ASCII碼 ESC C n

  十進制碼 27 67 n

  其中n 為每頁行數範圍(1-127)

  二、PB中控制碼的傳送及定制頁長的實作 

  在PB中通過函數Printsend(printjobnumber,string,{zerochar})來實作向列印機發送控制碼。各參數定義如下: 

  printjobnumber: 由printjob()函數傳回的列印作業号;

  string: 控制字元串,使用ASCII碼;

  zerochar: 用來替代string中的數字0;

  由于字元串中,0終止字元串,如果string 中包含0,則需利用其他字元來表示0,參數zerochar即為此用途而設,當PB發送控制字元串給列印機時,把替代的字元zerochar轉化為0。 

  下面是具體的完成定制頁長列印資料視窗的程式(定制頁長為2.75英寸): 

  long ll_job

  dw_print.reset()

  ll_job = printopen()

  if ll_job = -1 then

    messagebox(gs_title,"列印機未準備好")

    return

  end if

  //定制行距1/8英寸

  PrintSend(ll_job, CHAR(27)+CHAR(48)) 

  //設定頁長22行

  PrintSend(ll_job, CHAR(27)+CHAR(67)+CHAR(22))

  printdatawindow(ll_job,dw_print)

  printclose(ll_job) 

PB