1. 程式人生 > >實現程序間資料交換的兩種方法和應用

實現程序間資料交換的兩種方法和應用

Windows作業系統是一個多工系統,每個任務都有相應的程序對應。熟悉windows系統的使用者知道,每個程序都有自己獨立的記憶體地址和記憶體空間。這對程序間之間的資料相互訪問和相互交換帶來一定的不便,但是在實際應用中有時要在程序間進行資料交換。windows系統提供了許多方法實現程序間的資料交換,比如我們可以通過磁碟檔案來進行交換,這實際是最簡單可行的辦法,但執行速度大打折扣,特別是對於大批量資料交換時。另外我們可以通過Windows系統提供的CreateFileMaping、OpenFileMapping、MapViewofFile等API函式來實現程序間的資料交換,但實現方法相對複雜。

本文將介紹另外兩種程序間資料交換的方法,一種是通過剪貼簿的程序資料交換方法,另一種是直接記憶體讀取的程序資料交換方法。最後將用Delphi語言舉例加以實現應用。

一、通過剪貼簿的程序資料交換方法

剪貼簿是windows系統專門提供用來不同應用程式之間的資料交換,使用者只要通過“複製”和“粘帖”兩個動作就可以實現應用程式之間的資料交換。使用者可以自定義剪貼簿格式實現資料交換的目的。

其方法步驟為:

1、資料傳送程序向剪貼簿“複製”使用者自定義的資料內容

2、資料傳送程序向資料接受程序傳送資料交換的訊息。

3、資料接受程序收到訊息以後向剪貼簿“貼上”使用者自定義的資料內容。

這種方法的實現過程如圖一所示:

該方法涉及到的重要API函式主要有:

1、RegisterClipboardFormat

這個函式是向系統剪貼簿註冊新的剪貼簿資料格式其函式呼叫格式為:

UINT RegisterClipboardFormat(
    LPCTSTR lpszFormat 	  // 新剪貼簿資料格式的名稱
   );

如果該名稱的剪貼簿格式已經註冊函式返回已經的標示號,否則函式返回一個新的標示號。

2、GlobalAlloc、GlobalLock

這兩個函式前者是用於從當前程序的記憶體空間分配一定位元組數的記憶體,後者是對指定的記憶體加鎖。它們的函式呼叫格式分別為:

HGLOBAL GlobalAlloc(
    UINT uFlags,  	//分配到的記憶體屬性
    DWORD dwBytes 	// 需要記憶體分配的空間大小
   );
LPVOID GlobalLock(
    HGLOBAL hMem  	// 需要加鎖的記憶體“控制代碼”
   );

3、Clipboard的Open、SetAsHandle、Close、GetAsHandle

這四個函式是Delphi語言Clipboard全域性變數提供專門用於對剪貼簿資料“複製”和“粘帖”動作所要用到的函式。在Clipbrd.pas單元中實現。其函式格式略。

二、直接記憶體讀取的程序資料交換方法

這種方法是通過Windows系統一系列API函式呼叫直接讀取另一個程序的記憶體,來實現資料交換的目的。

其方法步驟為:

1、資料傳送方程序資料接受方程序傳送資料交換的訊息,Wparam引數值為資料傳送方程序標示號,Lparam引數值為要傳送的資料的地址。

2、資料接受方程序收到訊息以後直接讀取資料傳送方程序記憶體地址的資料。

這種方法的實現過程如圖二所示:

該方法涉及的重要API函式主要有:

1、GetCurrentProcessId

這個函式主要獲取當前執行程序的程序標示號,其函式格式為:

DWORD GetCurrentProcessId(VOID)

2、openProcess

這個函式主要獲得一個已經執行的程序的“程序控制代碼”,以便在另外的API函式呼叫。其函式格式為:

HANDLE OpenProcess(
    DWORD dwDesiredAccess,	// 要開啟的程序的訪問模式
    BOOL bInheritHandle,	// 該程序控制代碼是否在子執行緒中繼承
    DWORD dwProcessId 	// 程序的標示號
   );

3、ReadProcessMemory

這個函式是直接記憶體讀取的程序資料交換方法最核心的一個函式,它實現從另一個程序中讀取記憶體資料。其函式格式為:

