新聞| | PChome| 登入
2007-10-25 22:48:57 | 人氣139| 回應0 | 上一篇 | 下一篇
推薦 0 收藏 0 轉貼0 訂閱站台

記憶體對映檔的作法

來源:Bruce McKinney,  cww  Modify

    不同行程間的資訊相互傳遞,在32位元的環境來說,是有一些困難,因為每個行程有其
自己的4G Byte的位走空間,那如何做到行程間的相互溝通呢?有幾個方式可行,例如:
使用SendMessage()將訊息傳送給特定的Window,不過這種方式首先要先得到另一個Window
的hWnd,但有時候我們也不知會送之給誰,那就行不通了;再則以SendMessage來說,它
只能傳兩個整數參數過去(wParam, lParam),而wMsg是指定所送訊息的代號,一般我們會
自訂一個代碼(WM_USER + X, X為一整數),只傳整數,那大概不太夠,不能傳字串便很
痛苦,或許會說,如果傳過去的是指向一個字串的位址(位址是Long值),再想辦法將位
址指向的內容取出不就好了?可是,別忘了,32位元的世界中,位址空間沒有共用,也就是
說A行程中位址X的內容和B行程中X位址指向的內容並不相同,除非使用的是系統的資源,
而不是行程的資源。

Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
        ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

    另外一種行程間的通訊的方式就是透過檔案,將之寫到檔案的方法想必人人都會,但討
厭的是要殺檔,而且過份多的File I/O於Hard Disk的同一地方,可能HardDisk會很決就
玩完了;相對的,如果產生一記憶體對應檔,那就比較快,但傳的資料數量有限。

    我由Bruce McKinney 書中取出這個記憶體對應檔作法的Class。這Class使不同行程可以
傳遞字串。

該Class有一個Function兩個屬性,
Create(sName as String)
           這個Function的目的是產生一個記憶體應檔,sName是一字串,地位就好比一般
           檔案中的檔名,不管那個行程,只要傳入的sName相同,便是指向相同的記憶體
           對應檔 Object。
Data       這個Property負責設定與取出字串。
LastErr    是取得上一次呼叫記憶體對應檔的API所產生的錯誤代碼。

使用方式: 製作出以下的專案一.exe 與專案二.exe而後執行這兩個專案,首先,先在
專案一的TextBox keyin一些文字,而後按專案二的Command1,可以看到專案二的Label1
變成方才您所Keyin進TextBox的文字,看吧,兩個.Exe檔已可以互傳資料了。

