以前模仿大神在vs里使用c#实现RTD函数功能。(真是很生僻的东东啊)C#制作RTD参考:大神博客跳转。最近想VB里能不能做?就试着做了做,好像基本成了,整套代码有些毛病,勉强能算个样子,暂时不打算再细搞。

概念:什么是RTD函数(效果可先看下结尾的gif演示)

RTD函数是一种程序函数,用途从支持COM自动化的程序中返回实时数据(real-time data)。
语法:RTD(ProgID,server,topic1,[topic2],...)
参数:ProgID已安装在本地计算机中,经过注册的COM自动化加载宏的ProgID名称,该名称用引号引起来。Server是运行加载宏的服务器的名称
如果没有服务器,程序是在本地计算机上运行,那么该参数为空白
topic1,topic2,...为1到28个参数,这些参数放在一起代表一个唯一的实时数据。

猜测的图示,RTD函数和RTD服务和Excel三者之间互有关系?底层MyvbProj.rtdserver是我要做的RTD服务

实现的目标:制作RTD服务程序,从百度APIstore市场中获取股票信息,实时(real-time)刷新数据至excel中。

        API使用方法参考链接:http://apistore.baidu.com/apiworks/servicedetail/115.html

        API取得的数据是JSON,摘要如下(实际信息更多):

VB处理JSON的方法请参考我另一个博文:点击跳转

{
"errNum":0,
"errMsg":"success",
"retData":
{
"stockinfo":[
{
"name":"科大讯飞",
"code":"sz002230",
"OpenningPrice":31.59,
"closingPrice":31.4,
"currentPrice":30.92,
"hPrice":32.45,
"lPrice":30.28,
}]
}
}

方案准备:

一、使用VB6.0新建一个工程,类型选择ActiveX DLL,工程名称:MyvbProj

二、添加“Microsoft Excel 14.0 Object Library”的引用

三、分别新建四个类模块rtdserver、StockData、StockHelper和一个clsTimer

      前三个类代码下载请点击:点击下载

clsTimer类是个计时器功能的类,代码请参考博文:点击跳转到大神(说明:需要自己动手在类内部添加事件)

StockData类模块:实体类,用来记录数据。因百度api返回的json数据使用的是"name"、"code"等英文名称,所以用属性包装了一下。

     '该次请求的股票代码
Private Code As String
'该次请求的股票名称
Private Index As String
'该次请求Excel分配的TopicID
Public TopicID As Integer
'该次请求的返回值
Public Value As Variant Public Property Get StockCode() As Variant
If Left(Code, ) = Then
StockCode = "sh" & Code
Else
StockCode = "sz" & Code
End If
End Property Public Property Let StockCode(ByVal Value As Variant)
Code = Value
End Property Public Property Get StockIndex() As String
StockIndex = Index
End Property Public Property Let StockIndex(ByVal Value As String)
Select Case Value
Case "股票名称": Index = "name"
Case "股票代码": Index = "code"
Case "开盘价": Index = "OpenningPrice"
Case "收盘价": Index = "closingPrice"
Case "最新价": Index = "currentPrice"
Case "最高价": Index = "hPrice"
Case "最低价": Index = "lPrice"
Case Else: Index = "name"
End Select
End Property

StockHelper类模块:帮助类,用来具体向百度API拿取(get)数据。API的使用方法可参考网站说明。

向api请求数据需要使用apikey,测试时请替换成个人的apikey。

该类的主要工作是向api请求数据,把请求回来的值保存到StockData的Value属性中。

 Private url As String
Private list As String Private Sub Class_Initialize()
url = "http://apis.baidu.com/apistore/stockservice/stock?stockid="
list = "&list=2"
End Sub Private Function JsonText(stock As StockData) As String
Dim strurl As String
Set winhttp = CreateObject("WinHttp.WinHttpRequest.5.1")
strurl = url & stock.StockCode & list
winhttp.Open "GET", strurl, False
winhttp.setRequestHeader "apikey", "你的apikey"
winhttp.send
JsonText = winhttp.ResponseText
End Function Function QueryInfo(stock As StockData)
Set scobj = CreateObject("MSScriptControl.ScriptControl")
scobj.Language = "JavaScript"
scobj.AddCode ("var query = " & JsonText(stock))
scobj.AddCode ("var info =query.retData.stockinfo[0]")
scobj.Eval ("var value = info." & stock.StockIndex) stock.Value = scobj.Eval("value")
'非开盘时间,使用随机数模拟价格变化
' If stock.StockIndex = "name" Then
' stock.Value = scobj.Eval("value")
' Else
' stock.Value = scobj.Eval("value") + Format(Rnd * 10, "0.00")
' End If
End Function Function QueryInfos(stocks As Collection)
Dim temp As StockData
For Each s In stocks
Set temp = s
QueryInfo temp
Next s
End Function

