理论上DLL模块内部代码是不能自己卸载自己的,因为一旦DLL被FreeLibrary后,当前运行自身代码空间就为非法内存了。
但在某些特殊场合,需要实现这种功能。
例如,DLL导出某纯虚接口指针IExample*,存在一个IExample::Delete方法用于销毁当前对象。希望在销毁所有对象实例后,自动卸载DLL。
class IExample
{
public:
void Delete() = 0;
}
void CExample::Delete()
{
delete this;
// 希望在这里自动卸载DLL
}
但是实现Delete函数的代码位于DLL模块中,直接调用FreeLibrary将导致FreeLibirary函数执行后返回到已经被卸载的代码空间,造成内存访问错误。那么是不是就没有办法解决这个问题了呢?正规的方法行不通时,可以考虑一些旁门左道的做法。
第一种方法:
利用现在很常见的远程进程代码注入技术,这里实际上是注入自身进程。先利用VirtualAlloc分配一块代码内存,将然后将卸载代码复制到内存中,再已该地址作为入口创建一个线程,这种方式确定就是比较麻烦,而且分配的临时内存也存在难以释放的问题。
第二种方法:
不分配内存,直接创建一个以FreeLibrary函数为入口的线程,hModule为参数,让它完成调用FreeLibrary
::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FreeLib