BOOL ReadProcessMemory(
    HANDLE hProcess,  	    //程序控制代碼
    LPCVOID lpBaseAddress,	// 要讀取記憶體的起始地址
    LPVOID lpBuffer,	       //存放讀取的資料的變數
    DWORD nSize,	           //需要讀取的位元組數
    LPDWORD lpNumberOfBytesRead 	// 實際讀取到的位元組數
   );

三、兩種程序資料交換方法的應用舉例

為了更加詳細地介紹上述兩種方法,下面利用Delphi語言結合實際的例子來闡述它的應用。該例子分別用通過剪貼簿的程序資料交換的方法和直接記憶體讀取的程序資料交換方法實現兩個程序間的交換一個記錄資料,該記錄的資料格式為:

TFriend=packed record
     name    :array[1..8] of char;
     age     :byte;
     address :array[1..30] of char;
  end;

另外定義兩條訊息和幾個需要用到的常量:

1.WM_Datasend_byClpbrd=WM_user+1000;  //用於通過剪貼簿的程序資料交換的方法的訊息;
2.WM_DataSend_byMemory=WM_user+1001;// 直接記憶體讀取的程序資料交換方法的訊息;
3.receivewindowcaption='DataReceiver';     //接收資料程序視窗的標題;
4.receivewindowclassname='Data Receive Window';//接受資料程序視窗的類別名稱;
5.userDefineformat='process data exchange'; //自定義剪貼簿資料格式名稱;

以上常量和記錄結構是傳送程序和接受程序的兩個程式都要用到的資料。可以單獨存放在一個檔案中用uses引用,或用{$I }的方法引用。

(一)資料傳送程序程式的實現

1、在Delphi的IDE環境中新建Application

2、在Form1中加入一個Tspinedit、兩個Tedit和兩個Tbutton控制元件(分別為Button1和button2),兩個Edit控制元件分別供輸入姓名和地址,SpinEdit控制元件供輸入年齡。

3、過載Button1的onClick程式用於剪貼簿資料交換,如下所示:

procedure TForm1.Button1Click(Sender: TObject);
var
   wnd     :Hwnd;
   Friend  :TFriend;
   hmem    :Thandle;
   datapointer :pointer;
   CF_User  :Uint;
begin
   //尋找資料接受程序的視窗
   wnd:=findwindow(receivewindowclassname,receivewindowcaption);
   //如果找到了向剪貼簿複製資料並且向資料接受程序傳送訊息
   if wnd<>0 then  
begin
   //申請記憶體
         hmem:=globalAlloc(GMEM_MOVEABLE,sizeof(friend));
         //給記錄賦值
         strpcopy(@friend.name,edit1.text);
         friend.age:=byte(spinedit1.Value);
         strpcopy(@friend.address,edit2.text);
         //獲取申請到的記憶體地址並且把記錄的值匯入記憶體
         DataPointer := GlobalLock(hmem);
         //把記錄資料複製到Global記憶體中
         move(friend,datapointer^,sizeof(friend));
         //註冊或獲取新的剪貼簿資料格式標號
         CF_User:=registerclipboardformat(userdefineformat);
         //向剪貼簿複製資料
         clipboard.Open;
         clipboard.SetAsHandle(CF_USER,hmem);
         clipboard.Close;
         //向接收程序視窗傳送訊息
         sendmessage(wnd,WM_Datasend_byClpbrd,0,0);
      end;
end;

4、過載button2的OnClick程式用於直接記憶體讀取的資料交換,如下所示:

procedure TForm1.Button2Click(Sender: TObject);
var
   wnd       :Hwnd;
   Friend    :TFriend;
Begin
   //尋找資料接受程序的視窗
   wnd:=findwindow(receivewindowclassname,receivewindowcaption);
   //如果找到了向資料接收程序視窗傳送訊息
   if wnd<>0 then
begin
   //對記錄賦值
         strpcopy(@friend.name,edit1.text);
         friend.age:=byte(spinedit1.Value);
         strpcopy(@friend.address,edit2.text);
         //傳送訊息,把傳送程序的程序標示號作為Wparam
         //把記錄地址作為Lparam進行傳遞
       sendmessage(wnd,WM_DataSend_byMemory,
getcurrentprocessID,lparam(@Friend));
      end;
end;

5、儲存、編譯、執行

(二)資料接受程序程式的實現

1、在Delphi的IDE環境新建Application;

