windows动态链接库开发教程1

本章节的内容来自《Windows核心编程》第五版第19章。详情请细看此书

  1. dll基础
    dll可用于多个程序共享代码,因为如果有多个程序调用同一个dll,这个dll只会被加载到内存一次。这就对线程安全性有了要求。如果保证资源访问的正确性与安全性?这就需要在编写时注意资源的保护和函数中数据资源的存储。一下两点要注意:1>避免使用单一的全局变量,如:int g_nCarNum;这样做所有加载的进程都可以访问他;2>如果访问全局资源,注意加锁、关键段等。

构建dll的步骤:

  1. 头文件:其中包含了待导出的函数原型、结构和符号声明
  2. C/C++源文件,包含头文件中声明的实现
  3. 编译器为每个cpp文件生成.obj文件
  4. 连接器将每个.obj模块合并,从而生成.dll
  5. 如果至少包含了一个函数/变量,则会生成一个.lib文件(lib路径声明在 链接器-> 高级->导入库)。

构建dll模块:
dll模块可以用于导出函数、类、和变量。一般变量我们不会使用,也没有必要。原书中只提供了导出函数的方法,再次我提供两个分别为导出函数和导出类的方法:
首先声明:dll也是有main函数的,只是根据MSDN定义,这个dllmain是可有可无的,下面的第一个程序中我对main函数写了一个示例。
1>导出函数
testFunc.h

#pragma once
#include "iostream"

#ifdef WIN32
#define YCD_EXTERN	extern "C" __declspec(dllexport)
#else
#define YCD_EXTERN	extern "C"
#endif // WIN32

typedef void* YCD_HANDLE;

YCD_EXTERN int MyFun(YCD_HANDLE	hTest, int nStartTime, int nEndtime);

testFun.cpp

#include "test.h"
#include "windows.h"
#include "Psapi.h"
int DllMain(_In_ void* DllHandle,	// DLL 调用模块
	_In_ unsigned long Reason,		// 调用情况
	_In_opt_ void* Reserved)		// reserved
{
	// 在不同情况下都会调用dllmain函数,分别处理;
	switch (Reason)
	{
		// 加载 DLL
	case DLL_PROCESS_ATTACH:
	{
		char lpMainMoudleName[MAX_PATH] = { 0 };
		char lpMessage[MAX_PATH + 64] = { 0 };
		// 获取PID和主模块名;将弹出消息框
		DWORD dwPID = GetCurrentProcessId();
		GetModuleBaseName(GetCurrentProcess(), NULL, lpMainMoudleName, MAX_PATH);
		wsprintf(lpMessage, "Process Name :%s, PID :%u", lpMainMoudleName, dwPID);
		MessageBox(NULL, lpMessage, "testFun.dll", MB_OK);
		break;
	}
	// 新建线程;
	case DLL_THREAD_ATTACH:
	{
		break;
	}
	// 线程退出
	case DLL_THREAD_DETACH:
	{
		break;
	}
	// 进程退出,释放DLL
	case DLL_PROCESS_DETACH:
	{
		break;
	}
	default:
		break;
	}
	return true;
}
YCD_EXTERN int MyFun(YCD_HANDLE	hTest, int nStartTime, int nEndtime)
{
	return nEndtime - nStartTime;
}

2> 导出类
externClass.h

#pragma once
#include "iostream"

using namespace std;
#ifdef WIN32
#define YCD_EXTERN	extern "C" __declspec(dllexport)
#else
#define YCD_EXTERN	extern "C"
#endif

class MyClassImpl
{
public:
	MyClassImpl();
	~MyClassImpl();

	int OutPut();
private:

};

YCD_EXTERN class  MyClass
{
public:
	 MyClass();
	~ MyClass();
	int Output();
private:
	MyClassImpl* m_pMyclassImpl;
};

externClass.cpp


/**************************************************************
 *  Filename:    PKLog.cpp
 *  Copyright:   Shanghai Baosight Software Co., Ltd.
 *
 *  Description: create.
 *
 *  @author:     zhaohui
 *  @version     03/13/2008  zhaohui  Initial Version
 *  @version     05/19/2008  zhaohui  change PKLog from dll to lib .
 *  @version     05/26/2008  zhaohui  add conf env read and log out.
 *  @version     05/30/2008  zhaohui  change pugxml to tinyxml.
 *  @version     06/25/2008  caichunlei 添加LogErrMessage接口 .
 *	@version	 09/28/2008	 shenchunfeng 修正配置文件错误引起异常退出的缺陷,修正程序在调入Dll时引起的缺陷,增加能拆分多个日志文件的功能。
 *  @version     01/29/2010  chenzhiquan   将屏幕输出由std::cout改为printf,避免多条输出时发生混乱.
 *  @version     08/29/2010  chenzhiquan   初始化变量.
**************************************************************/
#include "pklog/pklog.h"

#include <ace/FILE.h>
#include <ace/Dirent.h>
#include <ace/Guard_T.h>
#include <ace/streams.h>
#include <ace/Thread_Mutex.h>
#include "ace/OS_NS_stdio.h"
#include "ace/OS_NS_sys_stat.h"
#include "ace/OS_NS_sys_time.h"
#include "tinyxml/tinyxml.h"
#include "log_to_file.h"
#include <sstream>
#include "PKLogImpl.h"

