C#如何调用C++写的DLL接口

mm6268 2009-04-14 04:33:01
小弟遇到一个难题,数据接口是用C++写的,我要在C#程序中调用。
下面附一个接口规范文档,请各位高手给解决一下
帮帮小弟解决难题

*银江行情接口规范V1.02
****************************************************************************************/
* 驱动程序安装后,在系统注册库中注册了以下信息,分析软件通过该注册信息启动引擎动态库*
* HKEY_LOCAL_MACHINE/SOFTWARE/StockDrv 下 *
* Driver = "驱动DLL全路径" *
****************************************************************************************/

#ifndef __STOCKDRV_H__
#define __STOCKDRV_H__


// 工作方式类型定义
#define RCV_WORK_SENDMSG 4

/////////////////////////////////////////////////////////////////////////////////////////

// 证券市场
#define SH_MARKET_EX 'HS' // 上海
#define SZ_MARKET_EX 'ZS' // 深圳

// 文件数据类型
// 结构数组形式的文件数据
#define FILE_HISTORY_EX 2 // 补日线数据
#define FILE_MINUTE_EX 4 // 补分钟线数据
#define FILE_POWER_EX 6 // 补充除权数据
#define FILE_5MINUTE_EX 81 // 补5分钟线数据

#define FILE_BASE_EX 0x1000 // 钱龙兼容基本资料文件,m_szFileName仅包含文件名
#define FILE_NEWS_EX 0x1002 // 新闻类,其类型由m_szFileName中子目录名来定

// 消息子类型
#define News_Sha_Ex 2 // 上证消息
#define News_Szn_Ex 4 // 深证消息
#define News_Fin_Ex 6 // 财经报道
#define News_Unknown_Ex -1 // 未知提供者

//Definition For nInfo of Function GetStockDrvInfo(int nInfo,void * pBuf);
#define RI_IDSTRING 1 // 厂商名称,返回(LPCSTR)厂商名
#define RI_IDCODE 2 // 卡号
#define RI_VERSION 3 // 驱动程序版本

#define RI_NETPCID 1000 // - 返回电脑硬件编号

#define STKLABEL_LEN 10 // 股号数据长度,国内市场股号编码兼容钱龙
#define STKNAME_LEN 32 // 股名长度


//////////////////////////////////////////////////////////////////////////////////
//行情数据(版本数据结构RCV_WORK_SENDMSG)
typedef struct tagRCV_REPORT_STRUCTExV2
{
WORD m_cbSize; // 结构大小
time_t m_time; // 成交时间
WORD m_wMarket; // 股票市场类型
char m_szLabel[STKLABEL_LEN]; // 股票代码,以'\0'结尾
char m_szName[STKNAME_LEN]; // 股票名称,以'\0'结尾

float m_fLastClose; // 昨收
float m_fOpen; // 今开
float m_fHigh; // 最高
float m_fLow; // 最低
float m_fNewPrice; // 最新
float m_fVolume; // 成交量
float m_fAmount; // 成交额
float m_fBuyPrice[3]; // 申买价1,2,3
float m_fBuyVolume[3]; // 申买量1,2,3
float m_fSellPrice[3]; // 申卖价1,2,3
float m_fSellVolume[3]; // 申卖量1,2,3

float m_fBuyPrice4; // 申买价4
float m_fBuyVolume4; // 申买量4
float m_fSellPrice4; // 申卖价4
float m_fSellVolume4; // 申卖量4
} RCV_REPORT_STRUCTExV2;

//////////////////////////////////////////////////////////////////////////////////
//行情数据(版本3数据结构RCV_WORK_SENDMSG,兼容RCV_REPORT_STRUCTExV2结构,使用m_cbSize区分不同结构)
typedef struct tagRCV_REPORT_STRUCTExV3
{
WORD m_cbSize; // 结构大小
time_t m_time; // 成交时间
WORD m_wMarket; // 股票市场类型
char m_szLabel[STKLABEL_LEN]; // 股票代码,以'\0'结尾
char m_szName[STKNAME_LEN]; // 股票名称,以'\0'结尾

float m_fLastClose; // 昨收
float m_fOpen; // 今开
float m_fHigh; // 最高
float m_fLow; // 最低
float m_fNewPrice; // 最新
float m_fVolume; // 成交量
float m_fAmount; // 成交额
float m_fBuyPrice[3]; // 申买价1,2,3
float m_fBuyVolume[3]; // 申买量1,2,3
float m_fSellPrice[3]; // 申卖价1,2,3
float m_fSellVolume[3]; // 申卖量1,2,3

float m_fBuyPrice4; // 申买价4
float m_fBuyVolume4; // 申买量4
float m_fSellPrice4; // 申卖价4
float m_fSellVolume4; // 申卖量4

float m_fBuyPrice5; // 申买价5
float m_fBuyVolume5; // 申买量5
float m_fSellPrice5; // 申卖价5
float m_fSellVolume5; // 申卖量5
} RCV_REPORT_STRUCTExV3;
...全文
1037 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
sunnnylove 2011-06-09
  • 打赏
  • 举报
