这个东西花了我好长时间才搞好,编译错误、连接错误一大堆,主要是那个error LINK2019:无法解析外部符号,试了好多次才发现是C调用C++链接库是符号不匹配,因为编译时C编译和C++编译对函数名的处理是不一样的,导致无法找到外部符号。这里把解决方法提一下。
这里主要参考了这两篇文章:C跟C++之间库的互相调用 - C++ (http://www.it2down.com/it-cpp/658024.htm) 和 C++调用C函数(http://blog.youkuaiyun.com/imcainiao11/article/details/7369447) 。由于C调用C++库和C++调用C库不一样,不能够简单添加extern “C”加以解决,需要对C++驱动库进行封装,即建立c++文件和头文件如下:
注意:函数名称及类型定义需要符合win32.c中需求。
注意这里的头文件usb2can.h的函数声明部分需要用extern “C”进行处理,C++文件可以不处理,调用C++编译的动态链接库的部分均在这个CPP文件中。将这两个文件加入CanFestival-3的头文件和源文件中,同时将库文件加入工程中,如下图所示:
注意头文件的目录要添加到属性中来
在win32.c中添加usb2can.h,同时定义#define NOT_USE_DYNAMIC_LOADING,再做出下列修改:即将CALLBACK去掉
// typedef UNS8 (CALLBACK* CANRECEIVE_DRIVER_PROC)(void* inst, Message *m);
// typedef UNS8 (CALLBACK* CANSEND_DRIVER_PROC)(void* inst, const Message *m);
// typedef void* (CALLBACK* CANOPEN_DRIVER_PROC)(s_BOARD *board);
// typedef int (CALLBACK* CANCLOSE_DRIVER_PROC)(void* inst);
// typedef UNS8 (CALLBACK* CANCHANGEBAUDRATE_DRIVER_PROC)(void* fd, char* baud);
typedef UNS8 (* CANRECEIVE_DRIVER_PROC)(void* inst, Message *m);
typedef UNS8 (* CANSEND_DRIVER_PROC)(void* inst, const Message *m);
typedef void* (* CANOPEN_DRIVER_PROC)(s_BOARD *board);
typedef int (* CANCLOSE_DRIVER_PROC)(void* inst);
typedef UNS8 (* CANCHANGEBAUDRATE_DRIVER_PROC)(void* fd, char* baud);
在can_driver.h中做下列修改:即注释掉驱动函数声明(在usb2can.h中代替)
// UNS8 DLL_CALL(canReceive)(CAN_HANDLE, Message *)FCT_PTR_INIT;
// UNS8 DLL_CALL(canSend)(CAN_HANDLE, Message const *)FCT_PTR_INIT;
// CAN_HANDLE DLL_CALL(canOpen)(s_BOARD *)FCT_PTR_INIT;
// int DLL_CALL(canClose)(CAN_HANDLE)FCT_PTR_INIT;
// UNS8 DLL_CALL(canChangeBaudRate)(CAN_HANDLE, char *)FCT_PTR_INIT;
编译即可生成库文件:CanFestival-3.lib CanFestival-3.dll。对于需要这个库的应用工程中,需要在属性-》配置属性-》VC++目录中的库目录添加这两个库的所在目录以及头文件所在目录。
编译这个工程,若遇到1>win32test.obj : error LNK2001: 无法解析的外部符号 __nodeguardError这样的错误,需要打开CanFestival-3.def,添加_nodeguardError符号(注意前面只有一个下划线),重新编译即可。运行时exe文件和库文件要在同一个目录下。
后记:将CanFestival集成到MFC界面中,利用MFC界面进行控制
需要做的不多,首先将对象字典的源文件和头文件添加到工程中,将Canfestival的头文件复制到工程目录(便于管理)并添加到工程附加目录中如下图所示:
新建Master.c和Master.h文件,主要用于管理Canfestival的回调函数,也添加到工程中。将工程中的C文件(主要是OD源文件和Master.c)的属性改成不使用预编译头,以免出现错误。将Canfestival相关的头文件添加到cpp文件头部,并用extern “C”{}处理一下。最后将调用的库文件(CanFestival-3.lib)添加到工程中,如下图所示:
下面就可以在该cpp文件中调用CanFestival的函数了。注:图中的CanFestival-3项目不是必须的,这里只是为了方便查看修改,将原来的工程复制过来,并添加到这里。