C#实现COM接口的编程原理介绍和WEALTHLAB插件DEMO

Discussion in 'Wealth-Lab Developer' started by tom_sh, Sep 23, 2005.

  1. 以下将介绍如何用C#制作符合COM规范的WEALTHLAB插件。这个插件是一个符合WEALTHLAB STATIC DATASOURCE API的DEMO,重点是原理方面的介绍,其他类型的

    WEALTHLAB插件(以及广义的COM接口)编程原理基本相同,大家只要能模仿,就可以用C#做出符合自己需要的任何一种COM组件,与你的特定程序配套使用。包

    括TS、AMIBROKER在内的大部分传统系统交易程序一般都支持COM技术,因此这里的介绍也是通用的。

    COM接口是一种公开程序编码规范,它要求不论开发工具为何,生成的程序代码(机器码)有一定的格式。这一定的格式包括预定义的对象属性(PROPERTY)、

    方法(METHOD)和事件(EVENT),此外还有枚举(ENUMERATION)和结构(STRUCTURE)等辅助性的信息。这个对象在C#中就是一个类(CLASS),你写出来的

    类只要具备着预定义的各项属性、方法、事件等对象要素,其他程序象WEALTHLAB就可以对其直接访问和交流。

    如何知道各项预定义对象要素呢?很简单,各种采用COM技术的主程序,如WEALTHLAB都会在程序代码中定义好这些要素,一般是通过一个接口的方式来做的。

    WEALTHLAB程序中定义了大约有十多种接口,包括IWealthLabEOD3(日末静态数据)、IWealthLabRT3(日内动态实时行情数据)、IWealthLabBroker3(经纪商

    下单接口)、IWealthLabAddOn3(通用数据接口)等。接下来的工作就是按照这些接口的定义编码COM对象的诸要素。C#提供了自动生成接口要素的功能。只要

    在编码上引用有关接口,各项要素就根据标准定义自动在代码文件中生成,但你需要根据各自实际情况自行编写各接口要素的具体实现代码。这就象给你提供

    了一个个人简历的模版,包括年龄、性别、资历、学历等要素都给你罗列齐备,但具体的内容需要你自行填写一样。

    我们的DEMO是一个静态日末数据源COM组件,即IWealthLabEOD3接口。这个接口只有四个预定义的方法(METHOD),比较简单,所以用它做例子比较合适。这四

    项方法分别为1、CreateDataSource(无入口参数,返回值为字符串);2、 GetSecurityName(入口参数为字符串,返回值为字符串);3、 FillSymbols(入

    口参数为字符串和一个IWealthLabStrings3类,无返回值);4、 LoadSymbol(入口参数为字符串、IWealthLabBars3类、时间等,无返回值)。只要按要求(

    即规定的入口参数和返回值)编码这四个方法,WEALTHLAB就可以获取又一种日末静态数据源。

    CreateDataSource方法:收集有关证券代码的信息,如存储目录、代码表等,可以为其他三项方法做些设置方面的准备工作。返回一个表示本数据源的字符串

    。在我们的DEMO中将简单地返回一个“STDEMO”表示我们的静态数据源。
    GetSecurityName方法:根据具体的代码查找其名字全称,即如入口参数为“600000”,则返回值应为“浦发银行”。在DEMO中,这个方法无须实现,返回一个

    空值。实用程序中可以建立一个字典,把股票代码和股票名称进行一一对应。
    FillSymbols方法:根据本数据源的代表字符串,如“STDEMO”,把本数据源负责采集或维护的所有代码(例如沪深股票)全部存储到一个IWealthLabStrings3

    类中。在DEMO中,我们仅使用600000和000001两个股票。实用程序可以从其他股票日线数据文件或码表文件中读取全部股票代码。
    LoadSymbol方法:这个方法向有关的图表提供静态日末数据。在DEMO中,我们仅使用600000和000001两个股票的五个交易日数据(直接用常数数组)。实用程

    序可以从互联网、文本文件、动态行情源的补日线接口或其他股票软件数据文件中读历史交易数据。

    1、创建一个C#类库项目
    选择文件-新建-项目,在VISUAL C#项目文件夹内选择类库,给项目起名WLDAdapter,选择一个保存目录,确定。
    2、设置项目
    在第一行using System;后增加以下代码:
    using System.Runtime.InteropServices;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.IO;
    using System.Threading;
    using System.Text;
    using System.Xml;
    using WealthLab;
    在项目-添加引用-COM页中选择Wealthlab library 1.0,双击选定,确定。此后代码编辑页旁的对象浏览页内会出现一个interop.wealthlab;
    3、编码
    修改第一个(也是唯一的)CLASS,即CLASS1如下:
    [ProgId("WLDSTAdapter.FXJ"),ComVisible(true)]//增加COM标识
    public class WLDST //把CLASS1更改为WLDST
    {
    public WLDST()//把CLASS1更改为WLDST
    {

    }
    }
    在public class WLDST后键入 “: IWealthLabEOD3”(引号内部分,包括冒号,这是引用IWealthLabEOD3接口的意思)。
    编码界面提示“按TAB键实现Wealthlab.IWealthLabEOD3接口的STUB”,遵循提示按TAB键。程序自动生成IWealthLabEOD3的各项方法(METHOD),即

    IWealthLabEOD3预定义子程序。现在需要我们自行编码具体的实现内容。程序自动生成的代码段如下:
    #region IWealthLabEOD3 成员

    public void LoadSymbol(string DSString, string Symbol, IWealthLabBars3 Bars, DateTime StartDate, DateTime EndDate, int

    MaxBars)
    {
    // TODO: 添加 WLDST.LoadSymbol 实现
    }

    public string GetSecurityName(string Symbol)
    {
    // TODO: 添加 WLDST.GetSecurityName 实现
    return null;
    }

    public void FillSymbols(string DSString, IWealthLabStrings3 Symbols)
    {
    // TODO: 添加 WLDST.FillSymbols 实现
    }

    public string CreateDataSource()
    {
    // TODO: 添加 WLDST.CreateDataSource 实现
    return null;
    }

    #endregion
    现在逐一做四个方法的具体实现。
    第一个,CreateDataSource,如下:

    public string CreateDataSource()
    {
    // TODO: 添加 WLDST.CreateDataSource 实现
    return "STDEMO";
    }
    仅仅把return null修改为return "STDEMO"就行了。
    第二个,GetSecurityName,维持原样。你也可以把null改成Symbol,即代码和名称一样。
    第三个,FillSymbols,如下:
    public void FillSymbols(string DSString, IWealthLabStrings3 Symbols)
    {
    // TODO: 添加 WLDST.FillSymbols 实现
    if(DSString=="STDEMO")
    {
    Symbols.Add("600000");
    Symbols.Add("000001");
    }
    }
    我们仅使用两个股票代码,600000和000001。实用程序可以通过FOR循环把所有的代码加入到Symbols中去,语法是Symbols.add(代码字符串)。
    第四个,LoadSymbol,如下:
    public void LoadSymbol(string DSString, string Symbol, IWealthLabBars3 Bars, DateTime StartDate, DateTime EndDate, int MaxBars)
    {
    // TODO: 添加 WLDST.LoadSymbol 实现
    if(DSString=="STDEMO")
    {
    switch (Symbol)
    {
    case "000001":
    Bars.Add(new DateTime (2005,9,16),(double)6.29,(double)6.37,(double)6.26,(double)6.3,72816);//添加2005-9-16日开高收低量数据,下类似
    Bars.Add(new DateTime (2005,9,19),(double)6.3,(double)6.32,(double)6.22,(double)6.28,69514);
    Bars.Add(new DateTime (2005,9,20),(double)6.27,(double)6.27,(double)6.13,(double)6.14,105659);
    Bars.Add(new DateTime (2005,9,21),(double)6.14,(double)6.18,(double)6.02,(double)6.03,83604);
    Bars.Add(new DateTime (2005,9,22),(double)6.02,(double)6.04,(double)5.83,(double)5.9,93892);
    break;
    case "600000":
    Bars.Add(new DateTime (2005,9,16),(double)8.86,(double)9.02,(double)8.84,(double)8.9,62436);//添加2005-9-16日开高收低量数据,下类似
    Bars.Add(new DateTime (2005,9,19),(double)8.9,(double)8.97,(double)8.82,(double)8.85,39076);
    Bars.Add(new DateTime (2005,9,20),(double)8.86,(double)8.88,(double)8.67,(double)8.71,42595);
    Bars.Add(new DateTime (2005,9,21),(double)8.66,(double)8.76,(double)8.47,(double)8.49,49920);
    Bars.Add(new DateTime (2005,9,22),(double)8.47,(double)8.51,(double)8.12,(double)8.27,71246);
    break;
    }
    }
    }
    本方法为WLD股价走势图提供数据,因此其实现的基本思路是首先取数据,如互联网、本地股票软件数据等,然后用BARS.ADD指令从先到后把所有的数据添加到

    BARS中去就可以了。StartDate, , EndDate, MaxBars在本实现中未使用,其具体含义可参考WLD的技术档案。
    4、编译
    完成了上述四项IWealthLabEOD3方法的具体实现代码,这个插件基本上就完成了。当然你可以按照这个思路编写适合自己情况的任何静态数据插件,可以在构

    造函数public WLDST()中进行有关初始化工作,可以增加任何必要的其他METHOD以执行有关操作。
    现在可以编译了,方法是选择菜单项生成-生成WLDAdapter,输出窗口会提示:
    ---------------------- 完成 ---------------------

    生成: 1 已成功, 0 已失败, 0 已跳过

    5、安装
    在你的项目文件夹的bin\debug下可以发现三个文件:Interop.WealthLab.dll,WLDAdapter.dll,WLDAdapter.pdb。把这三个文件拷贝到WLD安装目录下。打开

    记事本,新建一个文本文件,取名为StaticAdapter_STDEMO.txt,保存于WLD安装目录下,其内容(六行)如下:
    Name=STDEMO Adapter
    DLL=WLDAdapter.DLL
    ComClassName=WLDSTAdapter.FXJ
    Desc=HYLT样本WLD插件.
    URL=http://www.hylt.com
    Bitmap=logo_phpBB.bmp

    上面的logo_phpBB.bmp是海洋论坛首页的LOGO图片保存为BMP格式文件,也拷贝到WLD安装目录下。
    在WLD安装目录下进入命令提示符,键入C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\regasm /tlb /codebase WLDAdapter.dll,回车确认。运行WLD,选

    择菜单项datasource-datasource manager,可以看到STDEMO ADAPTER成为可选择的一项,点击该项,按NEXT,给新的DATASOURCE起个名字,如海洋论坛,确定

    后这个DATASOURCE就成为WLD的一个组成部分了(尽管只有两个股票)。

    全部源码、编译生成的文件(在BIN\DEBUG下)见上传的附件。

    此外,希望哪位试用DEMO的朋友把配合上面文字说明的贴图做出来,服务大家。

    附件已删
     
  2. 有意参与WLD插件项目开发的朋友:

    请安装WLD和VS2003,阅读programming C#(second edition)第二章:getting started:"hello world",按照本DEMO的提示编码、安装和运行我们的样本WLD插件,感觉一下这个项目是否适合你。如果一切OK,且最终决定参与人超过四人,这个项目就正式启动。具体的工作安排我另贴发布。

    有关项目范围和进度的信息:计划第一步做出STATIC和REALTIME两个插件,时间控制在三个月以内。
     
  3. 项目经理的这段文字,是进入实际的开发过程必须理解的最基本原理阐述,以下是我的逐步理解的过程。
    三个符合:制作的COM插件的性质吧。
    1。符合COM规范的WEALTHLAB插件。
    2。符合WEALTHLAB STATIC DATASOURCE API使用规范
    3。符合自己需要的任何一种COM组件,与你的特定程序配套使用
     
  4. 对象要素,对象属性是针对不同应用的一个意思。

    COM中:
    COM接口是一种公开程序编码规范,它要求生成的程序代码(机器码)有一定的格式,这一定的格式包括预定义的对象要素或对象属性。。。。

    C#中:
    这个对象在C#中就是一个类(CLASS),你写出来的类只要具备着预定义的各项属性、方法、事件等对象要素,其他程序象WEALTHLAB就可以对其直接访问和交流。

    WEALTHLAB中:
    如何知道各项预定义对象要素呢?很简单,各种采用COM技术的主程序,如WEALTHLAB都会在程序代码中定义好这些要素,一般是通过一个接口的方式来做的。
     
  5. 工作过程概述:
    1。接下来的工作就是按照这些接口的定义编码COM对象的诸要素。
    2。
    ----C#提供了自动生成接口要素的功能。
    ----只要在编码上引用有关接口,各项要素就根据标准定义自动在代码文件中生成,
    -----但你需要根据各自实际情况自行编写各接口要素的具体实现代码
     
  6.  
  7. 这是一个很生动的例子。关键是怎样将它与我们要做的工作联系起来。

    例子中的素材有:模板,模板中的各要素,各要素针对不同的人各要素的具体“反映”是不一样的。
    而我们工作中与以上相对应的是:
    COM:模板;
    COM中各对象要素:相当于模板中的各要素
    COM中各要素的“值”:对应例子中不同人的的具体情况,而此处就是反应不同WLD不同接口的具体情况。
     
  8. 此DEMO的作用就是怎样具体地或手把手地做:“但你需要根据各自实际情况自行编写各接口要素的具体实现代码”
     
  9. 我们的DEMO是一个静态日末数据源COM组件,即IWealthLabEOD3接口。。[/quote]

    我们的DEMO是一个静态日末数据源COM组件:讲明了此COM的用途。
    即IWealthLabEOD3接口:讲述了此COM与WLD相联系的部分或此COM进入WLD的路径或COM的各对象要素与WLD中相对应的部分。
     
  10. 只要按要求(即规定的入口参数和返回值)编码这四个方法,WEALTHLAB就可以获取又一种日末静态数据源。

    讲叙了此次编程的总体过程:按要求(即规定的入口参数和返回值)编码这四个方法,WEALTHLAB就可以获取又一种日末静态数据源。
     
  11. 收集的相关资料:

    When a user selects an Adapter DataSource and clicks next, WLD creates an instance of the Adapter's COM object. It then calls the Adapter's CreateDataSource method. The Adapter's implementation of CreateDataSource should open up an interface where the user can point to the DataSource's location, input a list of symbols, or specify whatever other options or settings that are required.



    CreateDataSource :
    returns a single string. This string should include any and all information that was input by the user. This string will be referred to hereafter as the "DataSource String".

    The next time a Static Adapter is called into action is when the list of symbols for a DataSource is required. This can happen at various points in the operation of WLD, but most often this happens when you open the DataSource's folder in a ChartScript Window, or open the DataSource Manager. When WLD needs the list of symbols contains in an Adapter DataSource it creates an instance of the Adapter's COM object, and then calls the FillSymbols method. FillSymbols is provided the "DataSource String" for the DataSource. Based on this information the Adapter should determine the symbols that compose the DataSource. It should use the provided IWealthLabStrings3 interface to populate the symbols, calling the Add method of that interface for each symbol.

    The last task the Static Adapter must perform is populating the chart with data when a symbol is selected. The LoadSymbol method is called whenever chart data needs to be populated. Once again the Adapter is passed the "DataSource String". The Adapter can use this value if required. LoadSymbol is also provided the Symbol being requested, and an instance of an IWealthLabBars3 interface. The Adapter should use the Add or AddOpenInterest method of the IWealthLabBars3 interface to populate the chart with data.

    function CreateDataSource: BSTR;
    This method is called when a new Static Adapter DataSource is created in the New DataSource Wizard. This method should bring up a modal dialog box and collect the appropriate information about the new DataSource from the user. For example, the user might have to navigate to a directory, or provide a list of symbols that the DataSource should be composed of. The method should then compress the information into a single string, and return this string as the function result.
     
  12. 相关资料:

    function GetSecurityName(Symbol: BSTR): BSTR;
    Implement this method to return a security name for the specified symbol. If you don't have access to a security name, return a blank string.
     
  13. 我们的DEMO是一个静态日末数据源COM组件:讲明了此COM的用途。
    即IWealthLabEOD3接口:讲述了此COM与WLD相联系的部分或此COM进入WLD的路径或COM的各对象要素与WLD中相对应的部分。[/quote]

    相关资料:

    An Adapter must implement the IWealthLabEOD3 COM interface. This interface provides a handful of methods that must be implemented in the Adapter
     
  14. 相关资料:

    procedure FillSymbols(DSString: BSTR; Symbols: IWealthLabStrings3);
    This method is responsible for populating a list of symbols based on the DataSource String supplied in the DSString parameter. The DSString is the same string that was returned when the DataSource was first created (the return value of CreateDataSource). The method should populate the symbols using the Symbols parameter, which is an instance of the IWealthLabStrings3 interface. Call the Symbols.Add method for each symbol that is contained in the DataSource.

    IWealthLabStrings3 Reference

    The IWealthLabEOD3.FillSymbols method contains parameter that is an instance of this interface. Use this instance to populate the symbols of a DataSource.

    procedure Add( Value: BSTR );


    The IWealthLabEOD3.LoadSymbol method contains a parameter that is an instance of this interface. Use this instance to populate the bars of a chart.

    procedure Add(Date: Date; Open: double; High: double; Low: double; Close: double; Volume: long);
    Call this method once for every bar of data that should be loaded. Be sure to load the bars from earliest to latest.

    procedure AddOpenInterest(Date: Date; Open: double; High: double; Low: double; Close: double; Volume: long; OpenInterest: long);
    Use this method instead of Add if you have data that contains open interest.


    Call this method once for each symbol that is contained in the DataSou
     
  15. 相关资料:

    procedure LoadSymbol(DSString: BSTR; Symbol: BSTR; Bars: IWealthLabBars3; StartDate: DATE; EndDate: DATE; MaxBars: long);


    This method is responsible for populating the bars of a chart for the specified Symbol.

    The DSString parameter contains the string that identifies the DataSource (as above).

    StartDate and EndDate may contain date values that specify a range of data to be loaded. If StartDate is non-zero, you should not load bars that are prior to that date. If EndDate is non-zero, you should not load dates that are after that date. It's not strictly necessary to observe these values. WLD will filter the data after the fact if your Adapter doesn't.

    MaxBars will contain the maximum number of bars that should be loaded, or zero if all bars should be loaded. Once again, you don't necessarily have to observe this parameter, but you should do so if it could save a significant amount of loading time.

    The Bars parameter is an instance of the IWealthLabBars3 interface. For each bar of data, call the Bars.Add method to add the date, open, high, low, close and volume. If you also have open interest data you can call Bars.AddOpenInterest instead. Be sure to load data in chronological order, oldest first.
     
  16.  
  17. 以上是用VC#生成COM的通用步骤,按照项目经理讲的参照PROGRAMING C#的例子操作过几次就会烂熟于胸了。
     
  18. 此即为VC#生成的WLD中IWealthLabEOD3接口各方法的编码框架,可理解成模板的各通用要素也即是简历中的各个通用项。其结构模式也是一回生二回熟。