当码农的第一篇博客

工作的时间越长越感受到时光的飞逝,越感受到自己的不足,时刻保持严谨的态度非常重要。

最近做一个项目需要使用对方用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,不能做无头苍蝇,还要加入自己的思想,有自己的判断,基础知识永远是自己的指路明灯,而不是人云亦云,否则,连人家说什么都无法听明白。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值