rtdserver类模块:rtdserver实现rtd函数的主要功能,是本案的主要功能模块

(VB中工程名称+该类模块的类名即为rtd函数的ProgID,本案例中的ProgID="MyvbProj.rtdserver")

该类模块主要实现IRtdServer接口(Implements IRtdServer)。

该接口下有五个方法:

1、服务启动时做一些初始化。该方法的返回值为1时,表示服务启动
参数是IRTDUpdateEvent对象,该对象有一个UpdateNotify方法很重要。起到通知的作用,执行方法后,Excel会调用IRtdServer_RefreshData方法更新数据
Private Function IRtdServer_ServerStart(ByVal CallbackObject As IRTDUpdateEvent) As Long

2、rtd函数首次向服务请求数据时执行的方法。每一个请求会被分配一个TopicID(主题)
Stings()与rtd函数的参数topic1,[topic2]对应,每一个唯一的topic组合对应一个TopicID
GetNewValues,当它值为1时表示,每次工作簿打开都重新请求数据
该方法的返回值类型为Variant类型,就是主题首次请求得到的值(即rtd公式的结果)
Private Function IRtdServer_ConnectData(ByVal TopicID As Long, Strings() As Variant, GetNewValues As Boolean) As Variant

3、IRTDUpdateEvent对象调用本方法更新数据(更新主题的数据),即更新rtd公式的结果
Private Function IRtdServer_RefreshData(TopicCount As Long) As Variant() 4、删除某个主题会执行的方法,参数是被删除的主题的TopicID
Private Sub IRtdServer_DisconnectData(ByVal TopicID As Long) 5、服务器关闭时执行的方法,主要用来释放资源
Private Sub IRtdServer_ServerTerminate()

下面是5个接口的具体实现:

 Implements IRtdServer

 Dim rtdUpdate As IRTDUpdateEvent
Dim stocks As Collection
Dim helper As StockHelper
Dim WithEvents Timer As clsTimer Private Function IRtdServer_Heartbeat() As Long
IRtdServer_Heartbeat =
End Function Private Function IRtdServer_ServerStart(ByVal CallbackObject As IRTDUpdateEvent) As Long
Set rtdUpdate = CallbackObject
Set stocks = New Collection
Set helper = New StockHelper
Set Timer = New clsTimer
Timer.Interval =
Timer.Enabled = True
IRtdServer_ServerStart =
End Function Private Sub Timer_Timer()
helper.QueryInfos stocks
rtdUpdate.UpdateNotify
End Sub Private Function IRtdServer_ConnectData(ByVal TopicID As Long, Strings() As Variant, GetNewValues As Boolean) As Variant
GetNewValues = True
Dim temp As New StockData
temp.StockCode = Strings()
temp.StockIndex = Strings()
temp.TopicID = TopicID
helper.QueryInfo temp
stocks.Add temp
IRtdServer_ConnectData = temp.Value
End Function Public Function IRtdServer_RefreshData(TopicCount As Long) As Variant()
Dim objs() As Variant
Dim i As Integer
TopicCount = stocks.Count
ReDim objs( To , To TopicCount - )
For Each s In stocks
objs(, i) = s.TopicID
objs(, i) = s.Value
i = i +
Next
IRtdServer_RefreshData = objs
End Function Private Sub IRtdServer_DisconnectData(ByVal TopicID As Long)
For i = stocks.Count To Step -
If stocks(i).TopicID = TopicID Then
stocks.Remove (i)
End If
Next i
End Sub Private Sub IRtdServer_ServerTerminate()
Timer.Enabled = False
Set rtdUpdate = Nothing
Set stocks = Nothing
Set Timer = Nothing
End Sub

IRtdServer_ServerStart:该方法做一些初始化工作,返回值设为1表示服务器已准备就绪,可以工作了。

参数CallbackObject是IRTDUpdateEvent类型,Excel将这个对象实例传至方法内部。

第7行接收IRTDUpdateEvent的对象实例,在类模块内部全局使用。这个对象有个重要方法是UpdateNotify

 Dim rtdUpdate As IRTDUpdateEvent
