top
Loading...
遠程共享顯示及聲音的實現

在局域網內共享調制解調器以及共享打印機都是我們非常熟悉的,而對于顯示器和聲卡的共享一般比較陌生。

當你在進行教學、演示或展示時,也許你希望主控電腦上的畫面同時也出現在其它電腦上;當你在跟蹤調試程序時,你也許夢想過兩臺顯示器能夠同步,以便觀看源代碼時不破壞運行程序畫面;還有,出于管理的目的,或許你需要遠程監控其它電腦的運行狀況,等等。上述所有情況都是遠程共享顯示的例子。

共享聲卡的需求也不少:首先這可以降低硬件投資,讓沒有裝或者沒法裝聲卡的電腦(如某些筆記本電腦)也有了“喉舌”;其次,即使每臺機器都有聲卡也不無用武之地:至少你的 mp3背景音樂與你的英語有聲軟件不再經常發生沖突了;還有,共享聲卡使得“遠程有聲通知”成為可能,其作用類似于立即型聲音郵件,在日常工作中有廣泛的應用。

共享顯示器或聲卡的硬件(一般在擴展槽內插一塊卡)在市場上不難找到。但擴充本文的示例程序即可以用軟件輕松實現這些功能。

一、共享顯示

我們通過一個完整的示例程序(VB 6.0)來說明。在例子中,被共享端(即服務器端)的任務是:自動捕獲本機的當前顯示畫面,并將之傳給共享端(即客戶端)。

1. 服務器端程序(frmServer.frm)

這里有三點需要重點說明:一是自動捕獲畫面問題。為了模擬“捕獲屏幕鍵”被按下的動作,程序里使用了 API調用 keybd_event。雖然VB的SendKeys語句也有類似功能,但它不如 keybd_event穩定和可靠。二是畫面粘貼和壓縮存儲問題。為了能把已經被捕獲到系統剪貼板中的圖像粘貼下來并存儲到文件,程序里使用了 ImgEdit控件。該控件強大的功能遠非PictureBox控件或 Image控件可比。ImgEdit 不僅支持多種壓縮圖像格式(如 JPG、TIFF等),而且它對畫面進行操縱和編輯的功能也非常強大(如圖像旋轉、縮放、嵌入等)。ImgEdit 還能對剪貼板進行Copy、Cut、Paste等操作。使用 Ctrl+T 或菜單(工程->部件)來添加 Windows標準的 ImgEdit控件(參見圖一)。三是文件傳輸問題。用 ImgEdit存儲的壓縮文件一般只有 40 KB左右,使用 Winsock控件可以一次傳輸出去。但由于接收方的 Winsock控件一般是4K至8K調用一次 DataArrival子程,故程序使用主動分塊進行傳輸,接收方確認后再發下一塊。



服務器端源程序如下:

'====================== frmServer.frm