#define MAX_LOG_SIZE						4096

#define MAXLOGNUM 1000

#define PK_SHORTFILENAME_MAXLEN			260			// 文件全名称(不含路径)的最大长度
#define PK_LONGFILENAME_MAXLEN			1024		// 文件全路径的最大长度(实际长度受限于操作系统,windows下文件夹长度小于249,文件名全路径长度小于260)

#define DT_SIZE_TIMESTR					24		// strlen("2008-01-01 12:12:12.000") + 1


//CPkLog::CPkLog(CPkLogImp *imp): m_pPkLogImp(imp)
CPKLog::CPKLog()
{
	m_pPKLogImp = new CPKLogImp();
}

CPKLog::~CPKLog()
{
	if (m_pPKLogImp)
	{
		delete m_pPKLogImp;
		m_pPKLogImp = NULL;
	}
}

bool CPKLog::SetLogFileName( const char *szLogFileName )
{
	return m_pPKLogImp->SetLogFileName(szLogFileName);
}

/*
int CPkLog::SwitchLogLevel( int nNewLevel )
{
	//CV_PK_LOGLEVEL_ nOldLevel = m_pPkLogImp->m_nCurrentLogLV;
	//m_pPkLogImp->m_nCurrentLogLV = nNewLevel;
	if (NULL != m_pPkLogImp)
	{
		return m_pPkLogImp->SetLogRecordLevel(nNewLevel);
	}
	else 
	{
		return PK_LOGLEVEL_CRITICAL;
	}
	
}
*/
/*
void CPkLog::SetLogOnMonitor( bool bLogOnMonitor )
{
	if (NULL != m_pPkLogImp)
	{
		m_pPkLogImp->m_bLogOnMonitor = bLogOnMonitor;//该值通过配置文件修改可以发生改变
		m_pPkLogImp->m_bCancelLogOnMonitor = !bLogOnMonitor;
	}
}
*/

//CPkLog PKLog(new CPkLogImp());   //PKLog使用的全局变量名字



/**
 *  记录日志信息.
 *  the same as BBSERROR uses.
 *
 *  @param  -[in,out]  int  nLogLevel: [日志级别]
 *  @param  -[in,out]  const char*  szFormat: [日志内容]
 *  @param  -[in,out]  ...: [不定参数]
 *  @return void.
 *
 *  @version     03/13/2008  zhaohui  Initial Version.
 */
void CPKLog::LogMessage(int nLogLevel, const char *szFormat, ... )
{
	// 不是Notice级别,且或者级别不满足
	if (nLogLevel != PK_LOGLEVEL_NOTICE && !(m_pPKLogImp->m_nCurrentLogBitMap & nLogLevel) )
		return;

	//ACE_Guard<ACE_Thread_Mutex> guard(m_pPKLogImp->m_mutex);

	//日志内容
	char* szbuf = NULL;
	szbuf = new char[MAX_LOG_SIZE];
	if (NULL == szbuf)
		return;
	szbuf[0] = '\0';

	//定义变量指针
	try
	{
		va_list	ap;   
		//初始化ap
		va_start(ap, szFormat);   
		int len = ACE_OS::vsnprintf(szbuf, MAX_LOG_SIZE, szFormat, ap);
		va_end(ap);
	}
	catch (...)
	{
		strcpy(szbuf, "loging,Error Formatting Log Message! ");
	}		

	m_pPKLogImp->WriteLog(nLogLevel, szbuf);

	if (szbuf != NULL)
	{
		delete[] szbuf;
	}
}

/**
 *  记录日志信息.
 *  the same as BBSERROR uses.
 *
 *  @param  -[in,out]  int  nLogLevel: [日志级别]
 *  @param  -[in,out]  const char*  szFormat: [日志内容]
 *  @param  -[in,out]  ...: [不定参数]
 *  @return void.
 *
 *  @version     03/13/2008  zhaohui  Initial Version.
 */
void CPKLog::LogErrMessage(int nErrCode, const char *szFormat, ... )
{
	// 不是Notice级别,且或者级别不满足
	int nLogLevel = PK_LOGLEVEL_ERROR;
	if (nLogLevel != PK_LOGLEVEL_NOTICE && !(m_pPKLogImp->m_nCurrentLogBitMap & nLogLevel) )
		return;

	//ACE_Guard<ACE_Thread_Mutex> guard(m_pPKLogImp->m_mutex);

	//日志内容
	char* szbuf = NULL;
	szbuf = new char[MAX_LOG_SIZE];
	if (NULL == szbuf)
		return;
	szbuf[0] = '\0';

	//定义变量指针
	try
	{
		va_list	ap;   
		//初始化ap
		va_start(ap, szFormat);   
		int len = ACE_OS::vsnprintf(szbuf, MAX_LOG_SIZE, szFormat, ap);
		va_end(ap);
	}
	catch (...)
	{
		strcpy(szbuf, "loging,Error Formatting Log Message! ");
	}		

	m_pPKLogImp->WriteLog(nLogLevel, szbuf);

	if (szbuf != NULL)
	{
		delete[] szbuf;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值