(转)C#封装CTP

21 篇文章 7 订阅
19 篇文章 0 订阅

一、CTPFutrueProvider

https://github.com/fouvy/CTPFutrueProvider

动态链接库:CTPWrapper 项目概述

应用程序向导已为您创建了此 CTPWrapper DLL。

本文件概要介绍组成 CTPWrapper 应用程序的每个文件的内容。

CTPWrapper.vcproj

这是使用应用程序向导生成的 VC++ 项目的主项目文件。

它包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。

CTPWrapper.cpp

这是主 DLL 源文件。

其他标准文件:

StdAfx.h, StdAfx.cpp

这些文件用于生成名为 CTPWrapper.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。

其他注释:

应用程序向导使用“TODO:”指示应添加或自定义的源代码部分。

二、PInvoke的方式

今天主要讲以下的方式:

http://www.360doc.com/content/14/0211/00/3218170_351502832.shtml
从C#的托管代码中,调用C++的非托管代码,主要是使用PInvoke的方式,但CTP的API接口中存在以下两个特点,使我们无法直接调用
1、各种请求(Req函数)是Api类的成员函数,而不是静态函数
2、各种响应,是需要继承Spi类之后,才能在重写的虚函数(是叫这名字吧。。。)中得到回传数据

针对这两个特点,我使用的方法是
1、新建WIN32项目(项目名:CTPWrapper),将Api类的成员函数扩展成静态函数,如:

Code:
///创建TraderApi
///@param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录
///@return 创建出的UserApi
extern "C" CTPWRAPPER_API void* CreateTraderApi(const char *pszFlowPath)
{
	return CThostFtdcTraderApi::CreateFtdcTraderApi(pszFlowPath);
};

///注册前置机网络地址
///@param pszFrontAddress:前置机网络地址。
///@remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:17001”。 
///@remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”17001”代表服务器端口号。
extern "C" CTPWRAPPER_API void TraderRegisterFront(void *instance,char *pszFrontAddress)
{
	((CThostFtdcTraderApi *)instance)->RegisterFront(pszFrontAddress);
};

其中的CTPWRAPPER_API 是
Code:

#define CTPWRAPPER_API __declspec(dllexport)

就像这样,实现了两个标准的WIN32API,将其编译成DLL,从C#中就可以直接调用了。

C#中定义PInvoke方法如下
Code:

[DllImport("CTPWrapper.dll")]
  internal static extern IntPtr CreateTraderApi(string pszFlowPath);

  [DllImport("CTPWrapper.dll")]
  internal static extern void TraderRegisterFront(IntPtr hTrader, String address);

在C#中创建并使用TraderApi
Code:

IntPtr _instance = CreateTraderApi("");
TraderRegisterSpi(_instance, this._listener.Instance);

2、使用函数指针从C++的函数中调用C#的方法
为保证C++的函数能够正确的调用C#的方法,函数指针的构成必须一致,因此分别在C++和C#中定义以下内容:
Code:
C++

///登录请求响应
typedef void (WINAPI *OnRspUserLoginCallback)(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) ;

C#
Code:

public delegate void UserLoginCallback(IntPtr pRspUserLogin, IntPtr pRspInfo, int nRequestID, [MarshalAs(UnmanagedType.U1)]bool bIsLast);

(这里注意下bool类型的定义,在这里我被郁闷了好久:()

然后在创建Spi类的时候将C#的回调函数指针作为参数传到C++中
Code:
C++中Spi的构造函数

CTPTraderSpi::CTPTraderSpi(OnRspUserLoginCallback callback)
{
	this->m_OnRspUserLoginCallback = callback;
}

同1的方法,将构造函数扩展为WIN32API
Code:

extern "C" CTPWRAPPER_API void* WINAPI CreateTraderSpiClass(OnRspUserLoginCallback callback) 
{
	CTPTraderSpi *spi = new CTPTraderSpi(callback);
	return (void*)spi; 
}

这样,在C++中得到响应时,就可以调用C#的方法了
Code:
///登录请求响应

void CTPTraderSpi::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) 
{
	if(this->m_OnRspUserLoginCallback)
	{
		(this->m_OnRspUserLoginCallback)(pRspUserLogin ,pRspInfo,nRequestID,bIsLast);
	}
}

在C#中,这样使用
Code:

UserLoginCallback userLoginCallback = new UserLoginCallback(this.OnUserLogin);

_instance = CreateTraderSpiClass(userLoginCallback);

OK,到这里,最最核心的东西已经说完了,剩下的都是些技巧和体力活了
比如Spi的回调函数有很多,总不可能在C#中创建好了再一个个传到C++里,怎办呢?其实我是用了个Struct,包好了一起传的
Code:

 /// <summary>
  /// 回调函数指针结构
  /// </summary>
  [StructLayout(LayoutKind.Sequential)]
  internal struct CTPTraderSpiCallbackStruct
  {

    ///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。
    internal FrontConnectedCallback FrontConnectedCallback;

    ///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
    ///@param nReason 错误原因
    ///        0x1001 网络读失败
    ///        0x1002 网络写失败
    ///        0x2001 接收心跳超时
    ///        0x2002 发送心跳失败
    ///        0x2003 收到错误报文
    internal FrontDisconnectedCallback FrontDisconnectedCallback;

    ///心跳超时警告。当长时间未收到报文时,该方法被调用。
    ///@param nTimeLapse 距离上次接收报文的时间
    internal HeartBeatWarningCallback HeartBeatWarningCallback;


    ///登录请求响应
    internal UserLoginCallback UserLoginCallback;

    ///登出请求响应
    internal UserLogoutCallback UserLogoutCallback;
  }

以下略
剩下还有一些细节问题,回头再慢慢说好了,整个过程被我封装成了两个工程
C++:CTPWrapper
C#:CTPInterop
由于还有很多工作没有完成,也就不发布出来了,有兴趣的朋友可以通过邮件和我联系,我把工程代码发给你
mail:lumen.xh@gmail.com

当然,如果有朋友愿意和我一起把剩下的部分建立起来的话,那就更好了:D

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值