Dim stocks As Collection
Dim helper As StockHelper
Dim WithEvents Timer As clsTimer Private Function IRtdServer_ServerStart(ByVal CallbackObject As IRTDUpdateEvent) As Long
Set rtdUpdate = CallbackObject
Set stocks = New Collection
Set helper = New StockHelper
Set Timer = New clsTimer
Timer.Interval =
Timer.Enabled = True
IRtdServer_ServerStart =
End Function Private Sub Timer_Timer()
helper.QueryInfos stocks
rtdUpdate.UpdateNotify
End Sub

a、StockHelper类中的方法向百度API请求(get)数据,在这里先做好实例化,备用。

  b、stocks集合用来保存所有请求到的StockData

  c、timer是一个计时器(类),因为vb的类模块里无法使用窗体控件timer,我从其它地方抄来了一个timer类来用,自己添加了事件进去。该计时器每隔两秒触发一次Timer事件(Sub Timer_Timer())做两件事情:

1、代码第17行:重新请求股票数据。
           2、代码第18行:执行rtdUpdate.UpdateNotify实现excel中数据的更新(Excel会调用IRtdServer_ConnectData方法,使用该方法的返回值更新数据)

IRtdServer_ConnectData:rtd函数首次请求数据时执行本方法。

 Private Function IRtdServer_ConnectData(ByVal TopicID As Long, Strings() As Variant, GetNewValues As Boolean) As Variant
GetNewValues = True
Dim temp As New StockData
  temp.StockCode = Strings()
  temp.StockIndex = Strings()
  temp.TopicID = TopicID
helper.QueryInfo temp
stocks.Add temp
IRtdServer_ConnectData = temp.Value
End Function

该方法主要做几个工作:

a、依据rtd函数的参数topic1、topic2...(对应Stings(0),String(1)...)请求数据,得到返回值。
                1.每一个不重复的topic组合,服务器会分配唯一的TopicID
                2.每个主题请求得到的返回值,本案保存在temp.value中。
           b、自动为每一个请求分配一个唯一的TopicID(在IRtdServer_ConnectData依据TopicID刷新数据)

c、GetNewValues=1表示,每次打开工作簿都重新请求数据

IRtdServer_RefreshData:当服务器要刷新数据时执行本方法(IRTDUpdateEvent的UpdateNotify执行时会调用本方法刷新数据)

 Public Function IRtdServer_RefreshData(TopicCount As Long) As Variant()
Dim objs() As Variant
Dim i As Integer
TopicCount = stocks.Count
ReDim objs( To , To TopicCount - )
For Each s In stocks
objs(, i) = s.TopicID
objs(, i) = s.Value
i = i +
Next
IRtdServer_RefreshData = objs
End Function

  a、TopicCount记录主题数量。
  b、返回值是一个2行n列的二维数组,第一行记录TopicID,第二行保存刷新后的值。
      c、猜测Excel使用该方法的返回值,这个二维数组更新rtd公式的值。

其他三个方法比较简单,具体代码可在下载文件中查看,也可以看前文中的代码折叠区,自行分析消化一下:

  IRtdServer_DisconnectData:删除主题时根据TopicID从Stocks中删除数据,它的参数TopicID就是被删除的主题ID。很简单。

  IRtdServer_ServerTerminate:释放资源。

  IRtdServer_Heartbeat:返回值为1时,表示服务器运行正常。

项目编译生成dll文件后,还有关键的一步是要在注册表中注册:

1、生成的dll,我生成的dll起名vbproj.dll。这个生成的dll名字可以按自己的想法起名字。

2、注册dll,方法是在cmd中输入"regsvr32 dll文件的保存路径"

注册完成以后,在注册表中搜索关键字myvbproj.rtdserver会有收获,如图:(可以看到ProgID,它的作用应该是标识这个服务)

效果展示

1、输入公式取到数据

2、数据每2秒更新一次(非开盘时间,使用随机数模拟数据源的变化)

3、删除单个主题,不影响其它主题

