windows的加载dll

windows的加载dll


隐式加载

  • 寻找 dll由系统控制
  • 一般会在exe同级目录放着

这个一般没有太多坑,所以,可以慢慢探索


显式加载

  • 加载路径自由选择

注意

踩过的坑:
  1. dll 内容没有改变
  • 如果网络传输过,最好打包传输
  1. dll 加载失败:126
    126真的一直在报。
  • 这种有几种原因: 原因1: 自己路径不对
  • 如果不是自己的路径不对:就这个dll还依赖其他的dll
  • 如果其他dll都全了,但是依然还是126。
    • 就需要设定工作目录。 这是windows本身的机制问题。
    • windows搜索工作目录会先在工作目录下搜索看看能不能找到。
稳妥做法:
  1. 将加载的dll 以及 它依赖的 dll 全部放在一个 工作目录中
  2. load的时候 一定要 设定工作目录(绝对路径)

显式加载的小例子

这个例子基于原来封装某厂商SDK的时候,自己在家写的小栗子。可能很捡漏。

1. 载入dll

头文件声明
// type
# ifdef _WIN32
using Handler = HMODULE;
using FuncPtr = FARPROC;
#endif

class CIMOSLoader
{
public:
	CIMOSLoader(const std::string& strName);
	virtual ~CIMOSLoader();

	bool Load();
	bool UnLoad();

	bool GetFunctionPtr(const std::string& strFunc, FuncPtr& ptrFuc);
	bool GetFunctionPtr(const char* strFunc, FuncPtr& ptrFuc);

	inline bool IsLoad() const { return (m_handler != nullptr); }
private:
	bool loadLibrary();
	bool unloadLibrary();

private:
	std::string m_Name;
	Handler m_handler;
	unsigned int m_error;
};
载入dll 的实现
  • 最好传进去是绝对路径
  • 备份和回复工作目录的原因:
    • 为了载入不同路径的dll,(打开你的游戏目录下就看到了各种目录里的dll)
bool CIMOSLoader::loadLibrary()
{
	std::string str = m_Name;

	//备份当前工作目录
	char szCurDir[MAX_PATH] = { 0 };
	GetCurrentDirectory(sizeof(szCurDir), szCurDir);

	int nLen = str.length();
	auto pos = str.find_last_of('\\');
	std::string substr = str.substr(0, pos+1);

	SetCurrentDirectory(substr.c_str());
	m_handler = LoadLibrary(str.c_str());
	if (nullptr == m_handler)
	{
		auto Error = GetLastError();
		m_error = Error;
	}

	//恢复当前工作目录
	SetCurrentDirectory(szCurDir);

	return m_handler != nullptr;
}

获取函数指针

下面的也很简单,主要就是调用windows的GetProcAddress
弄了个重载,主要是为了以后用起来方便

bool CIMOSLoader::GetFunctionPtr(const std::string& strFunc, FuncPtr& ptrFuc)
{
	return GetFunctionPtr(strFunc.c_str(), ptrFuc);
}

bool CIMOSLoader::GetFunctionPtr(const char* strFunc, FuncPtr& ptrFuc)
{
	if (!IsLoad())
	{
		return false;
	}

	FuncPtr pFun = GetProcAddress(m_handler, strFunc);
	if (pFun == nullptr)
	{
		return false;
	}

	ptrFuc = pFun;
	return true;
}

上面就是主要的了,其他的东西就是比较简单的,一并放出来,有种水字数的感觉,还是慢慢水一波

//卸载dll
bool CIMOSLoader::unloadLibrary()
{
	return FreeLibrary((HMODULE)m_handler) != 0;
}

CIMOSLoader::~CIMOSLoader()
{
	UnLoad();
}

bool CIMOSLoader::Load()
{
	if (IsLoad())
	{
		UnLoad();
	}

	if (m_Name.empty())
	{
		return false;
	}

	return loadLibrary();


}

bool CIMOSLoader::UnLoad()
{
	bool ret = true;
	if (IsLoad())
	{
		ret = unloadLibrary();
		if (ret)
		{
			m_handler = nullptr;
		}
	}

	return ret;
}

2. 使用loader获取函数指针

显式获取函数指针之后,就能使用了。所以我们可以封装一层 函数指针,让我们用起来比较简单点。

声明
//声明自己的函数指针        这边的是sdk的
using PFunc_Initiate = decltype(IMOS_Initiate)*;
using PFunc_SetOption = decltype(IMOS_SetOption)*;
using PFunc_CleanUp = decltype(IMOS_CleanUp)*;
//    ......   下面实际上还要加很多,
class IMOSFuntor
{
public:
	IMOSFuntor(const std::string& strSDKName, const std::string& strXPName);
	~IMOSFuntor();
	bool Init();
	bool InitSDK_Func();


private:
	std::unique_ptr<CIMOSLoader> m_pImosSdk;


public:
	PFunc_Initiate m_pInitiate{ nullptr };
	PFunc_SetOption m_pSetOption{ nullptr };
	PFunc_CleanUp m_pCleanUp{ nullptr };
	PFunc_Encrypt m_pEncrypt{ nullptr };
	// 上面声明多少,这里定义多少
获取函数指针

这里获取指针的时候,我就直接用了一个map,用了指针的指针?(主要我是不想一个一个判断) 其实你也可以直接在声明用map,

bool IMOSFuntor::InitSDK_Func()
{
	m_pImosSdk->Load();
	if (!m_pImosSdk->IsLoad())
	{
		return false;
	}

	std::map<std::string, FuncPtr*> mapFunc;
	{
		mapFunc.insert(std::make_pair("IMOS_Initiate", reinterpret_cast<FuncPtr*>(&m_pInitiate)));
		mapFunc.insert(std::make_pair("IMOS_SetOption", reinterpret_cast<FuncPtr*>(&m_pSetOption)));
		mapFunc.insert(std::make_pair("IMOS_CleanUp", reinterpret_cast<FuncPtr*>(&m_pCleanUp)));
		mapFunc.insert(std::make_pair("IMOS_Encrypt", reinterpret_cast<FuncPtr*>(&m_pEncrypt)));
	}

	for (auto it = mapFunc.begin(); it != mapFunc.end(); ++it)
	{
		if (!m_pImosSdk->GetFunctionPtr(it->first, *(it->second)))
		{
			printf("IMOSFuntor.Init: 获取 %s 地址失败.\n", it->first.c_str());
			return false;
		}
	}

	return true;
}

然后就能直接用IMOSFuntor里面的函数指针了。这样分割在多层,主要是,可能会跨平台,如果跨平台的话,就该更底层的loader。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值