不得不佩服ACE的跨平台强大之处
如果你需要在Windows下创建dll项目供其他项目使用。
你创建dll项目的代码要导出才能被外部访问,这个是由于Windows的动态链接库默认访问级别为私有导致的,所以只有导出的接口才会被外部访问。
当你打算导出的时候只需要使用ACE自带的导出宏即可:
使用ACE导出符号头文件
头文件应该像这个样子:
#ifndef CONFIGLOADER_H
#define CONFIGLOADER_H
#include "ace/Log_Msg.h"
class ACE_Export ConfigLoader
{
public:
ConfigLoader(void);
~ConfigLoader(void);
void load_from_file(void);
void load_from_db(void);
};
#endif
源文件正常,无需任何变动:
/************************************************************************/
/* 配置加载类 */
/************************************************************************/
#include "ConfigLoader.h"
ConfigLoader::ConfigLoader(void)
{
}
ConfigLoader::~ConfigLoader(void)
{
}
void ConfigLoader::load_from_db(void)
{
ACE_DEBUG((LM_DEBUG,"ConfigLoader::load_from_db(void) run"));
}
void ConfigLoader::load_from_file(void)
{
ACE_DEBUG((LM_DEBUG,"ConfigLoader::load_from_file(void) run"));
}
但是我发现当有继承关系的时候,尤其是基类是抽象基类但也要导出的时候,比如有virtual函数的时候这种方式就不行了,要用下面的这种方式(单独指定导出某个具体的函数,而不是整个类):
#ifndef COMMUNICATER_H
#define COMMUNICATER_H
#include "ace/ACE_export.h"
class Communicater
{
public:
ACE_Export Communicater(void);
ACE_Export virtual void run_collect() = 0;
ACE_Export virtual ~Communicater(void);
};
#endif
ACE的等价代码
#ifndef COMMUNICATER_H
#define COMMUNICATER_H
//#include "ace/ACE_export.h"
#ifdef COMMUNICATER_EXPORTS
#define COMMUNICATER_API __declspec(dllexport)
#else
#define COMMUNICATER_API __declspec(dllimport)
#endif
class Communicater
{
public:
COMMUNICATER_API Communicater(void);
COMMUNICATER_API virtual void run_collect() = 0;
COMMUNICATER_API virtual ~Communicater(void);
};
#endif
反正就是要对每个接口单个导出,而不是导出类,不知道为何
即可编译生成dll,供其他项目使用,多棒!
具体操作参考:http://blog.csdn.net/calmreason/article/details/6989390中官方网站教程(主要是VC++工程的“项目引用”功能 )
自己实现导出符号
由于ACE的导出符号多少针对ACE特定的要求,而且针对不同平台其导出宏我们不好确定是哪一个,所以,为了简单起见,自己也模仿定义了自己的导出符号:
头文件
SCP_Export.h头文件
#ifndef SCP_EXPORT_H
#define SCP_EXPORT_H
#ifdef WIN32 //for windows
#ifdef SCP_EXPORTS //for windows generate dll,you have to define SCP_EXPORTS in your preprocessor
#define SCP_Export __declspec(dllexport)
#else
#define SCP_Export //for windows as source file
#endif
#else //for Linux
#ifdef SCP_EXPORTS //for Linux as source file
#define SCP_Export
#else
#define SCP_Export //for Linux generate dll
#endif
#endif
#endif
使用自定义导出符号:
无论你是想以源文件方式使用自己的类,还是打算将自己的类放到dll里面,你都只需要做两件事(1)(2)
(1)可以在自己的类的头文件中包含SCP_Export.h头文件
(2)在有可能会被导出的地方加上SCP_Export声明
(3)只有一种情况:windows下,你打算把自己的类放到dll中,这时候你需要在preprocessor里加上SCP_EXPORTS预编译符号,表示你的类在dll里面是可以被外部的程序调用的。
在普通类使用导出符号示例:
CollectorInfor.h
/************************************************************************/
/* 采集器实体类 */
/************************************************************************/
#ifndef COLLECTORINFOR_H
#define COLLECTORINFOR_H
#include <string>
using namespace std;
#include "ace/INET_Addr.h"
#ifndef SCP_EXPORT_H
#include "SCP_Export.h"
#endif
class SCP_Export CollectorInfor
{
public:
CollectorInfor(void);
~CollectorInfor(void);
u_short get_port_number (void) const;
const char *get_host_name (void) const;
const string to_string(void) const;
private:
ACE_INET_Addr local_addr;
};
#endif
包含虚函数的基类使用导出符号的示例:
#ifndef COMMUNICATER_H
#define COMMUNICATER_H
#include <vector>
using namespace std;
#include "ace/INET_Addr.h"
#include "ace/Task.h"
#ifndef COMMUNICATERINFOR_H
#include "CommunicaterInfor.h"
#endif
#ifndef SCP_TYPE_H
#include "scp_type.h"
#endif
#ifndef SCP_EXPORT_H
#include "SCP_Export.h"
#endif
#ifndef MESSAGEQUEUE_H
#include "MessageQueue.h"
#endif
class Communicater
{
public:
//派生类必须实现的方法
SCP_Export virtual void run_collect(void) = 0;
SCP_Export const CommunicaterInfor& get_infor(void);
//派生类必须实现的方法
SCP_Export Communicater(const CommunicaterInfor&);
SCP_Export virtual ~Communicater(void);
protected:
vector<id_type> has_collector_id_;
const CommunicaterInfor& infor_;
};
//派生类必须实现的方法
extern "C" SCP_Export Communicater* CreateCommunicater(CommunicaterInfor&);
#endif
派生类使用导出函数:
Communicater_103.h
#ifndef COMMUNICATER_103_H
#define COMMUNICATER_103_H
#include <string>
using namespace std;
#include "ace/Log_Msg.h"
#include "ace/Event_Handler.h"
#include "ace/Date_Time.h"
#include "ace/WIN32_Proactor.h"
#include "ace/INET_Addr.h"
#include "ace/SOCK_Dgram.h"
#include "ace/Message_Block.h"
#include "ace/OS.h"
#include "ace/Proactor.h"
#include "ace/Task.h"
#include "ace/Asynch_Acceptor.h"
#include "SCP_Export.h"
#ifndef COMMUNICATER_H
#include "Communicater.h"
#endif
#ifndef SCP_TYPE_H
#include "scp_type.h"
#endif
#ifndef CONFIGLOADER_H
#include "ConfigLoader.h"
#endif
#ifndef GLOBAL_H
#include "global.h"
#endif
/*8 链路传输过程
8.1 客户机/服务器模型
系统采用标准TCP/IP 的客户机-服务器模型进行通信。应用服务数据单元(ASDU)报
文使用高可靠性的TCP 数据流传输,主站(监控/远动)作为服务器端在约定的1048(418H)
号TCP 端口上被动侦听等待,子站(保护/测控装置)作为客户端主动发起连接。TCP 传输
的数据保证可靠性但无报文边界,因而需要在接收方进行适当的解粘包处理。
为了适应多主站情况,系统通过辅助UDP 链路实现主站IP 的动态识别。在此辅助UDP
链路中,子站作为服务器端在约定的1032(408H)号UDP 端口被动等待接收,主站作为客
户端主动发送UDP 广播报文。子站接收UDP 报文后获得主站IP 地址信息可用来发起TCP
连接,同时可取得时间信息进行时钟同步。
*/
/**
* @class UDPSender
*
* @brief The class will be created by <main>.
*/
class UDPSender : public ACE_Handler
{
public:
UDPSender (void);
~UDPSender (void);
//FUZZ: disable check_for_lack_ACE_OS
///FUZZ: enable check_for_lack_ACE_OS
int open (const ACE_TCHAR *host, u_short port);
protected:
// These methods are called by the freamwork
/// This is called when asynchronous writes from the dgram socket
/// complete
virtual void handle_write_dgram (const ACE_Asynch_Write_Dgram::Result &result);
private:
/// Network I/O handle
ACE_SOCK_Dgram sock_dgram_;
/// wd (write dgram): for writing to the socket
ACE_Asynch_Write_Dgram wd_;
};
class Communicater_103 : public Communicater ,public ACE_Service_Handler
{
public:
Communicater_103(const CommunicaterInfor&);
~Communicater_103(void);
void run_collect(void);
private:
UDPSender udp_sender;
ACE_Asynch_Read_Stream reader_;
};
extern "C" SCP_Export Communicater* CreateCommunicater(CommunicaterInfor&);
#endif
名称空间中的函数和类的导出:
#ifndef GLOBAL_H
#define GLOBAL_H
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#ifndef SCP_EXPORT_H
#include "SCP_Export.h"
#endif
namespace global
{
int SCP_Export string_to_id(const string& dll_name);
string SCP_Export to_hex_string(const string& temp_string);
string SCP_Export long_long_to_string(long long id);
template<typename Result,typename Para>
Result SCP_Export lexical_cast(Para para)
{
stringstream ss;
ss<<para;
Result result;
ss>>result;
return result;
}
template<typename T>
void SCP_Export print(T begin,T end)
{
while(begin != end)
{
cout<<*begin++<<" ";
}
cout<<endl;
};
}
#endif
在编译环境中添加导出符号宏:
有了以上代码文件的准备,只需要在你用到这些代码的项目中添加导出宏即可使用:右键项目名》属性》Configuration Properties》C/C++》Preprocessor》Preprocessor Definitions》添加宏SCP_EXPORTS
这样你的项目就可以生成一个dll供其他项目使用,在其他项目中只需要包含你定义的头文件,并引用此项目即可,具体见:http://blog.csdn.net/calmreason/article/details/6989390