我是靠谱客的博主 狂野翅膀,最近开发中收集的这篇文章主要介绍(转)C#封装CTP,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、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

最后

以上就是狂野翅膀为你收集整理的(转)C#封装CTP的全部内容,希望文章能够帮你解决(转)C#封装CTP所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部