您的位置:首页 > 职场人生

当码农的第一篇博客

2014-05-13 14:23 176 查看
工作的时间越长越感受到时光的飞逝,越感受到自己的不足,时刻保持严谨的态度非常重要。

最近做一个项目需要使用对方用c++写的类库,本人本职c#,因为惧怕类型转换,回调之类的问题,于是把问题推给一个c++高手,让他帮忙写一个调用程序,调试轻松通过。但是最后在项目部署的时候还是出了大事,32位c++调用程序连接64位oracle数据库出现问题,折腾一番无解,找了个折中方案暂时应付。

空闲时,细细想来,用c#调用c++类库或许没有那么难,于是baidu,google向各位大牛学习,取经。

调用程序

typedef void * VT_DSP_SERVER_HANDLE ;

typedef struct tagDspData
{
char szIP[20];  //DSP设备IP地址
char szTime[25];//获取到数人结果的时间
int  nChannel;  //DSP设备的通道号
int  nIn;       //进人数
int  nOut;      //出人数
float fInSpeed;				//进速度
float fOutSpeed;            //出速度
int   nZoneNum;				//区域人数
}DspData;

typedef void (__stdcall *CALLBACK_recv_front_data)(DspData data,void* pData);

VT_DSP_SERVER_API VT_DSP_SERVER_HANDLE VT_DSP_start_service(CALLBACK_recv_front_data callback,long lPort);

VT_DSP_SERVER_API void VT_DSP_stop_service(VT_DSP_SERVER_HANDLE handle);

VT_DSP_SERVER_HANDLE 为服务句柄 ,启动时获得,关闭时消除。

tagDspData 传数据时的结构体。

typedef void (__stdcall *CALLBACK_recv_front_data)(DspData data,void* pData); 回调函数,

VT_DSP_start_service 启动函数

VT_DSP_stop_service 关闭函数。

接下来开始类型转换, 最终转换结果为:

public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi)]
public struct tagDspData
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string szIP;  //DSP设备IP地址
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string szTime;//获取到数人结果的时间
[MarshalAs(UnmanagedType.I4)]
public Int32 nChannel;  //DSP设备的通道号
[MarshalAs(UnmanagedType.I4)]
public Int32 nIn;       //进人数
[MarshalAs(UnmanagedType.I4)]
public Int32 nOut;      //出人数
[MarshalAs(UnmanagedType.R4)]
public Single fInSpeed;				//进速度
[MarshalAs(UnmanagedType.R4)]
public Single fOutSpeed;
[MarshalAs(UnmanagedType.I4)] //出速度
public Int32 nZoneNum;				//区域人数
};

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate IntPtr VT_DSP_start_service(ProcessDelegate callback, int lPort);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void VT_DSP_stop_service(IntPtr handle);

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public unsafe delegate void ProcessDelegate(tagDspData dsinfo, IntPtr pData);
public static ProcessDelegate callback;

//载入dll,且获取函数指针
hLib = LoadLibrary("DspProxySDK.dll");
IntPtr api = GetProcAddress(hLib, "VT_DSP_start_service");
Type t = typeof(VT_DSP_start_service);
vt_start = (VT_DSP_start_service)Marshal.GetDelegateForFunctionPointer(api, t);

api = GetProcAddress(hLib, "VT_DSP_stop_service");
t = typeof(VT_DSP_stop_service);
vt_stop = (VT_DSP_stop_service)Marshal.GetDelegateForFunctionPointer(api, t);

ProcessDelegate pdele = new ProcessDelegate(lpSnapFunc);

//启动函数, 将回调函数指针传给dll
WTS_CURRENT_SERVER_HANDLE = vts(pdele, (int)8560);

public unsafe void lpSnapFunc(tagDspData dsinfo, IntPtr pData){.....}


调试要点: 注意回调原型中的 “stdcall” [ typedef void (__stdcall *CALLBACK_recv_front_data)(DspData data,void* pData); ] 由于c++中默认是cdecl方式,很容易习惯性把c#上的委托也设置成cdecl方式,但是此处原型中明确要求用stdcall方式。

由于未深入理解网上大神们的说法, 把回调函数的第一个参数定义为ref tagDspData dsinfo , 或者定义为 IntPtr, 在根据获得的引用或者地址去组建结构, 结果一直被一个错误困扰" 尝试读取或写入受保护的内存。这通常指示其他内存已损坏",此处磕头谢罪,, 真是太不应该了。

深深觉得,要想成为高级码农,不能只靠baidu google,不能做无头苍蝇,还要加入自己的思想,有自己的判断,基础知识永远是自己的指路明灯,而不是人云亦云,否则,连人家说什么都无法听明白。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: