| 導購 | 订阅 | 在线投稿
分享
 
 
 

COMDCOM對象中通過Variant傳遞數組

來源:互聯網  2008-06-01 01:15:13  評論

因爲COM/DCOM對象都不在Client程序運行的內存空間(內進程COM對象除外,即便如此,爲了統一接口,內進程的COM也不得傳遞指針),而且在Win32中所有的程序都有自己獨立的2GB的內存空間,程序與程序之間傳遞指針(內存地址)是毫無意義的,而數組、字符串等大量的數據在程序中都是分配一定的內存空間,然後用指針加內存偏移量來存取數據的,這時,如何在COM/DCOM對象中如何傳遞呢?

在Win32中引入了一新變量Variant,可以通過Variant傳遞數組。具體的實現方法,用Delphi實現爲:

Server(COM/DCOM程序)端:

procedure TTestDCOM.Send4(Size: Integer; D1: OleVariant);

type

TData=array [0..999] of Byte;

Var

Data:TData;

i:Integer;

begin

for i:=0 to Size-1 do begin

Data[i]:=D1[i];

end;

end;

Cleint端:

Var

D1:OleVariant;

begin

D1:=VarArrayCreate([0,99],varByte);

{

D1[1]:=45;

.... file://將值存入D1中

}

S.Send4(99,D1); file://S是TestDCOM對象

end;

作者:高素梅

配置數據引擎(BDE、SQL Link)的簡單方法

在數據庫程序分發時,需要攜帶數據引擎(BDE、SQL Link),並且在客戶端安裝完程序後還需要配置數據引擎,如用戶名(username)、密碼(PassWord)等等。假如手工配置的話,工作量比較大,這時,我們可利用InstallShield For Delphi輕松實現配置。在用InstallShield For Delphi制作安裝程序時,在生成安裝程序的目錄裏有一個*.iwz的文本文件,只要在[IDAPI Alias]片段中手工加入即可。 例如:

[IDAPI Alias]

username=SYSDBA

password=masterkey

安裝程序後數據引擎自動配置完畢。

制做快速按鈕條的方法

快速按鈕條上的每一個圖形按鈕都代表著一項常用的功能,同時,這些圖形按鈕尺寸較普通的圖標大,可以放置更大、更形象的圖形,甚至可以帶上簡短的提示,這對于用戶執行最常用的功能很有幫助。基于上述原因,越來越多的Windows應用程序采用快速按鈕條來改善應用程序的界面。筆者在用Delphi編程時,采用了兩種不同的方法來實現快速按鈕條,本文結合制作一個具有兩組、共六個按鈕的快速按鈕條的實例,列出了這兩種方法的具體設計步驟。

1.組合生成法

(1)在窗體上放置一個Panel1對象,作爲圖形按鈕的載體。

(2)設置Panel1的屬性Caption爲空,屬性Align爲alTop,調整其高度至合適尺寸。

(3)在Panel1上放置六個SpeedButton按鈕(選用SpeedButton,是因它具有浮動特性)。

(4)在Panel1上放置兩個Bevel對象,調整其位置和大小,用于分隔按鈕組。

(5)調整SpeedButton1的大小及在Panel1中的位置。

(6)選擇SpeedButton1,設置其屬性Flat爲True。

(7)單擊SpeedButton1的屬性Glyph所對應的省略號小按鈕,打開PictureEditor窗口,選擇一個象征「查詢」的圖標。設置屬性ShowHint爲True,屬性Hint爲「查詢」。

(8)按步驟(5)至(7)的方法,分別設置好其余幾個SpeedButton按鈕的屬性。

這樣,一個快速按鈕條就制作完成了。運行時,快速按鈕均以浮動方式顯示,當鼠標移至其上時,即顯示按鈕外框,並顯示小提示。

2.借用ToolBar生成法

(1)在窗體上放置一個ToolBar1對象。

(2)設置ToolBar1的屬性EdgeBorders.ebLeft、eBTop、ebRight、ebButtom均爲True;屬性Flat爲True;調整ToolBar1的大小至合適尺寸。

(3)選擇ToolBar1,用右鍵點出快速選單,分別點擊NewButton和NewSeparator增加六個按鈕ToolButton和兩條分隔欄線。

(4)任意選擇一個ToolButton按鈕,調整其大小至合適尺寸,所有的ToolButton也同時被調整好。

(5)設置ToolBar1的屬性BorderWidth爲3,以調整ToolButton的位置。

(6)在窗體上放置一個ImageList1對象,設置它的屬性Height和Width的數值,以適應較大尺寸的圖像。

(7)雙擊ImageList1,通過「Add」按鈕分別裝入六個圖像,與ToolBar1中的六個ToolButton一一對應。

(8)設置ToolBar1的屬性Images爲ImageList1。

(9)設置六個ToolButton的屬性ShowHint爲True,並分別設置各自的小提示屬性Hint。

(10)還可以設置ToolBar1的HotImages指定鼠標指向按鈕時的圖片集。

采用ToolBar實現的快速按鈕條在外觀上與第一種方法制作的類似。

以上兩種方法均能實現快速按鈕條,但各有千秋:第一種設計過程較爲簡單;第二種方法則提供了更多的功能,如可用HotImages指定鼠標指向按鈕時的圖片集。讀者不妨從中選擇一種,並可繼續完善其功能。

建立臨時表的方法

數據輸入是開發數據庫程序的必然環節。在Client/Server結構中,客戶端可能要輸入一批數據後,再向服務器的後台數據庫提交,這就需要在本地(客戶端)建立臨時數據表來存儲用戶輸入的數據,待提交後,清除本地數據表。這種方法的好處是:提高輸入效率,減小網絡負擔。

由于用戶一次輸入的數據量一般情況下較小(不會超過幾百條記錄),所以臨時表可以建立在內存中,這樣處理速度較快。臨時表創建有如下兩種方法:

1.使用查詢控件創建臨時表

第1步:在窗體上放入查詢控件(TQuery),並設置好所連接的數據表。

第2步:添加如下語句:

TQuery. CachedUpdates=True;

TQuery. RequestLive=True。

第3步:在原有的SQL語句後加入一條Where子語句,要求加入這條Where子語句後SQL查詢結果爲空。

例如:

SELECT Biolife."Species No", Category, Common_Name, Biolife."Species Name", Biolife."Length (cm)", Length_In, Notes, Graphic

FROM "biolife.db" Biolife

where Biolife.Category=′A′ and Biolife.Category=′B′

這樣臨時表就建立好了。

2.使用代碼創建臨時表

函數代碼如下:

function CreateTableInMemory(const AFieldDefs:TFieldDefs):

TDataSet;

var TempTable:TClientDataSet;

begin

TempTable:=nil;

Result:=nil;

if AFieldDefs〈〉nil then

begin

try

TempTable:=TClientDataSet.Create(Application);

TempTable.FieldDefs.Assign(AFieldDefs);

TempTable.CreateDataSet;

Result:=(TempTable as TDataSet);

Except

if TempTable〈〉nil then TempTable.Free;

Result:=nil;

raise;

end

end

end;

在程序中按如下方法調用:

procedure TForm1.Button1Click(Sender: TObject);

var ADataSet:TDataSet;

begin

ADataSet:=TDataSet.Create(Self);

with ADataSet.FieldDefs do

begin

Add(′Name′,ftString,30,False);

Add(′Value′,ftInteger,0,False);

end;

with DataSource1 do

begin

DataSet:=CreateTableInMemory(ADataSet.FieldDefs);

DataSet.Open;

end;

ADataSet.Free;

end;

這樣,臨時表就創建完成。

方法1使用簡單,但由于利用了查詢控件,清空數據時需要查詢服務器後台數據庫,所以速度稍慢,而且不適用于臨時表中各個字段由幾個數據表的字段拼湊而成的情況。方法2適用範圍廣、速度快,但需要編寫代碼。

在InterBase數據庫中使用函數

程序員可能在用InterBase作爲後台數據庫時,常會爲其提供的函數過少而感到使用不便(只有四個),無法方便地編寫出複雜的存儲過程。InterBase本身無法編寫函數,但它可以使用外部函數(調用DLL中的函數)。下例中說明如何在InterBase 中聲明SUBSTR函數。

DECLARE EXTERNAL FUNCTION SUBSTR

CSTRING(80), SMALLINT, SMALLINT

RETURNS CSTRING(80)

ENTRY_POINT "IB_UDF_substr" MODULE_NAME "ib_udf"

其中:MODULE_NAME爲DLL的名稱,ENTRY_POINT爲函數名。

聲明後便可以使用,例如:

select SUBSTR(country)

from country

本例使用的是Delphi安裝時自帶的IBLocal數據庫,用戶也可以自己編寫函數來擴充InterBase

用Delphi實現遠程屏幕抓取

山東巨力股份有限公司CAD中心

檀革勤

---- 在網絡治理中,有時需要通過監視遠程計算機屏幕來了解網上微機的使用情況。雖然,市面上有很多軟件可以實現該功能,有些甚至可以進行遠程控制,但在使用上缺乏靈活性,如無法指定遠程計算機屏幕區域的大小和位置,進而無法在一屏上同時監視多個屏幕。其實,可以用Delphi自行編制一個靈活的遠程屏幕抓取工具,簡述如下。

---- 一、軟硬件要求。

---- Windows95/98對等網,用來監視的計算機(以下簡稱主控機)和被監視的計算機(以下簡稱受控機)都必須裝有TCP/IP 協議,並正確配置。如沒有網絡,也可以在一台計算機上進行調試。

---- 二、實現方法。

---- 編制兩個應用程序,一個爲VClient.exe,裝在受控機上,另一個爲VServer.exe,裝在主控機上。VServer.exe指定要監視的受控機的IP地址和將要在受控機屏幕上抓取區域的大小和位置,並發出屏幕抓取指令給VClient.exe,VClient.exe得到指令後,在受控機屏幕上選取指定區域,生成數據流,將其發回主控機,並在主控機上顯示出抓取區域的BMP圖象。由以上過程可以看出,該方法的要害有二:一是如何在受控機上進行屏幕抓取,二是如何通過TCP/IP協議在兩台計算機中傳輸數據。

---- UDP(User Datagram Protocol,意爲用戶報文協議)是Internet上廣泛采用的通信協議之一。與TCP協議不同,它是一種非連接的傳輸協議,沒有確認機制,可靠性不如TCP,但它的效率卻比TCP高,用于遠程屏幕監視還是比較適合的。同時,UDP控件不區分服務器端和客戶端,只區分發送端和接收端,編程上較爲簡單,故選用UDP協議,使用Delphi 4.0提供的TNMUDP控件。

---- 三、創建演示程序。

---- 第一步,編制VClient.exe文件。新建Delphi工程,將默認窗體的Name屬性設爲「Client」。加入TNMUDP控件,Name屬性設爲「CUDP」;LocalPort屬性設爲「1111」,讓控件CUDP監視受控機的1111端口,當有數據發送到該口時,觸發控件CUDP的OnDataReceived事件;RemotePort屬性設爲「2222」,當控件CUDP發送數據時,將數據發到主控機的2222口。

---- 在implementation後面加入變量定義

const BufSize=2048;{ 發送每一筆數據的緩沖區大小 }

var

BmpStream:TMemoryStream;

LeftSize:Longint;{ 發送每一筆數據後剩余的字節數 }

爲Client的OnCreate事件添加代碼:

procedure TClient.FormCreate(Sender: TObject);

begin

BmpStream:=TMemoryStream.Create;

end;

爲Client的OnDestroy事件添加代碼:

procedure TClient.FormDestroy(Sender: TObject);

begin

BmpStream.Free;

end;

爲控件CUDP的OnDataReceived事件添加代碼:

procedure TClient.CUDPDataReceived(Sender: TComponent;

NumberBytes: Integer; FromIP: String);

var

CtrlCode:array[0..29] of char;

Buf:array[0..BufSize-1] of char;

TmpStr:string;

SendSize,LeFTPos,TopPos,RightPos,BottomPos:integer;

begin

CUDP.ReadBuffer(CtrlCode,NumberBytes);{ 讀取控制碼 }

if CtrlCode[0]+CtrlCode[1]+CtrlCode[2]+CtrlCode[3]='show' then

begin { 控制碼前4位爲「show」表示主控機發出了抓屏指令 }

if BmpStream.Size=0 then { 沒有數據可發,必須截屏生成數據 }

begin

TmpStr:=StrPas(CtrlCode);

TmpStr:=Copy(TmpStr,5,Length(TmpStr)-4);

LeftPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1));

TmpStr:=Copy(TmpStr,Pos(':',TmpStr)+1,Length(TmpStr)

-Pos(':',TmpStr));

TopPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1));

TmpStr:=Copy(TmpStr,Pos(':',TmpStr)+1,Length(TmpStr)-

Pos(':',TmpStr));

RightPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1));

BottomPos:=StrToInt(Copy(TmpStr,Pos(':',TmpStr

)+1,Length(TmpStr)-Pos(':',TmpStr)));

ScreenCap(LeftPos,TopPos,RightPos,BottomPos); {

截取屏幕 }

end;

if LeftSize>BufSize then SendSize:=BufSize

else SendSize:=LeftSize;

BmpStream.ReadBuffer(Buf,SendSize);

LeftSize:=LeftSize-SendSize;

if LeftSize=0 then BmpStream.Clear;{ 清空流 }

CUDP.RemoteHost:=FromIP; { FromIP爲主控機IP地址 }

CUDP.SendBuffer(Buf,SendSize); { 將數據發到主控機的2222口 }

end;

end;

其中ScreenCap是自定義函數,截取屏幕指定區域,

代碼如下:

procedure TClient.ScreenCap(LeftPos,TopPos,

RightPos,BottomPos:integer);

var

RectWidth,RectHeight:integer;

SourceDC,DestDC,Bhandle:integer;

Bitmap:TBitmap;

begin

RectWidth:=RightPos-LeftPos;

RectHeight:=BottomPos-TopPos;

SourceDC:=CreateDC('DISPLAY',',',nil);

DestDC:=CreateCompatibleDC(SourceDC);

Bhandle:=CreateCompatibleBitmap(SourceDC,

RectWidth,RectHeight);

SelectObject(DestDC,Bhandle);

BitBlt(DestDC,0,0,RectWidth,RectHeight,SourceDC,

LeftPos,TopPos,SRCCOPY);

Bitmap:=TBitmap.Create;

Bitmap.Handle:=BHandle;

BitMap.SaveToStream(BmpStream);

BmpStream.Position:=0;

LeftSize:=BmpStream.Size;

Bitmap.Free;

DeleteDC(DestDC);

ReleaseDC(Bhandle,SourceDC);

end;

存爲「C:VClientClnUnit.pas」和「C:VClientVClient.dpr」,

並編譯。

---- 第二步,編制VServer.exe文件。新建Delphi工程,將窗體的Name屬性設爲「Server」。加入TNMUDP控件,Name屬性設爲「SUDP」;LocalPort屬性設爲「2222」,讓控件SUDP監視主控機的2222端口,當有數據發送到該口時,觸發控件SUDP的OnDataReceived事件;RemotePort屬性設爲「1111」,當控件SUDP發送數據時,將數據發到受控機的1111口。加入控件Image1,Align屬性設爲「alClient」;加入控件Button1,Caption屬性設爲「截屏」;加入控件Label1,Caption屬性設爲「左:上:右:下」;加入控件Edit1,Text屬性設爲「0:0:100:100」;加入控件Label2,Caption屬性設爲「受控機IP地址」;加入控件Edit2,Text屬性設爲「127.0.0.1」;

在implementation後面加入變量定義

const BufSize=2048;

var

RsltStream,TmpStream:TMemoryStream;

爲Server的OnCreate事件添加代碼:

procedure TServer.FormCreate(Sender: TObject);

begin

RsltStream:=TMemoryStream.Create;

TmpStream:=TMemoryStream.Create;

end;

爲Client的OnDestroy事件添加代碼:

procedure TServer.FormDestroy(Sender: TObject);

begin

RsltStream.Free;

TmpStream.Free;

end;

爲控件Button1的OnClick事件添加代碼:

procedure TServer.Button1Click(Sender: TObject);

var ReqCode:array[0..29] of char;ReqCodeStr:string;

begin

ReqCodeStr:='show'+Edit1.Text;

StrpCopy(ReqCode,ReqCodeStr);

TmpStream.Clear;

RsltStream.Clear;

SUDP.RemoteHost:=Edit2.Text;

SUDP.SendBuffer(ReqCode,30);

end;

爲控件SUDP的OnDataReceived事件添加代碼:

procedure TServer.SUDPDataReceived(Sender: TComponent;

NumberBytes: Integer; FromIP: String);

var ReqCode:array[0..29] of char;ReqCodeStr:string;

begin

ReqCodeStr:='show'+Edit1.text;

StrpCopy(ReqCode,ReqCodeStr);

SUDP.ReadStream(TmpStream);

RsltStream.CopyFrom(TmpStream,NumberBytes);

if NumberBytes< BufSize then { 數據已讀完 }

begin

RsltStream.Position:=0;

Image1.Picture.Bitmap.LoadFromStream(RsltStream);

TmpStream.Clear;

RsltStream.Clear;

end

else

begin

TmpStream.Clear;

ReqCode:='show';

SUDP.RemoteHost:=Edit2.Text;

SUDP.SendBuffer(ReqCode,30);

end;

end;

存爲「C:VServerSvrUnit.pas」和

「C:VServerVServer.dpr」,並編譯。

---- 四、測試。

---- 1、本地機測試:在本地機同時運行Vserver.exe和VClient.exe,利用程序的默認設置,即可實現截屏。查看「控制面板」-「網絡」-「TCP/IP」-「IP地址」,將程序的「客戶IP地址」設爲該地址 ,同樣正常運行。

---- 2、遠程測試:選一台受控機,運行VClient.exe;另選一台主控機,運行VServer.exe,將「受控機IP地址」即Edit2的內容設爲受控機的IP地址,「截屏」即可。以上簡要介紹了遠程屏幕抓取的實現方法,至于在主控機上一屏同時監視多個受控機,讀者可自行完善。以上程序,在Windows98對等網、Delphi 4.0下調試通過。

因爲COM/DCOM對象都不在Client程序運行的內存空間(內進程COM對象除外,即便如此,爲了統一接口,內進程的COM也不得傳遞指針),而且在Win32中所有的程序都有自己獨立的2GB的內存空間,程序與程序之間傳遞指針(內存地址)是毫無意義的,而數組、字符串等大量的數據在程序中都是分配一定的內存空間,然後用指針加內存偏移量來存取數據的,這時,如何在COM/DCOM對象中如何傳遞呢? 在Win32中引入了一新變量Variant,可以通過Variant傳遞數組。具體的實現方法,用Delphi實現爲: Server(COM/DCOM程序)端: procedure TTestDCOM.Send4(Size: Integer; D1: OleVariant); type TData=array [0..999] of Byte; Var Data:TData; i:Integer; begin for i:=0 to Size-1 do begin Data[i]:=D1[i]; end; end; Cleint端: Var D1:OleVariant; begin D1:=VarArrayCreate([0,99],varByte); { D1[1]:=45; .... file://將值存入D1中 } S.Send4(99,D1); file://S是TestDCOM對象 end; 作者:高素梅   配置數據引擎(BDE、SQL Link)的簡單方法   在數據庫程序分發時,需要攜帶數據引擎(BDE、SQL Link),並且在客戶端安裝完程序後還需要配置數據引擎,如用戶名(username)、密碼(PassWord)等等。假如手工配置的話,工作量比較大,這時,我們可利用InstallShield For Delphi輕松實現配置。在用InstallShield For Delphi制作安裝程序時,在生成安裝程序的目錄裏有一個*.iwz的文本文件,只要在[IDAPI Alias]片段中手工加入即可。 例如:   [IDAPI Alias]   username=SYSDBA   password=masterkey   安裝程序後數據引擎自動配置完畢。   制做快速按鈕條的方法   快速按鈕條上的每一個圖形按鈕都代表著一項常用的功能,同時,這些圖形按鈕尺寸較普通的圖標大,可以放置更大、更形象的圖形,甚至可以帶上簡短的提示,這對于用戶執行最常用的功能很有幫助。基于上述原因,越來越多的Windows應用程序采用快速按鈕條來改善應用程序的界面。筆者在用Delphi編程時,采用了兩種不同的方法來實現快速按鈕條,本文結合制作一個具有兩組、共六個按鈕的快速按鈕條的實例,列出了這兩種方法的具體設計步驟。   1.組合生成法   (1)在窗體上放置一個Panel1對象,作爲圖形按鈕的載體。   (2)設置Panel1的屬性Caption爲空,屬性Align爲alTop,調整其高度至合適尺寸。   (3)在Panel1上放置六個SpeedButton按鈕(選用SpeedButton,是因它具有浮動特性)。   (4)在Panel1上放置兩個Bevel對象,調整其位置和大小,用于分隔按鈕組。   (5)調整SpeedButton1的大小及在Panel1中的位置。   (6)選擇SpeedButton1,設置其屬性Flat爲True。   (7)單擊SpeedButton1的屬性Glyph所對應的省略號小按鈕,打開PictureEditor窗口,選擇一個象征「查詢」的圖標。設置屬性ShowHint爲True,屬性Hint爲「查詢」。   (8)按步驟(5)至(7)的方法,分別設置好其余幾個SpeedButton按鈕的屬性。   這樣,一個快速按鈕條就制作完成了。運行時,快速按鈕均以浮動方式顯示,當鼠標移至其上時,即顯示按鈕外框,並顯示小提示。   2.借用ToolBar生成法   (1)在窗體上放置一個ToolBar1對象。   (2)設置ToolBar1的屬性EdgeBorders.ebLeft、eBTop、ebRight、ebButtom均爲True;屬性Flat爲True;調整ToolBar1的大小至合適尺寸。   (3)選擇ToolBar1,用右鍵點出快速選單,分別點擊NewButton和NewSeparator增加六個按鈕ToolButton和兩條分隔欄線。   (4)任意選擇一個ToolButton按鈕,調整其大小至合適尺寸,所有的ToolButton也同時被調整好。   (5)設置ToolBar1的屬性BorderWidth爲3,以調整ToolButton的位置。   (6)在窗體上放置一個ImageList1對象,設置它的屬性Height和Width的數值,以適應較大尺寸的圖像。   (7)雙擊ImageList1,通過「Add」按鈕分別裝入六個圖像,與ToolBar1中的六個ToolButton一一對應。   (8)設置ToolBar1的屬性Images爲ImageList1。   (9)設置六個ToolButton的屬性ShowHint爲True,並分別設置各自的小提示屬性Hint。   (10)還可以設置ToolBar1的HotImages指定鼠標指向按鈕時的圖片集。   采用ToolBar實現的快速按鈕條在外觀上與第一種方法制作的類似。   以上兩種方法均能實現快速按鈕條,但各有千秋:第一種設計過程較爲簡單;第二種方法則提供了更多的功能,如可用HotImages指定鼠標指向按鈕時的圖片集。讀者不妨從中選擇一種,並可繼續完善其功能。   建立臨時表的方法   數據輸入是開發數據庫程序的必然環節。在Client/Server結構中,客戶端可能要輸入一批數據後,再向服務器的後台數據庫提交,這就需要在本地(客戶端)建立臨時數據表來存儲用戶輸入的數據,待提交後,清除本地數據表。這種方法的好處是:提高輸入效率,減小網絡負擔。   由于用戶一次輸入的數據量一般情況下較小(不會超過幾百條記錄),所以臨時表可以建立在內存中,這樣處理速度較快。臨時表創建有如下兩種方法:   1.使用查詢控件創建臨時表   第1步:在窗體上放入查詢控件(TQuery),並設置好所連接的數據表。   第2步:添加如下語句:   TQuery. CachedUpdates=True;   TQuery. RequestLive=True。   第3步:在原有的SQL語句後加入一條Where子語句,要求加入這條Where子語句後SQL查詢結果爲空。   例如:   SELECT Biolife."Species No", Category, Common_Name, Biolife."Species Name", Biolife."Length (cm)", Length_In, Notes, Graphic   FROM "biolife.db" Biolife   where Biolife.Category=′A′ and Biolife.Category=′B′   這樣臨時表就建立好了。   2.使用代碼創建臨時表   函數代碼如下:   function CreateTableInMemory(const AFieldDefs:TFieldDefs):   TDataSet;   var TempTable:TClientDataSet;   begin   TempTable:=nil;   Result:=nil;   if AFieldDefs〈〉nil then   begin   try   TempTable:=TClientDataSet.Create(Application);   TempTable.FieldDefs.Assign(AFieldDefs);   TempTable.CreateDataSet;   Result:=(TempTable as TDataSet);   Except   if TempTable〈〉nil then TempTable.Free;   Result:=nil;   raise;   end   end   end;   在程序中按如下方法調用:   procedure TForm1.Button1Click(Sender: TObject);   var ADataSet:TDataSet;   begin   ADataSet:=TDataSet.Create(Self);   with ADataSet.FieldDefs do   begin   Add(′Name′,ftString,30,False);   Add(′Value′,ftInteger,0,False);   end;   with DataSource1 do   begin   DataSet:=CreateTableInMemory(ADataSet.FieldDefs);   DataSet.Open;   end;   ADataSet.Free;   end;   這樣,臨時表就創建完成。   方法1使用簡單,但由于利用了查詢控件,清空數據時需要查詢服務器後台數據庫,所以速度稍慢,而且不適用于臨時表中各個字段由幾個數據表的字段拼湊而成的情況。方法2適用範圍廣、速度快,但需要編寫代碼。   在InterBase數據庫中使用函數   程序員可能在用InterBase作爲後台數據庫時,常會爲其提供的函數過少而感到使用不便(只有四個),無法方便地編寫出複雜的存儲過程。InterBase本身無法編寫函數,但它可以使用外部函數(調用DLL中的函數)。下例中說明如何在InterBase 中聲明SUBSTR函數。   DECLARE EXTERNAL FUNCTION SUBSTR   CSTRING(80), SMALLINT, SMALLINT   RETURNS CSTRING(80)   ENTRY_POINT "IB_UDF_substr" MODULE_NAME "ib_udf"   其中:MODULE_NAME爲DLL的名稱,ENTRY_POINT爲函數名。   聲明後便可以使用,例如:   select SUBSTR(country)   from country   本例使用的是Delphi安裝時自帶的IBLocal數據庫,用戶也可以自己編寫函數來擴充InterBase 用Delphi實現遠程屏幕抓取 山東巨力股份有限公司CAD中心 檀革勤 ---- 在網絡治理中,有時需要通過監視遠程計算機屏幕來了解網上微機的使用情況。雖然,市面上有很多軟件可以實現該功能,有些甚至可以進行遠程控制,但在使用上缺乏靈活性,如無法指定遠程計算機屏幕區域的大小和位置,進而無法在一屏上同時監視多個屏幕。其實,可以用Delphi自行編制一個靈活的遠程屏幕抓取工具,簡述如下。 ---- 一、軟硬件要求。 ---- Windows95/98對等網,用來監視的計算機(以下簡稱主控機)和被監視的計算機(以下簡稱受控機)都必須裝有TCP/IP 協議,並正確配置。如沒有網絡,也可以在一台計算機上進行調試。 ---- 二、實現方法。 ---- 編制兩個應用程序,一個爲VClient.exe,裝在受控機上,另一個爲VServer.exe,裝在主控機上。VServer.exe指定要監視的受控機的IP地址和將要在受控機屏幕上抓取區域的大小和位置,並發出屏幕抓取指令給VClient.exe,VClient.exe得到指令後,在受控機屏幕上選取指定區域,生成數據流,將其發回主控機,並在主控機上顯示出抓取區域的BMP圖象。由以上過程可以看出,該方法的要害有二:一是如何在受控機上進行屏幕抓取,二是如何通過TCP/IP協議在兩台計算機中傳輸數據。 ---- UDP(User Datagram Protocol,意爲用戶報文協議)是Internet上廣泛采用的通信協議之一。與TCP協議不同,它是一種非連接的傳輸協議,沒有確認機制,可靠性不如TCP,但它的效率卻比TCP高,用于遠程屏幕監視還是比較適合的。同時,UDP控件不區分服務器端和客戶端,只區分發送端和接收端,編程上較爲簡單,故選用UDP協議,使用Delphi 4.0提供的TNMUDP控件。 ---- 三、創建演示程序。 ---- 第一步,編制VClient.exe文件。新建Delphi工程,將默認窗體的Name屬性設爲「Client」。加入TNMUDP控件,Name屬性設爲「CUDP」;LocalPort屬性設爲「1111」,讓控件CUDP監視受控機的1111端口,當有數據發送到該口時,觸發控件CUDP的OnDataReceived事件;RemotePort屬性設爲「2222」,當控件CUDP發送數據時,將數據發到主控機的2222口。 ---- 在implementation後面加入變量定義 const BufSize=2048;{ 發送每一筆數據的緩沖區大小 } var BmpStream:TMemoryStream; LeftSize:Longint;{ 發送每一筆數據後剩余的字節數 } 爲Client的OnCreate事件添加代碼: procedure TClient.FormCreate(Sender: TObject); begin BmpStream:=TMemoryStream.Create; end; 爲Client的OnDestroy事件添加代碼: procedure TClient.FormDestroy(Sender: TObject); begin BmpStream.Free; end; 爲控件CUDP的OnDataReceived事件添加代碼: procedure TClient.CUDPDataReceived(Sender: TComponent; NumberBytes: Integer; FromIP: String); var CtrlCode:array[0..29] of char; Buf:array[0..BufSize-1] of char; TmpStr:string; SendSize,LeFTPos,TopPos,RightPos,BottomPos:integer; begin CUDP.ReadBuffer(CtrlCode,NumberBytes);{ 讀取控制碼 } if CtrlCode[0]+CtrlCode[1]+CtrlCode[2]+CtrlCode[3]='show' then begin { 控制碼前4位爲「show」表示主控機發出了抓屏指令 } if BmpStream.Size=0 then { 沒有數據可發,必須截屏生成數據 } begin TmpStr:=StrPas(CtrlCode); TmpStr:=Copy(TmpStr,5,Length(TmpStr)-4); LeftPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1)); TmpStr:=Copy(TmpStr,Pos(':',TmpStr)+1,Length(TmpStr) -Pos(':',TmpStr)); TopPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1)); TmpStr:=Copy(TmpStr,Pos(':',TmpStr)+1,Length(TmpStr)- Pos(':',TmpStr)); RightPos:=StrToInt(Copy(TmpStr,1,Pos(':',TmpStr)-1)); BottomPos:=StrToInt(Copy(TmpStr,Pos(':',TmpStr )+1,Length(TmpStr)-Pos(':',TmpStr))); ScreenCap(LeftPos,TopPos,RightPos,BottomPos); { 截取屏幕 } end; if LeftSize>BufSize then SendSize:=BufSize else SendSize:=LeftSize; BmpStream.ReadBuffer(Buf,SendSize); LeftSize:=LeftSize-SendSize; if LeftSize=0 then BmpStream.Clear;{ 清空流 } CUDP.RemoteHost:=FromIP; { FromIP爲主控機IP地址 } CUDP.SendBuffer(Buf,SendSize); { 將數據發到主控機的2222口 } end; end; 其中ScreenCap是自定義函數,截取屏幕指定區域, 代碼如下: procedure TClient.ScreenCap(LeftPos,TopPos, RightPos,BottomPos:integer); var RectWidth,RectHeight:integer; SourceDC,DestDC,Bhandle:integer; Bitmap:TBitmap; begin RectWidth:=RightPos-LeftPos; RectHeight:=BottomPos-TopPos; SourceDC:=CreateDC('DISPLAY',',',nil); DestDC:=CreateCompatibleDC(SourceDC); Bhandle:=CreateCompatibleBitmap(SourceDC, RectWidth,RectHeight); SelectObject(DestDC,Bhandle); BitBlt(DestDC,0,0,RectWidth,RectHeight,SourceDC, LeftPos,TopPos,SRCCOPY); Bitmap:=TBitmap.Create; Bitmap.Handle:=BHandle; BitMap.SaveToStream(BmpStream); BmpStream.Position:=0; LeftSize:=BmpStream.Size; Bitmap.Free; DeleteDC(DestDC); ReleaseDC(Bhandle,SourceDC); end; 存爲「C:VClientClnUnit.pas」和「C:VClientVClient.dpr」, 並編譯。 ---- 第二步,編制VServer.exe文件。新建Delphi工程,將窗體的Name屬性設爲「Server」。加入TNMUDP控件,Name屬性設爲「SUDP」;LocalPort屬性設爲「2222」,讓控件SUDP監視主控機的2222端口,當有數據發送到該口時,觸發控件SUDP的OnDataReceived事件;RemotePort屬性設爲「1111」,當控件SUDP發送數據時,將數據發到受控機的1111口。加入控件Image1,Align屬性設爲「alClient」;加入控件Button1,Caption屬性設爲「截屏」;加入控件Label1,Caption屬性設爲「左:上:右:下」;加入控件Edit1,Text屬性設爲「0:0:100:100」;加入控件Label2,Caption屬性設爲「受控機IP地址」;加入控件Edit2,Text屬性設爲「127.0.0.1」; 在implementation後面加入變量定義 const BufSize=2048; var RsltStream,TmpStream:TMemoryStream; 爲Server的OnCreate事件添加代碼: procedure TServer.FormCreate(Sender: TObject); begin RsltStream:=TMemoryStream.Create; TmpStream:=TMemoryStream.Create; end; 爲Client的OnDestroy事件添加代碼: procedure TServer.FormDestroy(Sender: TObject); begin RsltStream.Free; TmpStream.Free; end; 爲控件Button1的OnClick事件添加代碼: procedure TServer.Button1Click(Sender: TObject); var ReqCode:array[0..29] of char;ReqCodeStr:string; begin ReqCodeStr:='show'+Edit1.Text; StrpCopy(ReqCode,ReqCodeStr); TmpStream.Clear; RsltStream.Clear; SUDP.RemoteHost:=Edit2.Text; SUDP.SendBuffer(ReqCode,30); end; 爲控件SUDP的OnDataReceived事件添加代碼: procedure TServer.SUDPDataReceived(Sender: TComponent; NumberBytes: Integer; FromIP: String); var ReqCode:array[0..29] of char;ReqCodeStr:string; begin ReqCodeStr:='show'+Edit1.text; StrpCopy(ReqCode,ReqCodeStr); SUDP.ReadStream(TmpStream); RsltStream.CopyFrom(TmpStream,NumberBytes); if NumberBytes< BufSize then { 數據已讀完 } begin RsltStream.Position:=0; Image1.Picture.Bitmap.LoadFromStream(RsltStream); TmpStream.Clear; RsltStream.Clear; end else begin TmpStream.Clear; ReqCode:='show'; SUDP.RemoteHost:=Edit2.Text; SUDP.SendBuffer(ReqCode,30); end; end; 存爲「C:VServerSvrUnit.pas」和 「C:VServerVServer.dpr」,並編譯。 ---- 四、測試。 ---- 1、本地機測試:在本地機同時運行Vserver.exe和VClient.exe,利用程序的默認設置,即可實現截屏。查看「控制面板」-「網絡」-「TCP/IP」-「IP地址」,將程序的「客戶IP地址」設爲該地址 ,同樣正常運行。 ---- 2、遠程測試:選一台受控機,運行VClient.exe;另選一台主控機,運行VServer.exe,將「受控機IP地址」即Edit2的內容設爲受控機的IP地址,「截屏」即可。以上簡要介紹了遠程屏幕抓取的實現方法,至于在主控機上一屏同時監視多個受控機,讀者可自行完善。以上程序,在Windows98對等網、Delphi 4.0下調試通過。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有