Option Explicit
Const FileName = "C:sys1.tmp", BlockSize = 3072 ' 傳送包大小
Private Declare Sub keybd_event Lib "user32" _
(ByVal bVk As Byte, ByVal bScan As Byte, _
ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

Private Sub Form_Load()
tcpServer.LocalPort = 1001 ' 設置監聽端口號
tcpServer.Listen ' 開始監聽
End Sub

Private Sub tcpServer_ConnectionRequest(ByVal requestID As Long)
If tcpServer.State <> sckClosed Then tcpServer.Close
tcpServer.Accept requestID
tcpServer.SendData "SH" ' 成功連接后,發送“握手”信息
End Sub

Private Sub tcpServer_DataArrival(ByVal bytesTotal As Long)
Static FileID As Integer, Cur_Pos As Long, FileLen As Long
Dim strData As String, j
Dim Buf() As Byte ' 定義一個可變大小的數組,用于傳送二進制圖像包
tcpServer.GetData strData
Select Case strData
Case "Close" ' 接到“Disconnect”命令后,關閉當前連接,并繼續監聽
tcpServer.Close
ImgEdit1.ClearDisplay
tcpServer.LocalPort = 1001
tcpServer.Listen
Case "Save Picture"
Call keybd_event(vbKeySnapshot, 1, 0, 0) ' 模擬按鍵操作
j = DoEvents()
If Dir$(FileName) <> "" Then Kill FileName
If ImgEdit1.IsClipboardDataAvailable Then ' 當剪貼板上有數據時
ImgEdit1.ClearDisplay
ImgEdit1.DisplayBlankImage Screen.Width / _
Screen.TwipsPerPixelX, Screen.Height / _
Screen.TwipsPerPixelY, , , 6
ImgEdit1.ClipboardPaste ' 從剪貼板粘貼圖像
ImgEdit1.BurnInAnnotations 0, 2
ImgEdit1.SaveAs FileName, 1, 6, 6, 256 ' 另存圖像。參數說明如下:
' “FileName”:文件名
' 參數“1”:TIFF 型文件;
' 第一個“6”:RGB24類型;
' 第二個“6”:JPEG壓縮類型
' 參數“256”:最大壓縮比
Clipboard.Clear
tcpServer.SendData "PS" ' 發送“圖像文件就緒”信息
End If
Case "Get Picture"
If Dir$(FileName) <> "" Then
FileID = FreeFile
Open FileName For Binary As #FileID ' 打開文件并發送第一塊數據
FileLen = LOF(FileID)
ReDim Buf(1 To BlockSize) As Byte
Get #FileID, , Buf
tcpServer.SendData Buf
Cur_Pos = BlockSize
End If
Case "Next Block"
If Cur_Pos = FileLen Then
tcpServer.SendData "EF" ' 文件傳送完畢后,發送“完成”信息
Close FileID
Exit Sub
End If
j = Cur_Pos + BlockSize
If j > FileLen Then
j = FileLen - Cur_Pos
Else
j = BlockSize
End If
ReDim Buf(1 To j) As Byte ' 動態確定數組大小
Get #FileID, , Buf
tcpServer.SendData Buf ' 發送后續包
Cur_Pos = Cur_Pos + j
End Select
End Sub

2. 客戶端程序(frmClient.frm)

在窗體上建六個控件:一個名為 tcpClient的 Winsock控件用于通訊;一個名為txtIP 的 TextBox控件用于填寫服務器的IP地址;一個名為ImgEdit1的 ImgEdit控件用于顯示服務器傳來的圖像;三個CommandButton控件( cmdConnect、cmdGet_Pic和cmdDisconnect) 分別用于執行連接、取回圖像和斷開連接(見圖二)。



客戶端源代碼如下:

'====================== frmClient.frm

Option Explicit
Const FileName = "C:sys1.tmp"
Private Sub cmdConnect_Click()
If tcpClient.State <> sckClosed Then tcpClient.Close
tcpClient.RemoteHost = txtIP.Text
tcpClient.RemotePort = 1001
tcpClient.Connect ' 進行連接
End Sub

Private Sub cmdDisconnect_Click()
tcpClient.SendData "Close" ' 斷開連接
cmdConnect.Enabled = True
cmdGet_Pic.Enabled = False
cmdDisconnect.Enabled = False
End Sub

Private Sub cmdGet_Pic_Click()
tcpClient.SendData "Save Picture" ' 請求圖像返回
frmClient.MousePointer = 11
End Sub

Private Sub Form_Resize() ' 使 ImgEdit1 的大小隨窗體的變化而變化
ImgEdit1.Height = frmClient.Height - 825
ImgEdit1.Width = frmClient.Width - 225
End Sub

Private Sub tcpClient_DataArrival(ByVal bytesTotal As Long)
Static FileID As Integer, FileLen As Long
Dim Buf() As Byte
Dim j As Integer
ReDim Buf(bytesTotal) As Byte ' 根據到達數據的字節數確定接收數組的大小
tcpClient.GetData Buf
' 收到連接完成的“握手”信息
If bytesTotal = 2 And Chr(Buf(0)) = "S" And Chr(Buf(1)) = "H" Then
cmdConnect.Enabled = False
cmdGet_Pic.Enabled = True
cmdDisconnect.Enabled = True
Exit Sub
End If
' 收到圖像就緒的信息
If bytesTotal = 2 And Chr(Buf(0)) = "P" And Chr(Buf(1)) = "S" Then
If Dir$(FileName) <> "" Then Kill FileName
FileID = FreeFile
Open FileName For Binary As #FileID ' 打開文件,準備存儲圖像
FileLen = 0
tcpClient.SendData "Get Picture"
Exit Sub
End If
' 收到圖像發送完畢的信息
If bytesTotal = 2 And Chr(Buf(0)) = "E" And Chr(Buf(1)) = "F" Then
Close #FileID ' 關閉文件
j = DoEvents()
ImgEdit1.Image = FileName
ImgEdit1.Display ' 顯示收到的圖像
ImgEdit1.BurnInAnnotations 0, 2
frmClient.MousePointer = 0
Exit Sub
End If
' 收到一塊二進制圖像信息
Put #FileID, , Buf ' 將當前數據塊存盤
tcpClient.SendData "Next Block" ' 申請下一塊
FileLen = FileLen + bytesTotal
frmClient.Caption = "TCP Client " + Trim(Str(FileLen)) + _
" Bytes Received." ' 顯示當前收到的字節數
End Sub

客戶端成功共享服務器端顯示畫面后的外觀如圖三所示。




二、共享聲音

共享聲音與共享顯示的思想是一致的,只是這時是客戶端向服務器端發送聲音文件,以便共享服務器的聲卡。服務器端應使用微軟的多媒體控件(MMControl) 進行聲音播放(使用 Ctrl+T 或菜單“工程->部件”來添加)。用該控件播放聲音不僅是簡單的,而且功能強大。

由于關鍵模塊與共享顯示一致,故此處略去源代碼。

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