在Excel中使用WinSock控件远程通信
贵州大学计算机软件与理论研究所 李 元
本文讨论在Excel 电子表格里使用对WinSock 控件的VBA 编程,实现电子表格数据在Internet 网络上远程通信。具体地说,我们要求在Internet 网络上的两个Excel 用户的工作簿启动后,能够连接起来,既可互相将自己工作表单元里已有的数据传送给对方,也可将在表单文字框里现场输入的数据传送给对方,而且无论哪方都可将接收到的数据传到工作表指定的单元里保存下来。这样,用Excel 不仅实现了工作表数据在Internet 网络上传输的功能,同时也达到了用Excel 实现一个“聊天室”的目的。
为实现上述要求,可在Excel 中使用微软的WinSock 控件,用UDP 协议(无连接的通讯协议)或TCP 协议进行。下面叙述用UDP 进行的具体做法。
一、工作簿:Book_A.XLS
1. 设计工作簿Book_A.XLS 的表单
运行Excel,将工作簿用Book_A 存盘,选“工具| 宏| Visual Basic 编辑器”,在出现的Visual Basic 编辑器窗口里选菜单“插入| 添加用户窗体”,鼠标右击窗体选“属性”在左面的窗体属性栏里对窗体做一些设置,例如:设置窗体的名称为:frmA (缺省名为UserForm1),窗体标题(缺省名为Caption):Caption="A 聊天室”等。
设置信息输入输出文本框:从工具箱里将下列控件放到窗体上:两个文字框:TextBox1(用来输入要发送的字符串)、TextBox2(用来接受对方发送来的字符串);再放三个命令按钮:CommandButton1(用来执行发送文本框TextBox1 里的数据的过程)、CommandButton2(用来执行发送工作表Sheet1 单元Cells(1,1) 的数据的过程)、CommandButton3(用来将在TextBox2 里接收到的数据传到工作表Sheet1 里的单元Cells(3,1) 里保存的过程)。
在窗口中添加WINSOCK 控件:选菜单的“工具| 附加控件”,选“Microsoft Winsock Cotrol"(在Win98 中是6.0 版,在\windows\sytem 下的mswinsck.ocx),这时,该控件的图标已在工具箱里出现,将它放入窗体中后,左面出现“Winsock1 Winsock"属性栏窗口,这里Winsock1 是该控件的缺省名(用于编写代码),可在该属性栏里进行下面的设置,也可如下用代码进行设置。
2. 对工作簿Book_A.XLS 的表单进行VBA 编程
Private Sub CommandButton1_Click()
' 发送用户在文字框TextBox1 里的数据
Winsock1.SendData TextBox1.Text
End Sub
Private Sub CommandButton2_Click()
' 发送用户工作表指定单元里的数据
Winsock1.SendData Cells(1, 1).Value
End Sub
Private Sub CommandButton3_Click()
' 将接收的数据保存在单元Cells(3,1) 里
Cells(3, 1).Value = "接收的数据:" +TextBox2.Text
' 将积分结果保存在当前的活动单元里
ActiveCell.Value = "接收的数据:" +TextBox2.Text
End Sub
Private Sub TextBox1_Change()
' 发送用户输入
'Winsock1.SendData TextBox1.Text
End Sub
'
Private Sub UserForm_Initialize()
Winsock1.Protocol = 1
'winsock 通讯协议设为UDP 协议1, TCP:0
' 设置网络地址
Winsock1.LocalPort = 1999
'Winsock1.RemoteHost = "210.40.7.168"
Winsock1.RemoteHost = "Localhost" ' 在本机测试
Winsock1.RemotePort = 1024
End Sub
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim rec As String
' 接收对方数据并在Text2 中显示
Winsock1.GetData rec, vbString
TextBox2.Text = rec
End Sub
最后,为使调用工作簿Bokk_A.XLS 时即运行表单,打开窗口:双击“工程——VBAProject"栏里的“ThisWorkBook",出现代码窗口,在Worksheet_Activate 事件里录入下列代码(这个过程实现当打开工作簿时,首先显示名为frmDemo 的窗体):
Private Sub Workbook_Activate()
frmA.Show
End Sub
二、工作簿:Book_B.XLS
另一方的工作簿Book_B.XLS 的做法与工作簿Book_A.XLS 几乎完全一样,不同的是在表单的初始化事件里对网络通信的远程主机和端口设置:
Private Sub UserForm_Initialize()
' 设置网络协议
Winsock1.Protocol = 1
'winsock 通讯协议设为UDP 协议1, TCP:0
' 设置网络地址
Winsock1.LocalPort = 1024 ' 本地端口
'Winsock1.RemoteHost = "210.40.7.188" ' 远程主机
Winsock1.RemoteHost = "Localhost" ' 远程主机
Winsock1.RemotePort = 1999 ' 远程端口
End Sub
本文设计在Win98/Excel97/2000 下通过,下面是运行情况(A 接收B 的数据)。
如果系统没有Winsock控件的话,可以下载下面的控件MSWINSCK.OCX,然后将该文件复制到C:\Windows\System32目录下。
在VBE窗口中,从菜单“工具”->“引用”中,点击“浏览”按钮,选择MSWinSCK.ocx文件,再从“工具箱”的“附加控件”中选择Microsoft Winsock Control。
此时使用Winsock控件的话,将会出现提示不安全的ActiveX控件的提示。可以点击同时下载的REG文件注册该控件即可。
一般在Excel的窗体中添加Winsock控件。
使用Winsock控件的应用程序一般是Client/Server结构,也就是客户端/服务器端。
以服务端为例,一般的步骤是:
先设置LocalPort本地端口,然后使用Listen方法侦听数据请求。然后处理ConnectionRequest和DataArrival事件。使用完后使用Close方法关闭连接。
Private Sub UserForm_Initialize()
Winsock1.LocalPort = 1999
Winsock1.Listen
End Sub
Private Sub UserForm_Terminate()
Winsock1.Close
End Sub
Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
If Winsock1.State <> sckClosed Then Winsock1.Close
Winsock1.Accept requestID
End Sub
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim Buffer() As Byte
TransferedBytes = TransferedBytes + bytesTotal
ReDim Buffer(bytesTotal - 1)
Winsock1.GetData Buffer, vbArray + vbByte
End Sub
Private Sub Winsock1_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
Debug.Print "Sock Err:" & Description
End Sub
而客户端的一般步骤如下:
设置远程服务器端口RemotePort属性,然后使用Connect方法连接。处理ConnectionRequest和DataArrival事件。发送数据就直接使用Send方法就可以了,可以发送字符串或者Byte数组。
Private Sub UserForm_Initialize()
Winsock1.RemoteHost = "127.0.0.1"
Winsock1.RemotePort = 2999
Winsock1.Connect
End Sub
Private Sub UserForm_Terminate()
Winsock1.Close
End Sub
Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
If Winsock1.State <> sckClosed Then Winsock1.Close
Winsock1.Accept requestID
End Sub
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim strData As String
Winsock1.GetData strData, vbString
If strData = "OK" Then
Winsock1.Close
Winsock1.RemotePort = 1999
Winsock1.Connect
MsgBox "You can send file now"
End If
End Sub