使用VB6制作RTD函数的更多相关文章

  1. 浅谈Excel开发:五 Excel RTD函数

        上文介绍了Excel中的UDF函数,本文介绍一下同样重要的RTD函数.从Excel 2002开始,Excel引入了一种新的查看和更新实时数据的机制,即real-time data简称RTD函数 ...

  2. VB6 如何添加自定义函数 模块 把代码放到一个模块中

    1 工程-添加模块,在右侧工程视图中可以发现多了一个Module1   2 比如我在这个模块中自定义两个函数,分别为写入和读取INI的函数   3 则在主程序中已经可以直接调用  

  3. VB6制作的自定义ocx控件

    下载后,解压缩,有一个TreeviewExplorer.ocx文件 在Excel的开发工具选项卡,点击插入ActiveX控件 VBA窗体,VB6窗体.VB.Net窗体都可以使用这个自定义控件的功能. ...

  4. 浅谈Excel开发:六 Excel 异步自定义函数

    上文介绍了Excel中的自定义函数(UDF ),它极大地扩展了Excel插件的功能,使得我们可以将业务逻辑以Excel函数的形式表示,并可以根据这些细粒度的自定义函数,构建各种复杂的分析报表. 普通的 ...

  5. 浅谈Excel开发:四 Excel 自定义函数

    我们知道,Excel中有很多内置的函数,比如求和,求平均,字符串操作函数,金融函数等等.在有些时候,结合业务要求,这些函数可能不能满足我们的需求,比如我想要一个函数能够从WebService上获取某只 ...

  6. VB6.0调用DLL

    目录 第1章 VB6.0调用DLL    1 1 VC++编写DLL    1 1.1 使用__stdcall    1 1.2 使用 .DEF 文件    1 2 简单数据类型    2 2.1 传 ...

  7. Excel 自定义函数

    浅谈Excel开发:四 Excel 自定义函数   我们知道,Excel中有很多内置的函数,比如求和,求平均,字符串操作函数,金融函数等等.在有些时候,结合业务要求,这些函数可能不能满足我们的需求,比 ...

  8. python之函数对象、函数嵌套、名称空间与作用域、装饰器

    一 函数对象 一 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素 二 利用该特性,优雅的取代多分支的if de ...

  9. python基础知识13---函数对象、函数嵌套、名称空间与作用域、装饰器

    阅读目录 一 函数对象 二 函数嵌套 三 名称空间与作用域 四 闭包函数 五 装饰器 六 练习题 一 函数对象 1 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 ...

随机推荐

  1. Emgu 决策树

    MCvDTreeParams cvFolds //If this parameter is >1, the tree is pruned using cv_folds-fold cross va ...

  2. Linux ACL管理详解

    转自: http://linuxguest.blog.51cto.com/195664/124107 1. 为什么要使用ACL先让我们来简单地复习一下Linux的file permission.在li ...

  3. symmetric multiprocessor

    https://en.wikipedia.org/wiki/Symmetric_multiprocessor_system A symmetric multiprocessor system (SMP ...

  4. JDBC 基本操作

    1. 简介 JDBC(Java DataBase Connectivity) 是有一些接口和类构成的API JDBC是J2SE的一部分, 又java.sql: javax.sql包组成.   应用程序 ...

  5. 使用 U盘 重装 Mac OSX

    一.制作 U 盘系统启动盘 1.从 App Store 上下载 OS Application.(这里需要注意,取消下载完的自动更新,并存储下这个 OS.Application 文件,因为系统更新完后, ...

  6. SSH 登录VPS解决 The directory media/wysiwyg is not writable by server.问题

    权限问题,去到 Magent根目录的Media文件夹,执行下面代码授权. chmod 777 wysiwyg

  7. MacOS10.11的/usr/bin目录不可写后class-dump的处理办法

    许多升级了OSX 10.11的朋友在配置class-dump的时候,会发现书上推荐的class-dump存放目录/usr/bin不再可写,如下所示: 192:~ snakeninny$ touch c ...

  8. blockdev命令和blkid命令

    blockdev命令和blkid命令 http://www.jb51.net/LINUXjishu/310389.html block相关的命令 这篇文章主要介绍了Linux blockdev命令设置 ...

  9. mac 启动 docker daemon

    我是用virtualbox安装的. 有一个小问题就是启动docker服务时会检查boot2docker是不是最新的. 由于github被封了,所以只能手动下 https://github.com/bo ...

  10. ios-高仿别踩白块游戏的实现

    先看下效果图片 前几天看到一个游戏叫别踩白块,下载量还挺大几百万了都,下载下来玩了玩看了看,这个游戏还挺简单的.俗话说想一千遍,一万遍不如动手做一遍来的实在.昨晚以及今天白天闲的没事就开搞了,下午六点 ...