65.9K
CodeProject 正在变化。 阅读更多。
Home

Excel 2007 股票报价加载项

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (8投票s)

2012年4月2日

CPOL

4分钟阅读

viewsIcon

111823

downloadIcon

4880

创建一个类似 MSN 的 Excel 2007 股票报价加载项,使用用户自定义函数和 Ribbon 界面。

安装说明

在使用加载项之前,您应该检查安装是否已正确执行。 打开 Excel 2007 选项对话框,然后单击菜单项“加载项”。 活动加载项列表应包含“Parago.de Stock Quotes Function Add-In”(COM 加载项)以及“Parago.de Stock Quotes UI Add-In”(COM 加载项)。

然后,通过按“加载项”对话框窗口上的按钮(请参阅对话框底部的按钮)打开 Excel 加载项管理器对话框。 然后检查加载项“ParagoStockQuote.Functions”是否在列表中可用并被标记。 如果没有,请将其添加到列表中并标记它。

引言

本文介绍如何用 C# 为 Excel 2007 实现一个托管股票报价加载项,使其行为类似于您可以从 Microsoft 下载的“MSN MoneyCentral Stock Quotes”加载项(请参阅“Excel 2003/2002 加载项:MSN Money Stock Quotes”)。 该加载项是从头开始开发的,未使用 Visual Studio Tools for Office (VSTO)。

一旦加载项安装并注册后,您可以使用名为“PSQ”的用户定义函数 (UDF) 从 Yahoo! 财经服务检索给定股票代码的股票报价价格、日期、时间和名称。

以下公式示例显示了 PSQ 函数的用法

=PSQ(B4;'PRICE') or just =PSQ(A1)to retrieve the last price
=PSQ(B4;'NAME') to retrieve the company name
=PSQ(B4;'DATE') to retrieve the last price date
=PSQ(B4;'TIME') to retrieve the last price time 

该加载项还实现了新的 Office “Fluent”用户界面的自定义 Ribbon 界面。 以下两个屏幕截图显示了使用德语版 Excel 的加载项的操作

StockQuoteExcelAddIn/Screenshot1.png

StockQuoteExcelAddIn/Screenshot2.png

自定义 Ribbon 界面(名为“Stock Quotes”)提供了一个“更新”按钮,用于一次性检索(更准确地说是重新计算)所有与股票相关的公式。

本文的主要目的是展示使用新的 UI 元素,特别是用户自定义函数,创建 Excel 2007 加载项是多么容易。 因此,为了保持这项任务简单明了,我省略了安装项目和通常需要的 COM shim 项目(请参阅下面关于托管 Office 扩展的解释)。

Office 扩展

多年来,Microsoft 公开了大量不同的 Office 可扩展性机制,例如 COM 加载项、XLL 扩展、智能标记等等,开发人员可以使用这些机制来创建自己的自定义解决方案。

本文中描述的股票报价加载项是一个 COM 加载项,更准确地说,它被分为两个加载项。 一个加载项提供用户自定义函数“PSQ”,另一个加载项负责 UI 元素(Ribbon 界面)。 此技术允许您在不激活 UI 的情况下使用 UDF。

COM 加载项是一个 ActiveX-DLL(进程内服务器),它实现了 IDTExensibility 接口,并且所有 COM 加载项都必须提供这五个接口方法的实现: OnAddInsUpdate, OnBeginShutdown, OnConnection, OnDisconnection, OnStartupComplete。 在我们的例子中,我们只提供没有特定逻辑的空方法,除了 OnConnection。 此重写保存了对主机应用程序 (Excel) 的给定引用,以供以后使用

public void OnConnection(object host, ext_ConnectMode connectMode, 
            object addInInst, ref Array custom)
{
   _excel = (Application)host;
}

除了经典的 COM 注册之外,加载项还必须向 Excel 或扩展正在使用的另一个 Office 应用程序注册。 要向 Excel 注册扩展,加载项应使用其 ProgID 作为密钥的名称,在以下位置创建一个子密钥

HKEY_CURRENT_USER\Software\Microsoft\Office\Excel\Addins\ProgID