2、在Form1中加入三個Tedit控制元件,接受傳送過來的資料;

3、過載Form1的CreateParams程式,重新定義Form1的類,程式如下:

procedure TForm1.CreateParams(var Params: TCreateParams);
    begin
      inherited CreateParams(Params);
      params.Caption:=receivewindowcaption;
      Params.WinClassName :=receivewindowclassname;
    end;

4、過載在Form1的wndproc程式接受兩種方法傳送過來的資料,程式如下:

procedure Tform1.wndproc(var message:Tmessage);
   var
    processhnd   :Thandle;
      Friend       :TFriend;
numread     :dword;
hmem       :Thandle;
clipdata      :pointer;
CF_User     :Uint;
        Begin
           Case message.msg of
               //處理剪貼簿方式傳送過來的訊息
WM_Datasend_byClpbrd:
   Begin
     //註冊或獲取新的剪貼簿資料格式標號
     CF_User:= registerclipboardformat(userdefineformat);
     if clipboard.HasFormat(CF_User) then
        begin
           //獲取剪貼簿的內容,並且分別賦值給三個Edit
           hmem:=clipboard.GetAsHandle(CF_user);
           clipdata:=globallock(hmem);
           if clipdata<>nil then
              begin
                 move(clipdata^,Friend,sizeof(Friend));
                 edit1.text:=Friend.name;
                 edit2.text:=inttostr(Friend.age);
                 edit3.text:=Friend.address;
              end;
        end;
       message.Result:=1;
   End;
//處理直接記憶體讀取傳送過來的訊息
               WM_DataSend_byMemory:
                  Begin
                     //獲取傳送程序的“程序控制代碼”,設定訪問模式為“讀”
                     processhnd:=openprocess(PROCESS_VM_READ,
false,message.WParam);
                     //讀取傳送程序的記憶體資料
  readprocessmemory(processhnd,
ptr(message.lparam),
@friend,sizeof(friend),numread);
edit1.text:=Friend.name;
    edit2.text:=inttostr(Friend.age);
    edit3.text:=Friend.address;
     closehandle(processhnd);
     message.result:=1;
                  End;
Else
   //對於其它訊息依然按照原來的方法進行訊息處理
Inherited wndproc(message);
        End;

5、儲存、編譯、執行

到這裡為止已經實現上述程序間記錄資料的交換的兩種方法。執行結果如圖三所示:

圖三

以上程式僅僅是上面介紹的兩種方法最簡單應用,使用者可以根據自己的實際需要加以拓展應用。上述程式在Windows 2000+Delphi 5.0的環境下執行通過。 

轉自:http://industry.ccidnet.com/art/322/20031027/68697_1.html

下面是我寫的剪貼簿交換資料的程式碼 點選下載

相關推薦

實現程序資料交換方法應用

Windows作業系統是一個多工系統,每個任務都有相應的程序對應。熟悉windows系統的使用者知道,每個程序都有自己獨立的記憶體地址和記憶體空間。這對程序間之間的資料相互訪問和相互交換帶來一定的不便,但是在實際應用中有時要在程序間進行資料交換。windows系統提供了許多方

通過記憶體對映實現程序資料交換

