程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> COMDCOM對象中通過Variant傳遞數組

COMDCOM對象中通過Variant傳遞數組

編輯:Delphi
  因為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地址,“截屏”即可。以上簡要介紹了遠程屏幕抓取的實現方法,至於在主控機上一屏同時監視多個受控機,讀者可自行完善。以上程序

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved