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

40 篇文章 2 订阅

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

 

 

自己实现导出符号

实现功能:
源文件可以在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"
#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

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++程序员Carea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值