程序間通訊有好幾种放發,其中共享記憶體可以實現大量快速得資料交換,現簡單介紹下這種方法得基本原理所用API函式說明:HANDLE CreateFileMapping(  HANDLE hFile,              // handle to file to map ,

python 使用多程序實現併發程式設計/使用queue進行程序資料交換

import time import os import multiprocessing from multiprocessing import Queue, pool """ 一.Python 使用多程序實現併發程式設計: 因為cpython直譯器中有GIL存在的原因(每個程序都會維護一

C#實現匯入匯出Excel資料方法詳解

這篇文章主要為大家詳細介紹了C#匯入匯出Excel資料的兩種方法,具有一定的參考價值,感興趣的小夥伴們可以參考一下本文為大家分享了C#匯入匯出Excel資料的具體程式碼,供大家參考,具體內容如下注:對於實體類物件最好新建一個並且繼承原有實體類,這樣可以將型別進行修改;方法一:

C語言經典演算法(七)——遞迴實現階乘演算法的方法

今後繼續整理演算法並寫出自己的理解和備註。 C++實現的:遞迴實現階乘演算法N! 1、 遞迴實現n! <1> 題目描述:輸入n值,求解n的階乘 <2> 方法一:累乘法 <3> 方法二:遞迴法 原始碼: 一、 遞迴實現n! 1、 累乘法 #

Java實現生產者消費者模式的方法

1、 利用 Object的 wait/notify,和非阻塞佇列實現 import java.util.PriorityQueue; public class Test{ private int size=10; private PriorityQueue&

scrapy框架 用post 爬取網站資料方法區別

post請求,一定要重新呼叫父類的 start_requests(self)方法 方法1:(推薦) 重構start_requests def start_requests(self): data = { 'source': 'index_na

方法實現Python二分查詢演算法 方法實現Python二分查詢演算法

兩種方法實現Python二分查詢演算法   一. ? 1 2

mybatis查詢樹形資料方法

原貼地址:https://www.cnblogs.com/nick-guo-sdly/p/7668462.html 最近開發中遇到了很多樹形結構資料的需要,利用mybatis提供巢狀查詢功能,基本上可以完美解決,但是對於其中的原理並不理解,導致在使用的時候像瞎貓碰死耗子一樣,照著先前成功的例子c

實現List集合排序的方法(使用Collections.sort方法

1:實現comparable package core.java.collection.collections;      public class User implements Comparable<User>{              private i

Python實現"3的冪"的方法

給定一個整數,寫一個函式判斷它是否是3的冪 Example 1: Input: 27 Output: true Example 2: Input: 0 Output: false Example 3: Input: 9 Output: true Exampl

Python實現"4的冪"的方法

給定一個帶符號整數,寫一個函式判斷它是否是4的冪 Example: Given num = 16, return true. Given num = 5, return false. 進階: 你能不用迴圈或者遞迴完成本題麼? 1:累除4 迴圈 def isPo

Python實現"左葉子之和"的方法

給定一顆二叉樹,返回它所有左葉子節點之和 Example:     3    / \   9  20     /  \    15   7 There are two left leaves in the binary tree, with values 9 and

Python操作Mongodb插入資料方法:insert_one()與insert_many()

sys.setdefaultencoding('utf8') import web from pymongo import MongoClient class getPltfList(object):     def __init__(self):         self.db1 = web.databa

從執行緒返回資料方法

執行緒中返回資料和向執行緒傳遞資料類似。也可以通過類成員以及回撥函式來返回資料。但類成員在返回資料和傳遞資料時有一些區別,下面讓我們來看看它們區別在哪。 一、通過類變數和方法返回資料 使用這種方法返回資料需要在呼叫start方法後才能通過類變數或方法得到資料。讓我們先

Python實現"顛倒二進位制位"的方法

翻轉給定的32位無符號整數的二進位制位 Example: Input: 43261596 Output: 964176192 Explanation: 43261596 represented in binary as 0000001010010100000111101

初學Java多執行緒:從執行緒返回資料方法

從執行緒中返回資料和向執行緒傳遞資料類似。也可以通過類成員以及回撥函式來返回資料。但類成員在返回資料和傳遞資料時有一些區別,下面讓我們來看看它們區別在哪。 一、通過類變數和方法返回資料 使用這種方法返回資料需要在呼叫start方法後才能通過類變數或方法得到資料。讓我們先來看

刪除一堆資料中重複資料方法(單鏈表與線性表)c++

前言   第一次寫部落格,問題雖然簡單,但是我寫的很認真的,,儘量將自己的思路寫的清晰,大神若路過請不要見笑(還望多多指點),真誠的希望我寫的東西能幫助到一些 人,有問題或錯誤都可以提,讓我們共同進步! 1.問題概述   在一堆資料中可能存在重複的資料,請將重

使用C++11實現執行緒池的方法

概述:什麼是執行緒池?    因為程式邊執行邊建立執行緒是比較耗時的,所以我們通過池化的思想:在程式開始執行前建立多個執行緒,這樣,程式在執行時,只需要從執行緒池中拿來用就可以了.大大提高了程式執行效率. 如何實現:    一般執行緒池都會有以下幾個部分構成: 1. 執行

SQL Server 複製表及資料方法

1、新表不存在(即複製資料的同時建立與舊錶相同結構的新表): select [col1,col2,col3...] into new_table from old_table where 1=1 2、新表已存在,從舊錶從插入選擇的資料(注意:表的[主鍵]不要複製,