註:專案二中故意把MemString物件宣告成於Command1中的區域物件,當專案二的Command1
    每次按下時都會執行mf.Create("MyMem")的動作,而這個記憶體對應檔物件早在專
    案一中Create出了,所以它每次執行CreateFileMapping時時會產生ERROR_ALREADY_EXISTS
    的錯誤,但這錯誤沒有關係,因仍然傳回正確的物件代碼(h),而緊接著的MapViewOfFile()
    又把Error物件的訊息清掉,所以如果一切正常,我們查到的LastErr屬性會是0。而
    當專案二的Command1_Click()執行完後,也結束了專案二mf的生命週期,所以會執行
    MemString.Cls中的Destory動作,把由系統取得的handle都Release掉(即執行UnmapViewOfFile
    、CloseHandle,然而此時專案一仍對該物件存有引用,所以該記體對應檔的物件仍
    然存在,要等到所有引用都結束時,才會真的由系統中Release掉,這也是為什麼
    專案二中明明執行過好多次的Destory,而再按Command1時仍可取得Form1.Text1.Text
    的內容;最後,先結束專案一,再按一下專案二的Command1,Label1.Caption會是""。

'專案一 請自行新增物件模組MemString.Clx
'需一個Command Button, 一個Text Box
Option Explicit
Private mf As New MemString

'設定Text1.Text的資料到記憶體對應檔
Private Sub text1_change()
mf.Data = Text1.Text
End Sub

'產生一個記憶體對應檔
Private Sub Form_Load()
Dim B As Boolean
B = mf.Create("MyMem")
End Sub
專案二 請自行新增物件模組MemString.Clx
'需一個Command Button, 一個Label
Option Explicit

'取出記憶體對應檔內專案一所設的字串
Private Sub Command1_Click()
Dim mf As New MemString
Dim B As Boolean
B = mf.Create("MyMem")
Label1.Caption = mf.Data
End Sub

'以下在MemString.Cls
Option Explicit

Const SECTION_MAP_WRITE = &H2
Const SECTION_MAP_READ = &H4
Const FILE_MAP_WRITE = SECTION_MAP_WRITE
Const FILE_MAP_READ = SECTION_MAP_READ
Const PAGE_READONLY = &H2
Const PAGE_READWRITE = &H4
Const ERROR_ALREADY_EXISTS = 183&
Const ERROR_INVALID_DATA = 13&

Private Declare Function CreateFileMapping Lib "KERNEL32" Alias "CreateFileMappingA" _
        (ByVal hFile As Long, lpFileMappigAttributes As Any, _
        ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "KERNEL32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "KERNEL32" (lpBaseAddress As Any) As Long
Private Declare Function CloseHandle Lib "KERNEL32" (ByVal hObject As Long) As Long
Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" ( _
   lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
Private h As Long, p As Long, e As Long
Const MEM_HANDLE As Long = -1&
'產生一個記憶體對應檔,名稱為sName
'該記憶體對應檔裡面存的資料分成兩部份
'一個Long值,代表字串的長度,另一為字串,這字串才是要Share部份
Function Create(sName As String) As Boolean
    Create = False
    If sName = "" Then Exit Function
    ' Try to create file mapping of 65535 (only used pages matter)
    h = CreateFileMapping(MEM_HANDLE, ByVal 0, PAGE_READWRITE, _
                          0, 65535, sName)
    '如果sName原本就存在,則傳回的h值是先前Call CreateFileMapping的handle of file Mapping Object
    '而且Err.LastDllError 傳回的是ERROR_ALREADY_EXISTS,如果sName原來不存在,則傳回新的Handle值
    '且Err.LastDllError = 0
    e = Err.LastDllError
    ' Unknown error, bail out
    If h = 0 Then Destroy: Exit Function

    ' Get pointer to mapping
    p = MapViewOfFile(h, FILE_MAP_WRITE, 0, 0, 0)
    If p = 0 Then e = Err.LastDllError: Exit Function
    If e <> ERROR_ALREADY_EXISTS Then
        ' Set size of new file mapping to 0 by copying first 4 bytes
        Dim c As Long ' = 0
        '將0放入記憶體對應檔中的前4個Byte
        CopyMemory ByVal p, c, 4
    ' Else
        ' Existing file mapping
    End If
    e = 0
    Create = True
End Function
Property Get Data() As String
    If h = 0 Or p = 0 Then e = ERROR_INVALID_DATA: Exit Property
    Dim c As Long, sData As String
    CopyMemory c, ByVal p, 4
    ' Copy rest of memory into string
    If c = 0 Then Exit Property ' Data = sEmpty
    sData = String$(c, 0)
    '將字串放入記憶體對應檔中的第4個Byte之後
    CopyMemory ByVal sData, ByVal (p + 4), c
    Data = sData
End Property

Property Let Data(s As String)
    If h = 0 Or p = 0 Then e = ERROR_INVALID_DATA: Exit Property
    Dim c As Long
    c = Len(s)
    ' Copy length to first 4 bytes and string to remainder
    CopyMemory ByVal p, c, 4
    CopyMemory ByVal (p + 4), ByVal s, c
End Property

Property Get LastErr() As Long
    LastErr = e
End Property
Private Sub Destroy()
   Dim i As Long
    i = UnmapViewOfFile(p)
    i = CloseHandle(h)
    h = 0
    p = 0
End Sub

Private Sub Class_Terminate()
    If h <> 0 Then Destroy
End Sub

                                                        

台長: Kenny
人氣(139) | 回應(0)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 教育學習(進修、留學、學術研究、教育概況) | 個人分類: 程式設計 |
此分類下一篇:如何用VB建立捷徑(ShortCut)
此分類上一篇:建立與讀取.ini檔

是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文