• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    在VB中用文件映射來進行進程通訊

    發布: 2007-7-14 20:28 | 作者: 佚名    | 來源: 網絡轉載     | 查看: 1899次 | 進入軟件測試論壇討論

    領測軟件測試網
    四川行政財貿管理干部學院計算機管理系 卿 靜

    當我們用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。
    三. 函數描述
    在Module1.bas中用到幾個與文件映射有關的API函數,分述如下:
    1.CreateFileMapping:創建文件映射對象
    參數:
    hFile:Long——欲在其中創建映射的一個已經打開的磁盤文件句柄;
    LpFileMappingAttributes:Long——通常用0表示使用默認安全對象;
    FlProtect:Long——打開映射的方式(用API常數表示的讀/寫或其它);
    DwMaximumSizeHigh,dwMaximumSizeLow:Long——共同表示文件映射的最大長度(前者為高32位,后者為低32位),通常均設為0表示磁盤文件的實際長度;
    LpName: String——指定文件映射對象的名稱。
    返回值:Long——新建文件映射對象的句柄。
    2.OpenFileMapping:打開一個現成的文件映射對象
    參數:
    dwDesiredAccess:Long——用API常數表示的對文件映射的訪問方式;
    bInheritHandle:Long——返回值對與子進程的繼承屬性,常設為False;
    lpName:String——準備打開的文件映射對象的名稱。
    返回值:Long——指定的文件映射對象的句柄。
    3.MapViewOfFile:將一個文件映射對象映射到當前應用程序空間
    參數:
    hFileMappingObject:Long——文件映射對象的句柄;
    dwDesiredAccess:Long——用API常數表示的對文件映射的訪問方式;
    dwFileOffsetHigh,dwFileOffsetLow:Long——共同表示文件中的映射起點(前者為高32位,后者為低32位),通常均設為0表示從文件的起始處開始映射;
    dwNumberOfBytesToMap:Long——要映射的字節數,通常設為0表示映射整個文件映射對象。
    返回值:Long——文件映射在內存中的起始地址。
    4.UnmapViewOfFile:解除當前應用程序中的一個文件映射對象的映射地址空間
    參數:
    lpBaseAddress:要解除映射的文件映射起始地址。
    返回值:Long——非零表示成功,零表示失敗。
    Sampling.vbp的啟動窗體Form1.frm在裝載時創建一個文件映射(CreateMap),這個創建過程分三步:首先,通過CreateFile,WriteFile,FlushFileBuffers建立一個具有指定長度(LenBuffer + 1)的磁盤文件DiskFileName;然后,由CreateFileMapping創建一個對應于磁盤文件DiskFileName的文件映射對象MapFileName;最后,用MapViewOfFile將文件映射對象映射到應用程序地址MapAddress。在本例中,磁盤文件建立后便不再與之打交道,以后的操作均針對其映射地址空間。
    采樣通過觸發定時器Timer1周期性的進行(采樣周期Pub_Period)。每次采樣首先通過GetV取得原始樣本并放入數組v(本例的樣本用隨機數替代,實際應用中是從RS232或其他設備取得),然后將其存入映射地址空間以便“管理程序”取用。樣本在映射地址空間的存放形式為:“x 采樣時間 樣本值1 樣本值2”。其中x是一個標記,當它為空格時表示新樣本,為“*”時表示已取用。 為了方便程序處理,設置了一個樣本緩沖strBuffer,由它與映射地址空間交換數據,CopyToMap和GetFromMap也是用于這個目的,CopyToMap(S)是復制S到映射地址空間,而GetFromMap(S)是從映射地址空間取值送到S。
    在“采樣程序”運行過程中,“管理程序”由于某種原因(如維護程序)可能長時間不取用樣本(超過一個采樣周期),這時,“采樣程序”應當把樣本存放到另外的磁盤文件,以免丟失樣本?紤]到本文主題和文章篇幅,本例未做處理。
    Manage.vbp啟動窗體Form1.frm很簡單,僅僅從演示的角度將映射地址空間的數據取出并顯示。
    試驗時先運行“采樣”, 再運行“管理”,觀察兩個窗體中的樣本數據,我們會發現他們幾乎是同步的。感謝文件映射!

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備2023014753號-2
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>