当我们用VB开发应用系统时,可能涉及多进程问题。比如工业上应用较多的数据采集系统,也许就需要两个进程,一个是“采样程序”,另一个是“管理程序”,“采样程序”做单一的采集样本工作,而“管理程序”则对样本进行分析,存储,输出各种图表等等。为了便于维护,“采样程序”与“管理程序”各自作为独立的应用程序而运行,那么“管理程序”怎样才能取得“采样程序”所采集的数据呢?这就是所谓进程间的通信问题。 在多个应用程序之间交换数据,我们自然会想到磁盘文件,但这种方法在实时系统中是不宜采用的,因为读写磁盘文件的时间效率往往不能满足实时要求。幸运的是,Windows提供了几种高效的进程间交换数据的机制,如管道,邮路和文件映射。以下我们只针对文件映射进行讨论。 一. 文件映射概念 所谓文件映射,简单地说,就是将磁盘文件(或部分)映射到某段内存空间,对磁盘文件的访问转变成对内存的访问,显然,这大大提高了访问速度。 实际的映射过程是通过几个API函数来实现的,首先需要创建一个“文件映射对象”,而这个对象是共享的,各个进程可将对象映射到自己的内存地址空间,各进程的映射地址不一定相同,但地址中的内容却一定是相同的,各进程对各自的映射地址的访问都归结为对“文件映射对象”的访问。 如上所言,我们可以认为“文件映射”是将文件映射到内存供各进程共享。那我们何不直接开辟一块全局内存来共享呢?这在32位Windows中是行不通的,因为全局内存在32位Windows中不是多进程共享的对象。因此,文件映射在进程间通信中扮演了重要的角色。 二. 示例 我们姑且把这个示例叫做“数据采集系统”,它由两个工程组成:Sampling.vbp(采样)和Manage.vbp(管理)。 Sampling.vbp包含两个文件:Form1.frm,Module1.bas。清单如下: Form1.frm: VERSION 5.00 Begin VB.Form Form1 Caption = "Sampling" ClientHeight = 1440 ClientLeft = 48 ClientTop = 288 ClientWidth = 4416 LinkTopic = "Form1" ScaleHeight = 1440 ScaleWidth = 4416 StartUpPosition = 3 '窗口缺省 Begin VB.CommandButton cmdStop Caption = "Stop" Enabled = 0 'False Height = 372 Left = 2160 TabIndex = 2 Top = 360 Width = 972 End Begin VB.CommandButton cmdStart Caption = "Start" Height = 372 Left = 840 TabIndex = 1 Top = 360 Width = 972 End Begin VB.TextBox Text1 Height = 372 Left = 120 TabIndex = 0 Text = "Text1" Top = 840 Width = 4092 End Begin VB.Timer Timer1 Enabled = 0 'False Interval = 60 Left = 0 Top = 0 End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Option Explicit
Private Sub cmdStart_Click() Pub_Timer1Run = False Pub_LastTime = Timer() Timer1.Enabled = True cmdStart.Enabled = False cmdStop.Enabled = True End Sub
Private Sub cmdStop_Click() Timer1.Enabled = False cmdStart.Enabled = True cmdStop.Enabled = False End Sub
Private Sub Form_Load() Call CreateMap End Sub
Private Sub Form_Unload(Cancel As Integer) Call CloseMap End Sub
Private Sub Timer1_Timer() Static tm As Single, Dlt As Single Static i As Integer Static dtNow As Date Static S As String Static v(1 To Pub_LoopN) As Single
If Pub_Timer1Run Then Exit Sub Pub_Timer1Run = True
tm = Timer(): dtNow = Now() Dlt = tm - Pub_LastTime If Sgn(Dlt) = -1 Then '两次时间跨午夜0点 Dlt = Dlt + 86400! '86400 = 24 * 3600 End If
Do While Dlt >= Pub_Period Pub_LastTime = tm Call GetV(v()) Call GetFromMap(strBuffer) If Left(strBuffer, 1) = "*" Then S = " " & Format(dtNow, Pub_FormatDT) For i = 1 To Pub_LoopN S = S & " " & Format(v(i), Pub_FormatV) Next i strBuffer = S: Call CopyToMap(strBuffer) Text1.Text = S Else 'Add to File End If 'Left(strBuffer, 1) = "*" Exit Do Loop
Pub_Timer1Run = False End Sub 'Timer1_Timer
Private Sub GetV(v() As Single) Const MaxV = 4000! Dim i As Integer
Randomize For i = 1 To Pub_LoopN v(i) = CSng(MaxV * Rnd) Next i End Sub 'GetV
Module1.bas: Attribute VB_Name = "Module1" Option Explicit #Const Sampling = True '编译常数Sampling=Ture:采样, =False:管理 Public DiskFileName As String '实时样本磁盘文件名 Public MapFileName As String '前者的(内存)映射文件名 Public FileHandle As Long '磁盘文件句柄 Public MapHandle As Long '映射文件句柄 Public MapAddress As Long '映射地址 Public strBuffer As String '实时样本缓冲 Public LenBuffer As Long '缓冲区长度
Public Const Pub_LoopN = 2 '通道数目 Public Const Pub_FormatDT = "yyyy-mm-dd hh:mm:ss" '日期/时间格式 Public Const Pub_FormatV = "0000.000" '样本数据格式 Public Pub_LenDT As Long '日期/时间宽度 Public Pub_LenV As Long '样本数据宽度
Public Const Pub_Period = 2! '采样周期(秒) Public Pub_LastTime As Single '上次采样时间 Public Pub_Timer1Run As Boolean '中断例程在运行标志
Public Const FILE_MAP_WRITE = &H2 Public Const FILE_MAP_READ = &H4 Public Const PAGE_READWRITE = 4& Public Const GENERIC_READ = &H80000000 Public Const GENERIC_WRITE = &H40000000 Public Const CREATE_ALWAYS = 2 Public Const FILE_SHARE_READ = &H1 Public Const FILE_SHARE_WRITE = &H2 Public Const FILE_ATTRIBUTE_NORMAL = &H80
Declare Function lstrcpyn Lib "kernel32" Alias "lstrcpynA" _ (DesStr As Any, _ SrcStr As Any, _ ByVal MaxLen As Long) As Long Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long #If Sampling Then Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _ (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) As Long Declare Function WriteFile Lib "kernel32" _ (ByVal hFile As Long, _ lpBuffer As Any, _ ByVal nNumberOfBytesToWrite As Long, _ lpNumberOfBytesWritten As Long, _ ByVal lpOverlapped As Long) As Long Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long #End If #If Sampling Then Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" _ (ByVal hFile As Long, _ ByVal lpFileMappingAttributes As Long, _ ByVal flProtect As Long, _ ByVal dwMaximumSizeHigh As Long, _ ByVal dwMaximumSizeLow As Long, _ ByVal lpName As String) As Long #Else Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" _ (ByVal dwDesiredAccess As Long, _ ByVal bInheritHandle As Long, _ ByVal lpName As String) As Long #End If 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 Declare Function UnmapViewOfFile Lib "kernel32" _ (lpBaseAddress As Any) As Long ' Public Sub InitVar() DiskFileName = "D:/Article/Mapping/Sample" MapFileName = DiskFileName & "Map" Pub_LenDT = Len(Pub_FormatDT) Pub_LenV = Len(Pub_FormatV) LenBuffer = 1 + Pub_LenDT + (Pub_LenV + 1) * Pub_LoopN strBuffer = String(LenBuffer + 1, "*") FileHandle = 0 MapHandle = 0 MapAddress = 0 End Sub 'InitVar
Public Sub CopyToMap(S As String) If MapAddress <> 0 Then Call lstrcpyn(ByVal MapAddress, ByVal S, LenBuffer + 1) End If End Sub
Public Sub GetFromMap(S As String) If MapAddress <> 0 Then Call lstrcpyn(ByVal S, ByVal MapAddress, LenBuffer + 1) End If End Sub
Public Sub CloseMap() If MapAddress <> 0 Then Call UnmapViewOfFile(ByVal MapAddress) MapAddress = 0 End If If MapHandle <> 0 Then Call CloseHandle(MapHandle) MapHandle = 0 End If If FileHandle <> 0 Then Call CloseHandle(FileHandle) FileHandle = 0 End If End Sub 'CloseMap
#If Sampling Then
Public Sub CreateMap() Dim w As Long
Call InitVar FileHandle = CreateFile(DiskFileName, _ GENERIC_WRITE Or GENERIC_READ, _ FILE_SHARE_READ Or FILE_SHARE_WRITE, _ 0, _ CREATE_ALWAYS, _ FILE_ATTRIBUTE_NORMAL, _ 0) Call WriteFile(FileHandle, ByVal strBuffer, LenBuffer + 1, w, 0) Call FlushFileBuffers(FileHandle)
MapHandle = CreateFileMapping(FileHandle, _ 0, _ PAGE_READWRITE, _ 0, _ 0, _ MapFileName) MapAddress = MapViewOfFile(MapHandle, FILE_MAP_WRITE, 0, 0, 0) End Sub 'CreateMap
#Else
Public Function OpenMap() As Long Call InitVar OpenMap = 0 MapHandle = OpenFileMapping(FILE_MAP_WRITE, False, MapFileName) If MapHandle = 0 Then Exit Function MapAddress = MapViewOfFile(MapHandle, FILE_MAP_WRITE, 0, 0, 0) If MapAddress = 0 Then Call CloseHandle(MapHandle) MapHandle = 0 End If OpenMap = MapAddress End Function 'OpenMap
#End If 'Sampling
Manage.vbp也包含两个文件:Form1.frm,Module1.bas。清单如下: Form1.frm: VERSION 5.00 Begin VB.Form Form1 Caption = "Manage" ClientHeight = 1440 ClientLeft = 48 ClientTop = 288 ClientWidth = 4416 LinkTopic = "Form1" ScaleHeight = 1440 ScaleWidth = 4416 StartUpPosition = 3 '窗口缺省 Begin VB.CommandButton cmdStart Caption = "Start" Height = 372 Left = 1560 TabIndex = 1 Top = 240 Width = 972 End Begin VB.TextBox Text1 Height = 372 Left = 120 TabIndex = 0 Text = "Text1" Top = 840 Width = 4092 End Begin VB.Timer Timer1 Enabled = 0 'False Interval = 60 Left = 0 Top = 0 End End Attribute VB_Name = "Form1" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False Option Explicit
Private Sub cmdStart_Click() If OpenMap() = 0 Then MsgBox "采样程序未运行!", vbOKOnly, "" Exit Sub End If
Pub_Timer1Run = False Timer1.Enabled = True cmdStart.Enabled = False End Sub
Private Sub Form_Unload(Cancel As Integer) Call CloseMap End Sub
Private Sub Timer1_Timer() Static tm As Single, Dlt As Single Static i As Integer Static dtNow As Date Static S As String Static v(1 To Pub_LoopN) As Single
If Pub_Timer1Run Then Exit Sub Pub_Timer1Run = True
Call GetFromMap(strBuffer) If Left(strBuffer, 1) = " " Then strBuffer = "*" & Mid(strBuffer, 2) Call CopyToMap(strBuffer) Text1.Text = strBuffer End If
Pub_Timer1Run = False End Sub 'Timer1_Timer
Module1.bas:与Sampling.vbp之Module1.bas几乎完全相同,只是其中编译常数Sampling= False。 <  
1/2 1 2 下一页 尾页 |