在我们的例子中,两个 COM 加载项的 ProgID 是 ParagoStockQuote.FunctionsParagoStockQuote.UI。 加载项注册为 Excel 提供了更多信息值,例如完整描述和友好名称。 此外,我们还指定了加载项 LoadBehavior(应用程序启动时加载为 0x03)。

为了在注册表中注册扩展,加载项提供了两个名为 RegisterFunctionUnregisterFunction 的静态方法。 它们分别用 ComRegisterFunctionAttributeComUnregisterFunctionAttribute 属性标记。 一旦包含程序集通过 RegAsm 等实用程序注册,CLR 就会调用这些方法。

[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type t)
{
   RegistryKey key;
   key = Registry.ClassesRoot.CreateSubKey(Functions.ClsIdKeyName + "Programmable");
   key.Close();
   key = Registry.ClassesRoot.CreateSubKey(Functions.ClsIdKeyName + "InprocServer32");
   key.SetValue(string.Empty, Environment.SystemDirectory + @"\mscoree.dll");
   key.Close();
   key = Registry.CurrentUser.CreateSubKey(Functions.ExcelAddInKeyName);
   key.SetValue("Description", "Parago.de Stock Quotes Function Add-In for Excel 2007", RegistryValueKind.String);
   key.SetValue("FriendlyName", "Parago.de Stock Quotes Function Add-In", RegistryValueKind.String);
   key.SetValue("LoadBehavior", 3, RegistryValueKind.DWord);
   key.SetValue("CommandLineSafe", 1, RegistryValueKind.DWord);
   key.Close();
}

[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type t)
{
   Registry.ClassesRoot.DeleteSubKey(Functions.ClsIdKeyName + "Programmable");
   Registry.ClassesRoot.DeleteSubKeyTree(Functions.ClsIdKeyName + "InprocServer32");
   Registry.CurrentUser.DeleteSubKey(Functions.ExcelAddInKeyName);
}

有关 COM Interop 和 COM 注册的更多信息,我推荐 CodeProject.com 文章:理解 .NET 应用程序的经典 COM 互操作性。

股票报价数据

加载项调用 Yahoo.com 的财经门户来检索请求的股票报价。 以下 URL 返回一个包含股票报价数据的逗号分隔字符串:http://download.finance.yahoo.com/d/quotes.csv?s=MSFT&f=sl1d1t1n

查询字符串参数是“s”表示股票代码,“f”表示返回的股票数据字段。 您可以在 Perl 模块“Finance::YahooQuote”(CPAN.org) 的文档中找到可用字段的列表。 因此,使用此来源,只需几行代码即可获取股票报价(请参阅代码和“用户自定义函数”部分)。

用户自定义函数

用户自定义函数没什么大不了的。 它们只是带有或不带有可选参数的普通方法。 可选参数用 OptionalAttribute 标记。“PSQ”的方法如下

public object PSQ(Range Cell, [Optional] object InfoCode)
{
   string symbol = Cell.Value2 as string;
   string infoCode = (InfoCode is Missing) ? "PRICE" : InfoCode as string;

   if(string.IsNullOrEmpty(symbol) || string.IsNullOrEmpty(infoCode))
      throw new Exception();

   WebClient client = new WebClient();
   Stream data = client.OpenRead("http://download.finance.yahoo.com/d/quotes.csv?s=" + 
                                 symbol.Trim() + "&f=sl1d1t1n");
   StreamReader reader = new StreamReader(data);
   string content = reader.ReadToEnd();
   data.Close();
   reader.Close();

   string[] quote = content.Split(",".ToCharArray());

   switch(infoCode.Trim().ToUpper())
   {
      case "NAME":
         return quote[4].Replace("\"", "").Replace("\r", "").Replace("\n", "");
      case "DATE":
         return Convert.ToDateTime(quote[2].Trim("\"".ToCharArray()), 
                CultureInfo.InvariantCulture).ToShortDateString();
      case "TIME":
         return Convert.ToDateTime(quote[3].Trim("\"".ToCharArray()), 
                CultureInfo.InvariantCulture).ToShortTimeString();
      case "PRICE":
      default:
         return Convert.ToDouble(quote[1], CultureInfo.InvariantCulture);
   }
}
© . All rights reserved.