Windows 的這個 File Mapping 的方法,是可以用在 file 及 memory 的。
用了這個方法,不同的 process 就可以共用一個 memory 區域,達到 share memory 的功能。
要 share memory ,其步驟是
1 CreateFileMapping, 請求開啟一個區域,並且給該區域一個名字。之後,可以得到該區域的 handle,
2 MapViewOfFile, 要對已開啟的區域做動作,必須要建立一個 view 才行。之後,會得到 memory 的 address。
3 讀寫 view,在VB裡,可以使用 copy memory 來做讀寫的動作
4 UnmapViewOfFile 把 view 給關起來。當程式要結束的時候該做的事。
5 CloseHandle 把 FileMapping 給釋放掉,也是當程式結束,或不需要 share memory 的時候該做的事。免得系統的memory被吃光了也找不到兇手。
按照 MSDN 的介紹,寫了一個程式,可以CreateFileMapping,也可以OpenFileMapping。
我定義,執行 CreateFileMapping 那一個叫做 Server,執行OpenFileMapping 的叫做 Client。
當程式執行之後,可以執行兩次,就會有兩個程式。
兩個都可以當 Server (CreateFileMapping),而且名字可以一樣,這樣就可以溝通了。
當然也可以一個當 Server,一個當 Client。可以兩個都當 Server 的原因,我推測是因為只 share memory 的關係。
Share file 可能就不可以兩個都當 server。這個就不去實驗了,因為目前只關心 share memory。
同時兩個程式以上溝通也可以。只要多開幾次程式,而且有一個人當 Server 即可。感覺很方便。
這個程式只 share 32 byte 的 memory,所以只能傳遞比這個小的 message。
若是想要實作一個新的 protocol 來傳遞大 message 也行。
這個樣子的特性,讓我想到電路傳輸的特性,應該可以用來模擬CDMA, TDMA, 網路上的 CSMA/CA, CSMA/CD 的行為。
也可以用來模擬SECS I 或 HSMS 的傳送,對於學習上有相當幫助。
但是更有幫助的,當然是在這一層上面,支援更高一點的 protocol,做異質轉換。
或是建立新的 protocol,為自己的程式量身打造一個小而快的溝通管道。
雖然這種方式,已經不是新聞了,也一定有一堆的研究,但是如此就可以讓位在同樣 server 的 EAP 有個免費、簡單的管道互相溝通。
接下來的工作,是設計一個新的 protocol 來研究通訊模式嗎?
還是當做 adapter 接收現有的 protocol 如 SECS2呢?
都是一個學習的方向。
還有,若是對於在 hub 內資料如何傳送有了解的話,就可以設計一個比較複雜的 protocol 以提供穩定的溝通環境。
當然,不是只有這個 file mapping 可以用而已,還有其他的方式,也需多了解。例如 platform independent 的方法,
或是跨電腦的溝通,也是將來應該要學習的方向。
[1] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/sharing_files_and_memory.asp
本文授權為 CC
code in Module1.bas
==================================================
Attribute VB_Name = "Module1"
Public Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" _
(ByVal hFile As Long, _
lpFileMappingAttributes As Any, _
ByVal flProtect As Long, _
ByVal dwMaximumSizeHigh As Long, _
ByVal dwMaximumSizeLow As Long, _
ByVal lpName As String) As Long
Public Const INVALID_HANDLE_VALUE As Long = -1
Public Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Public Const PAGE_READ_WRITE As Long = 4
'===========================================================================================
Public Declare Function MapViewOfFile Lib "kernel32" _
(ByVal hFileMappingObject As Long, _
ByVal dwDesiredAccess As Long, _
ByVal dwFileOffsetHigh As Long, _
ByVal dwFileOffsetLow As Long, _
ByVal dwNumberOfByteToMap As Long) As Long
Public Const FILE_MAP_ALL_ACCESS = 983071
'==========================================================================================
Public Declare Function UnmapViewOfFile Lib "kernel32" (lpBaseAddress As Any) As Long
'==========================================================================================
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pvDst As Any, pvSrc As Any, ByVal LengthInByte As Long)
'==========================================================================================
Public Declare Function GetLastError Lib "kernel32" () As Long
'==========================================================================================
Public Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal lpName As String) As Long
'==========================================================================================
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'==========================================================================================
Public Const ERROR_ALREADY_EXISTS = 183&
'==========================================================================================
'Public Const FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS
'Public Const SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE
'Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
'Public Const SECTION_QUERY = &H1
'Public Const SECTION_MAP_WRITE = &H2
'Public Const SECTION_MAP_READ = &H4
'Public Const SECTION_MAP_EXECUTE = &H8
'Public Const SECTION_EXTEND_SIZE = &H10
==================================================
code in Module1.bas complete
code in form1.frm
==================================================
VERSION 5.00
Begin VB.Form Form1
Caption = "Server"
ClientHeight = 3090
ClientLeft = 60
ClientTop = 450
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 3090
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
Begin VB.CommandButton Command4
Caption = "Connect Share"
Height = 495
Left = 3480
TabIndex = 4
Top = 720
Width = 1095
End
Begin VB.CommandButton Command3
Caption = "change value"
Height = 495
Left = 3480
TabIndex = 3
Top = 1920
Width = 1095
End
Begin VB.TextBox Text1
Height = 1215
Left = 360
MultiLine = -1 'True
TabIndex = 2
Text = "Form1.frx":0000
Top = 360
Width = 2535
End
Begin VB.CommandButton Command2
Caption = "stop monitor"
Height = 495
Left = 3480
TabIndex = 1
Top = 1320
Width = 1095
End
Begin VB.Timer Timer1
Left = 1680
Top = 2160
End
Begin VB.CommandButton Command1
Caption = "Create Share"
Height = 495
Left = 3480
TabIndex = 0
Top = 120
Width = 1095
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Dim m_handle As Long
Dim BaseAddress As Long
Dim ShareMemoID As String
Private Sub Command1_Click()
Form1.Caption = "Server"
Dim ERROR_CODE As Long
Dim ATTS As SECURITY_ATTRIBUTES
If ShareMemoID = "" Then
ShareMemoID = "ShareMemoTest"
End If
ShareMemoID = InputBox("Input ShareMemoryID", "ShareMemoryID", ShareMemoID)
If ShareMemoID = "" Then
MsgBox "share memory id can't be null string"
Exit Sub
End If
m_handle = CreateFileMapping(INVALID_HANDLE_VALUE, ATTS, PAGE_READ_WRITE, 0, 64, ShareMemoID)
ERROR_CODE = GetLastError()
If ERROR_CODE <> 0 Then
MsgBox "some error"
Exit Sub
End If
If m_handle = 0 Then
MsgBox "create share memory failed"
Else
BaseAddress = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
If GetLastError() <> 0 Then
MsgBox "some error"
Exit Sub
End If
End If
Timer1.Enabled = True
Timer1.Interval = 500
Text1.Text = ""
End Sub
Private Sub Command2_Click()
Timer1.Enabled = False
End Sub
Private Sub Command3_Click()
Dim s(31) As Byte
Dim i As Integer
Message = InputBox("message")
If Len(Message) = 0 Then
MsgBox "input is not valid"
Exit Sub
End If
For i = 0 To Len(Message) - 1
s(i) = Asc(Mid(Message, i + 1, 1))
Next
CopyMemory ByVal BaseAddress, s(0), 32
End Sub
Private Sub Command4_Click()
Form1.Caption = "client"
If ShareMemoID = "" Then
ShareMemoID = "ShareMemoTest"
End If
ShareMemoID = InputBox("Input ShareMemoryID", "ShareMemoryID", ShareMemoID)
If ShareMemoID = "" Then
MsgBox "share memory id can't be null string"
Exit Sub
End If
m_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, ShareMemoID)
If GetLastError() <> 0 Then
MsgBox "some error"
End If
If m_handle = 0 Then
MsgBox "open share memory failed"
Timer1.Enabled = False
Else
BaseAddress = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
'MsgBox "m_handle=" & m_handle & " Server_map=" & Server_map
If GetLastError() <> 0 Then
MsgBox "some error"
Exit Sub
End If
If BaseAddress = 0 Then
MsgBox "BaseAddress can't get"
Exit Sub
End If
Timer1.Enabled = True
Timer1.Interval = 500
Text1.Text = ""
End If
End Sub
Private Sub Form_Load()
Message = ""
Form1.Caption = "Not connected"
End Sub
Private Sub Form_Unload(Cancel As Integer)
Timer1.Enabled = False
If BaseAddress <> 0 Then
UnmapViewOfFile BaseAddress
End If
If m_handle <> 0 Then
CloseHandle m_handle
End If
End Sub
Private Sub Timer1_Timer()
Dim m(31) As Byte
Dim i As Integer
Dim msg As String
Text1.Text = ShareMemoID & " : " & BaseAddress
CopyMemory m(0), ByVal BaseAddress, 32
For i = 0 To 31
msg = msg & Chr(m(i))
Next
Text1.Text = Text1.Text & vbNewLine & msg
End Sub
==================================================
code in form1.frm complete
用了這個方法,不同的 process 就可以共用一個 memory 區域,達到 share memory 的功能。
要 share memory ,其步驟是
1 CreateFileMapping, 請求開啟一個區域,並且給該區域一個名字。之後,可以得到該區域的 handle,
2 MapViewOfFile, 要對已開啟的區域做動作,必須要建立一個 view 才行。之後,會得到 memory 的 address。
3 讀寫 view,在VB裡,可以使用 copy memory 來做讀寫的動作
4 UnmapViewOfFile 把 view 給關起來。當程式要結束的時候該做的事。
5 CloseHandle 把 FileMapping 給釋放掉,也是當程式結束,或不需要 share memory 的時候該做的事。免得系統的memory被吃光了也找不到兇手。
按照 MSDN 的介紹,寫了一個程式,可以CreateFileMapping,也可以OpenFileMapping。
我定義,執行 CreateFileMapping 那一個叫做 Server,執行OpenFileMapping 的叫做 Client。
當程式執行之後,可以執行兩次,就會有兩個程式。
兩個都可以當 Server (CreateFileMapping),而且名字可以一樣,這樣就可以溝通了。
當然也可以一個當 Server,一個當 Client。可以兩個都當 Server 的原因,我推測是因為只 share memory 的關係。
Share file 可能就不可以兩個都當 server。這個就不去實驗了,因為目前只關心 share memory。
同時兩個程式以上溝通也可以。只要多開幾次程式,而且有一個人當 Server 即可。感覺很方便。
這個程式只 share 32 byte 的 memory,所以只能傳遞比這個小的 message。
若是想要實作一個新的 protocol 來傳遞大 message 也行。
這個樣子的特性,讓我想到電路傳輸的特性,應該可以用來模擬CDMA, TDMA, 網路上的 CSMA/CA, CSMA/CD 的行為。
也可以用來模擬SECS I 或 HSMS 的傳送,對於學習上有相當幫助。
但是更有幫助的,當然是在這一層上面,支援更高一點的 protocol,做異質轉換。
或是建立新的 protocol,為自己的程式量身打造一個小而快的溝通管道。
雖然這種方式,已經不是新聞了,也一定有一堆的研究,但是如此就可以讓位在同樣 server 的 EAP 有個免費、簡單的管道互相溝通。
接下來的工作,是設計一個新的 protocol 來研究通訊模式嗎?
還是當做 adapter 接收現有的 protocol 如 SECS2呢?
都是一個學習的方向。
還有,若是對於在 hub 內資料如何傳送有了解的話,就可以設計一個比較複雜的 protocol 以提供穩定的溝通環境。
當然,不是只有這個 file mapping 可以用而已,還有其他的方式,也需多了解。例如 platform independent 的方法,
或是跨電腦的溝通,也是將來應該要學習的方向。
[1] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/sharing_files_and_memory.asp
本文授權為 CC
code in Module1.bas
==================================================
Attribute VB_Name = "Module1"
Public Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" _
(ByVal hFile As Long, _
lpFileMappingAttributes As Any, _
ByVal flProtect As Long, _
ByVal dwMaximumSizeHigh As Long, _
ByVal dwMaximumSizeLow As Long, _
ByVal lpName As String) As Long
Public Const INVALID_HANDLE_VALUE As Long = -1
Public Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Public Const PAGE_READ_WRITE As Long = 4
'===========================================================================================
Public Declare Function MapViewOfFile Lib "kernel32" _
(ByVal hFileMappingObject As Long, _
ByVal dwDesiredAccess As Long, _
ByVal dwFileOffsetHigh As Long, _
ByVal dwFileOffsetLow As Long, _
ByVal dwNumberOfByteToMap As Long) As Long
Public Const FILE_MAP_ALL_ACCESS = 983071
'==========================================================================================
Public Declare Function UnmapViewOfFile Lib "kernel32" (lpBaseAddress As Any) As Long
'==========================================================================================
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pvDst As Any, pvSrc As Any, ByVal LengthInByte As Long)
'==========================================================================================
Public Declare Function GetLastError Lib "kernel32" () As Long
'==========================================================================================
Public Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" _
(ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal lpName As String) As Long
'==========================================================================================
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'==========================================================================================
Public Const ERROR_ALREADY_EXISTS = 183&
'==========================================================================================
'Public Const FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS
'Public Const SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE
'Public Const STANDARD_RIGHTS_REQUIRED = &HF0000
'Public Const SECTION_QUERY = &H1
'Public Const SECTION_MAP_WRITE = &H2
'Public Const SECTION_MAP_READ = &H4
'Public Const SECTION_MAP_EXECUTE = &H8
'Public Const SECTION_EXTEND_SIZE = &H10
==================================================
code in Module1.bas complete
code in form1.frm
==================================================
VERSION 5.00
Begin VB.Form Form1
Caption = "Server"
ClientHeight = 3090
ClientLeft = 60
ClientTop = 450
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 3090
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
Begin VB.CommandButton Command4
Caption = "Connect Share"
Height = 495
Left = 3480
TabIndex = 4
Top = 720
Width = 1095
End
Begin VB.CommandButton Command3
Caption = "change value"
Height = 495
Left = 3480
TabIndex = 3
Top = 1920
Width = 1095
End
Begin VB.TextBox Text1
Height = 1215
Left = 360
MultiLine = -1 'True
TabIndex = 2
Text = "Form1.frx":0000
Top = 360
Width = 2535
End
Begin VB.CommandButton Command2
Caption = "stop monitor"
Height = 495
Left = 3480
TabIndex = 1
Top = 1320
Width = 1095
End
Begin VB.Timer Timer1
Left = 1680
Top = 2160
End
Begin VB.CommandButton Command1
Caption = "Create Share"
Height = 495
Left = 3480
TabIndex = 0
Top = 120
Width = 1095
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Dim m_handle As Long
Dim BaseAddress As Long
Dim ShareMemoID As String
Private Sub Command1_Click()
Form1.Caption = "Server"
Dim ERROR_CODE As Long
Dim ATTS As SECURITY_ATTRIBUTES
If ShareMemoID = "" Then
ShareMemoID = "ShareMemoTest"
End If
ShareMemoID = InputBox("Input ShareMemoryID", "ShareMemoryID", ShareMemoID)
If ShareMemoID = "" Then
MsgBox "share memory id can't be null string"
Exit Sub
End If
m_handle = CreateFileMapping(INVALID_HANDLE_VALUE, ATTS, PAGE_READ_WRITE, 0, 64, ShareMemoID)
ERROR_CODE = GetLastError()
If ERROR_CODE <> 0 Then
MsgBox "some error"
Exit Sub
End If
If m_handle = 0 Then
MsgBox "create share memory failed"
Else
BaseAddress = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
If GetLastError() <> 0 Then
MsgBox "some error"
Exit Sub
End If
End If
Timer1.Enabled = True
Timer1.Interval = 500
Text1.Text = ""
End Sub
Private Sub Command2_Click()
Timer1.Enabled = False
End Sub
Private Sub Command3_Click()
Dim s(31) As Byte
Dim i As Integer
Message = InputBox("message")
If Len(Message) = 0 Then
MsgBox "input is not valid"
Exit Sub
End If
For i = 0 To Len(Message) - 1
s(i) = Asc(Mid(Message, i + 1, 1))
Next
CopyMemory ByVal BaseAddress, s(0), 32
End Sub
Private Sub Command4_Click()
Form1.Caption = "client"
If ShareMemoID = "" Then
ShareMemoID = "ShareMemoTest"
End If
ShareMemoID = InputBox("Input ShareMemoryID", "ShareMemoryID", ShareMemoID)
If ShareMemoID = "" Then
MsgBox "share memory id can't be null string"
Exit Sub
End If
m_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, ShareMemoID)
If GetLastError() <> 0 Then
MsgBox "some error"
End If
If m_handle = 0 Then
MsgBox "open share memory failed"
Timer1.Enabled = False
Else
BaseAddress = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
'MsgBox "m_handle=" & m_handle & " Server_map=" & Server_map
If GetLastError() <> 0 Then
MsgBox "some error"
Exit Sub
End If
If BaseAddress = 0 Then
MsgBox "BaseAddress can't get"
Exit Sub
End If
Timer1.Enabled = True
Timer1.Interval = 500
Text1.Text = ""
End If
End Sub
Private Sub Form_Load()
Message = ""
Form1.Caption = "Not connected"
End Sub
Private Sub Form_Unload(Cancel As Integer)
Timer1.Enabled = False
If BaseAddress <> 0 Then
UnmapViewOfFile BaseAddress
End If
If m_handle <> 0 Then
CloseHandle m_handle
End If
End Sub
Private Sub Timer1_Timer()
Dim m(31) As Byte
Dim i As Integer
Dim msg As String
Text1.Text = ShareMemoID & " : " & BaseAddress
CopyMemory m(0), ByVal BaseAddress, 32
For i = 0 To 31
msg = msg & Chr(m(i))
Next
Text1.Text = Text1.Text & vbNewLine & msg
End Sub
==================================================
code in form1.frm complete
全站熱搜