ACE_Export与自定义导出符号(结贴)

来源:互联网 发布:冬不拉调音软件下载 编辑:程序博客网 时间:2024/04/28 16:03

     不得不佩服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) #endifclass  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++工程的“项目引用”功能 )

 

 

自己实现导出符号

实现功能:
源文件可以在Windows应用程序中使用(直接包含源文件即可)
源文件可以在Windows生成动态链接库程序中使用(需在预编译的时候定义宏SCP_EXPORTS)
源文件可以在Linux应用程序中使用(直接包含源文件即可)
源文件可以在Linux生成动态链接库程序使用(直接包含源文件即可)

由于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"#endifclass 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"#endifclass  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

 

 

0 0
原创粉丝点击