回复
学习ing!
平凡的傲娇 2011-04-08
  • 打赏
  • 举报
回复
学习了
最近在做自助设备这方面的软件
受益良多。
杰克陈81 2010-01-14
  • 打赏
  • 举报
回复
看看,学习下。
HSZDDD 2010-01-04
  • 打赏
  • 举报
回复
学习下
wind_wolf00 2009-09-24
  • 打赏
  • 举报
回复
It is very good for fresh bird~
Thank you!
xiaomiyinerzhou 2009-05-13
  • 打赏
  • 举报
回复
你的问题主要就是使用平台调用(P/Invoke)或C++ Interop调用非托管DLL的问题。

如果你想系统学习如何进行数据封送,我推荐你阅读刚刚出版的新书:《精通.NET互操作P/Invoke,C++Interop和COM Interop》,这本书的第2章“数据封送”详细介绍了平台调用中的数据封送过程,非常详细,我就是读完后才搞清楚平台调用中的封送处理。


该书的官方网站:
www.interop123.com

豆瓣网信息:
http://www.douban.com/subject/3671497/
冰凝瞬间1986 2009-04-15
  • 打赏
  • 举报
回复
添加引用-浏览-指定的Dll文件
wzyzju 2009-04-14
  • 打赏
  • 举报
回复
学习~~
lybelmont 2009-04-14
  • 打赏
  • 举报
回复
可能需要对C++的结构体进行 C#的转化 2者兼容不是太好(即使类型相同)
陌上花花 2009-04-14
  • 打赏
  • 举报
回复
好复杂呀
txt_paul 2009-04-14
  • 打赏
  • 举报
回复
友情一顶
打酱油 ,路过
深海之蓝 2009-04-14
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 oyljerry 的回复:]
dllimport导入对应的dll,然后申明对应的几个导出函数,就可以调用了
[/Quote]
正解
liu20071001 2009-04-14
  • 打赏
  • 举报
回复
up
蓝海D鱼 2009-04-14
  • 打赏
  • 举报
回复
我做过这个
可以采用这种办法
如果是非托管的,就用DllImport,举例
using System;
using System.Runtime.InteropServices;
class MainApp
[DllImport("Kernel32")] //读取动态库文件
public static extern int GetProcAddress(int handle, String funcname);

给你讲一下我的经验:
首先 你在C#中调用的 是C++ 写的一个动态库。比如Kernel32.dll 中的 函数;
这个函数用C++写 有如下要求:
1、 必须为全局函数
2、 函数参数 必须为基本类型,也就是C++ 和C#都有的类型,否则你在public static extern int GetProcAddress(int handle, String funcname);
这里没有办法声明。 其余的 没什么了;

还有你可以参考这里:http://blog.csdn.net/jingshuaizh/archive/2009/02/04/3862019.aspx
zgke 2009-04-14
  • 打赏
  • 举报
回复
你先把C结构体都翻译过来. 我还以为你招苦工呢.
qqiuzaihui 2009-04-14
  • 打赏
  • 举报
回复

引用: using System.Runtime.InteropServices;


[DllImport("Kernel32")] //读取动态库文件
public static extern int GetProcAddress(int handle, String funcname);
[DllImport("Kernel32")]
public static extern int LoadLibrary(String funcname);
[DllImport("Kernel32")]
public static extern int FreeLibrary(int handle);


[DllImport("HmPark.dll")] //声明C++中的接口函数, 其中 HmPark 为你的动态库文件名
public static extern double GetStdCharge(UInt32 time_In, UInt32 time_Out);

private int huser32 = 0;
private void CountCharge()
{
double dCharge = 0;
try
{
huser32 = LoadLibrary("HmPark.dll"); //载入动态库
dCharge = GetStdCharge(time_In, time_Out); //调用 C++ 中的接口函数, 此处的两个参数分别对应C++入口函数中的time_t参数
}
catch (Exception ex)
{
MessageBox.Show("调用出错: " + ex.Message, "操作提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
try
{
FreeLibrary(huser32); //释放动态库文件, 否则会弹出异常
}
catch (Exception ee)
{
MessageBox.Show("释放出错: " + ee.Message, "操作提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
xiaoyi63 2009-04-14
  • 打赏
  • 举报
回复
如果是非托管的,就用DllImport,举例
using System;
using System.Runtime.InteropServices;
class MainApp
{ //通过DllImport引用user32.dll类。MessageBox来自于user32.dll类
 [DllImport("user32.dll", EntryPoint="MessageBox")]
 public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);
 public static void Main()
 {
  MessageBox( 0, "您好,这是 PInvoke!", ".net", 0 );
 }
}

DllImport具有五个命名参数:

   a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。

   b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。

   c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。

   d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。

   e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。

   f、SetLastError 参数指示方法是否保留 Win32"上一错误"。如果未指定 SetLastError,则使用默认值 false。



使用时注意C#与C++之间的类型映射

Wtypes.h 中的非托管类型 非托管C语言类型 托管类名 说明
HANDLE void* System.IntPtr 32 位
BYTE unsigned char System.Byte 8 位
SHORT short System.Int16 16 位
WORD unsigned short System.UInt16 16 位
INT int System.Int32 32 位
UINT unsigned int System.UInt32 32 位
LONG long System.Int32 32 位
BOOL long System.Int32 32 位
DWORD unsigned long System.UInt32 32 位
ULONG unsigned long System.UInt32 32 位
CHAR char System.Char 用 ANSI 修饰。
LPSTR char* System.String 或 System.StringBuilder 用 ANSI 修饰。
LPCSTR Const char* System.String 或 System.StringBuilder 用 ANSI 修饰。
LPWSTR wchar_t* System.String 或 System.StringBuilder 用 Unicode 修饰。
LPCWSTR Const wchar_t* System.String 或 System.StringBuilder 用 Unicode 修饰。
FLOAT Float System.Single 32 位
DOUBLE Double System.Double 64 位
qqiuzaihui 2009-04-14
  • 打赏
  • 举报
回复

引用: using System.Runtime.InteropServices;


[DllImport("Kernel32")] //读取动态库文件
public static extern int GetProcAddress(int handle, String funcname);
[DllImport("Kernel32")]
public static extern int LoadLibrary(String funcname);
[DllImport("Kernel32")]
public static extern int FreeLibrary(int handle);


[DllImport("HmPark.dll")] //声明C++中的接口函数, 其中 HmPark 为你的动态库文件名
public static extern double GetStdCharge(UInt32 time_In, UInt32 time_Out);

private int huser32 = 0;
private void CountCharge()
{
double dCharge = 0;
try
{
huser32 = LoadLibrary("HmPark.dll"); //载入动态库
dCharge = GetStdCharge(time_In, time_Out); //调用 C++ 中的接口函数
}
catch (Exception ex)
{
MessageBox.Show("调用出错: " + ex.Message, "操作提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
try
{
Inspect.FreeLibrary(huser32); //释放动态库文件, 否则会弹出异常
}
catch (Exception ee)
{
MessageBox.Show("释放出错: " + ee.Message, "操作提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}

如何在C++中写DLL文件请自行在网上搜一下.
oyljerry 2009-04-14
  • 打赏
  • 举报
回复
dllimport导入对应的dll,然后申明对应的几个导出函数,就可以调用了
mm6268 2009-04-14
  • 打赏
  • 举报
回复
//////////////////////////////////////////////////////////////////////////////////
// 数据通知消息
//直接数据引用通知消息
// wParam = RCV_WPARAM;
// lParam 指向 RCV_DATA结构;
// 返回 1 已经处理, 0 未处理或不能处理

#define RCV_REPORT 0x3f001234
#define RCV_FILEDATA 0x3f001235
#define RCV_FENBIDATA 0x3f001301


// 注一:
// 记录数表示行情数据和补充数据(包括 Header)的数据包数,对文件类型数据, = 1
// 注二:
// 若 m_bDISK = FALSE, m_pData 为数据缓冲区指针
// ******** 数据共享,不能修改数据 **********
// m_bDISK = TRUE, m_pData 为该文件的存盘文件名,一般情况只有
// 升级软件等大文件用存盘方式
typedef struct tagRCV_DATA
{
int m_wDataType; // 文件类型
int m_nPacketNum; // 记录数,参见注一
RCV_FILE_HEADEx m_File; // 文件接口
BOOL m_bDISK; // 文件是否已存盘的文件
union
{
RCV_REPORT_STRUCTExV2* m_pReportV2;
RCV_REPORT_STRUCTExV3* m_pReportV3;
RCV_HISTORY_STRUCTEx * m_pDay;
RCV_MINUTE_STRUCTEx * m_pMinute;
RCV_POWER_STRUCTEx * m_pPower;
void * m_pData; // 参见注二
};
} RCV_DATA;

/* 消息处理程序 DEMO
LONG OnStkDataOK(UINT wParam,LONG lParam)
{
RCV_DATA * pHeader;
pHeader = (RCV_DATA *)lParam;
switch( wParam )
{
case RCV_REPORT: //股票行情
for(i=0; i<pHeader->m_nPacketNum; i++)
{
pHeader->m_pReportV3[i]...// 数据处理


//CTime tm(pHeader->m_pReportV3[i].m_time);
//CString jc=pHeader->m_pReportV3[i].m_szName;
//CString jg;
//jg.Format("%.2f",pHeader->m_pReportV3[i].m_fNewPrice);
//AfxMessageBox(tm.Format ("%Y%m%d %H:%M:%S")+ " " + jc+ " " + jg);//显示时间 简称 最新价
}
break;

case RCV_FILEDATA: //文件
switch(pHeader->m_wDataType)
{
case FILE_HISTORY_EX: // 补日线数据
break;
case FILE_MINUTE_EX: // 补分钟线数据
break;
case FILE_5MINUTE_EX: // 补5分钟线数据
break;
case FILE_POWER_EX: // 补充除权数据
break;
case FILE_BASE_EX: // 基本资料文件,m_szFileName仅包含文件名
break;
case FILE_NEWS_EX: // 新闻类,其类型由m_szFileName中子目录名来定
break;
}
break;
case RCV_FENBIDATA
{
RCV_FENBI* pFb;
pFb = (RCV_FENBI *)lParam;
for ( i=0; i<pFb->m_nCount; i++ )
{
//数据处理
}
}
break;
default:
return 0; // unknown data
}
return 1;
}
*/


//////////////////////////////////////////////////////////////////////////////////
//APIs
#ifdef __cplusplus
extern "C"{
#endif

//////////////////////////////////////////////////////////////////////////////////
// 注册函数

// 股票初始化
// 入口参数:
// hWnd 处理消息的窗口句柄
// Msg 用户自定义消息
// nWorkMode 接口工作方式,参见工作方式类型定义
// 返回参数:
// 1 成功
// -1 失败
// 注:
// 注册后,驱动程序会向处理窗口发送消息
// 若股票接收没启动,则启动股票接收程序
int WINAPI Stock_Init(HWND hWnd,UINT Msg,int nWorkMode);

// 退出,停止发送消息
// 入口参数:
// hWnd 处理消息的窗口句柄,同 Stock_Init 的调用入口参数
// 返回参数:
// 1 成功
// -1 失败
int WINAPI Stock_Quit(HWND hWnd);

// 激活接收程序,进行设置
// 入口参数:
// bSetup TRUE 显示窗口,进行设置
// FALSE 隐含窗口
// 返回参数:
// 1 成功
// -1 失败
int WINAPI SetupReceiver(BOOL bSetup);

// 取得股票驱动信息
// 入口参数:
// nInfo 索引
// pBuf 缓冲区
// 出口参数:
// nInfo == RI_IDSTRING, 返回特征字符串长度, pBuf 为特征字符串
// 如: "银江网络"
// nInfo == RI_IDCODE, 返回信息卡 ID 号, pBuf 为字符串形式的 ID 号
// 如: 0x78001234 "78001234"
// nInfo == RI_VERSION, 返回信息卡版本号, pBuf 为字符串版本
// 如: 1.00 "1.00"
// nInfo == RI_V2SUPPORT, 返回是否支持深圳SJS库结构, pBuf无效

// nInfo == RI_NETPCID 返回字符串长度, pBuf电脑硬件编号(用于验证合法用户)


// 另:当接口上的自动补充分时数据选项开启时,接口会根据分析软件的标题上的股票代码自动补充该股分时数据
DWORD WINAPI GetStockDrvInfo(int nInfo,void * pBuf);


#ifdef __cplusplus
}
#endif


#endif // __STOCKDRV_H__

加载更多回复(1)

110,586

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