动态链接库


一、DLL种类

不使用MFC的win32 DLL和使用MFC的MFC DLL


MFC DLL三种开发方式
1.使用静态链接MFC类库的常规DLL
2.使用动态链接MFC类库的常规DLL
3.MFC扩展DLL。现有MFC类库中的类派生而来的可以重复使用的类。扩展DLL使用MFC的动态链接库版本构建




二、DLL文件组成

DEF文件模块定义语句
1.文件的第一条语句必须是LIBRARY语句。语句后写入DLL名称。
2.文件中的EXPORTS语句用于列出导出的函数名称和为其分配序号值。格式是函数名称后写入@符号和序号值
3.DESCRIPTION语句描述DLL的功能
4.所有以分号开头的行都是注释行



;MFCDLL1.def:Declares the module parameters for the DLL.
LIBRARY "MFCDLL1"
DESCRIPTION "MFCDLL1 windows Dynamic Link Library"
EXPORTS 
Writelog @1



三.函数介绍

1.DLLMain 入口函数

BOOL WINAPI DLLMain(
HINSTANCE hinstDll,//Dll模块的句柄
DWORD fdwReason,//调用函数的来源
LPVOID lpvReserved//预留
);
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
//根据调用DLL的来源完成相应的工作
case DLL_PROCESS_ATTACH:
	//对于每个新进程,初始化一次,如果DLL装载失败,则返回false
case DLL_THREAD_ATTACH:
	//执行线程指定初始化
case DLL_THREAD_DETACH:
	//执行线程指定的清除工作
case DLL_PROCESS_DETACH
	//执行任何需要的清除工作
break;
}
return true;//进程装载入口函数成功完成
}



2.LoadLibrary

DLL映射到进程地址空间
HMODULE LoadLibrary(PCTSTR pszDLLPathName);




3.LoadLibraryEx

https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx


HMODULE LoadLibraryEx(PCTSTR pszDLLPathName,HANDLE hFile,DWORD dwFlags);


4.FreeLibrary

将DLL从进程地址空间中卸载


BOOL FreeLibrary( HMODULE  hInstDll );

5.FreeLibraryAndExitThread

从进程地址空间卸载某DLL的功能,还能退出调用线程
   VOID FreeLibraryAndExitThread(HMODULE hInstDll,DWORD dwExitCode)

6.GetModuleFileName

返回执行文件包含的指定模块的完整路径和文件名
DWORD GetModuleFileName(
HMODULE hModule,//要获取文件名的模块句柄
LPTSTR lpFilename,//接收模块路径的缓冲区的指针
DWORD nSize//缓冲区的大小
);

7.GetModuleHandle

返回模块的模块句柄
HMODULE GetModuleHandle(
LPCTSTR lpModuleName)//要获取句柄的模块的名称地址


8.GetProcAddress

返回导出的DLL函数的地址
FARPROC GetProcAddress(
HMODULE hModule,//DLL模块的句柄
LPCSTR lpProcName);//函数名


四.从动态库中获取位图资源

LoadLibraryEx() 函数加载动态库,EnumResourceNames函数枚举指定类型的资源。


BOOL EnumResourceNames(
HINSTANCE hModule,//指定要枚举资源的可执行文件的模块句柄
LPCTSTR lpszType,//指定要枚举的资源类型
ENUMRESNAMEPROC lpEnumFunc,//指定查找到每个资源后都要执行的回调函数
LONG lParam);//传递给回调函数的用户自定义参数值


回调函数
BOOL CALLBACK EnumResNameProc(
HANDLE hModule,//枚举函数 正在枚举的资源所在的可执行文件的句柄
LPCTSTR lpszType,//正在枚举创建当前进程的模块的资源
LPTSTR lpszName,//当前枚举项的资源名称
LONG lParam);//EnumResourceNames函数LParam参数传进来的用户自定义参数值


DLLAppSampleDlg.cpp:
// 枚举位图
void CDLLAppSampleDlg::OnButtonGetbitmap() 
{
	m_iconList.ShowWindow(SW_HIDE);
	if( (hLibrary = LoadLibraryEx( "MORICONS.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE )) == NULL )
	{
		WriteLog("文件载入错误!");
		return;
	}


	if(!EnumResourceNames(hLibrary,RT_BITMAP,(ENUMRESNAMEPROC)EnumBitmapProcedure,(LPARAM)GetSafeHwnd()))
		WriteLog("列举位图资源停止!");
	FreeLibrary(hLibrary);
}


//显示位图
LRESULT CDLLAppSampleDlg::OnBitmapMessage(WPARAM wParam,LPARAM lParam)
{	
	CStatic* m_Bitmap = (CStatic*)GetDlgItem(IDC_STATIC_BITMAP);
	m_Bitmap->SetBitmap((HBITMAP)wParam);
	WriteLog((const char*)&lParam);
    return 1;
}


DLLAppSample.cpp:
BOOL CALLBACK EnumBitmapProcedure(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
{
	HBITMAP bitmap = LoadBitmap((HINSTANCE)hModule,lpszName);
	if (true)
	{
		SendMessage((HWND)lParam, WM_BITMAP_MESSAGE, (LPARAM)bitmap, (WPARAM)lpszName);	
		return FALSE;
	}
}




五.枚举模块中的所有图标

DLLAppSampleDlg.cpp:
// 枚举图标
void CDLLAppSampleDlg::OnButtonGetallicon() 
{
	ResetContent();	
	HINSTANCE  hLibrary;
	if( (hLibrary = LoadLibraryEx( "MORICONS.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE )) == NULL )
	{
		WriteLog("文件载入错误!");
		return;
	}


	if(!EnumResourceNames(hLibrary,RT_GROUP_ICON,(ENUMRESNAMEPROC)EnumIconProcedure,(LPARAM)GetSafeHwnd()))
		WriteLog("列举图标资源停止!");


	FreeLibrary(hLibrary);


	CString log;
	log.Format("DLL中共包含%d个图标资源!", m_iconList.GetItemCount());
	WriteLog(log);
}


// 显示图标
LRESULT CDLLAppSampleDlg::OnIconMessage(WPARAM wParam,LPARAM lParam)
{
	int iIconRet = imagelist.Add((HICON)wParam); 
	if (iIconRet!=-1)
	{
		m_iconList.SetImageList (&imagelist,LVSIL_SMALL);
		int iIndex = m_iconList.GetItemCount();
		m_iconList.InsertItem(iIndex, (const char*)&lParam, iIndex);
	}
    return 1;
}


DLLAppSample.cpp:
BOOL CALLBACK EnumIconProcedure(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
{
	HICON icon = LoadIcon((HINSTANCE)hModule,lpszName);
	SendMessage((HWND)lParam, WM_ICON_MESSAGE, (LPARAM)icon, (WPARAM)lpszName);	
	return TRUE;
}



六.使用模块对话框资源 

AfxSetResourceHandle函数可以切换要使用的资源所在的实例,从而实现调用其他模块中的对话框资源的功能


AfxSetResourceHandle(
HINSTANCE hInstResource);//指定应用程序要载入的资源所在的EXE或DLL文件的模块句柄或实例


AfxGetResourceHandle函数保存原来的实例句柄。


//使用模块对话框资源
void CDLLAppSampleDlg::OnButtonGetdialog() 
{
	HINSTANCE m_hInstOld=AfxGetInstanceHandle();
	HINSTANCE m_hInstNew = LoadLibrary("RedDLL.exe"); 
	if (m_hInstNew == NULL)  WriteLog("装载可执行文件失败!");	 
	AfxSetResourceHandle(m_hInstNew);
	CDialog* dlg = new CDialog();
	if (dlg->Create(IDD_ABOUTBOX))	dlg->ShowWindow(SW_SHOW);
	AfxSetResourceHandle(m_hInstOld);
}




七.替换应用程序的对话框资源

1.使用 LoadLibrary函数装载替换内容的可执行文件
2.使用 FindResource函数和LoadResource函数查找定位并装载用于替换对话框资源
3.调用 LockResource函数获取对话框资源的数据指针
4.使用 BeginUpdateResource函数打开要更新的资源
5.使用 UpdateResource函数将用于替换的对话框资源复制到要替换的对话框资源
6.使用 EndUpadteResource函数完成替换


void CDLLAppSampleDlg::OnButtonReplacedialog() 
{
	HRSRC hRes, hResLoad; 
	HANDLE hExe, hUpdateExe; 
	char *lpResLock;    
	BOOL bResult; 
 
	hExe = LoadLibrary("RedDLL.exe"); 
	if (hExe == NULL)  WriteLog("装载可执行文件失败!");		
 
	hRes = FindResource((HINSTANCE)hExe, MAKEINTRESOURCE(IDD_ABOUTBOX), RT_DIALOG); 
	if (hRes == NULL) WriteLog("无法查找要替换的资源!");
	 
	hResLoad = (HRSRC)LoadResource((HINSTANCE)hExe, hRes);  
	if (hResLoad == NULL)	WriteLog("无法装载对话框!"); 	


	lpResLock = (char*)LockResource(hResLoad); 
	if (lpResLock == NULL)  WriteLog("无法锁定对话框!"); 


 
	hUpdateExe = (HRSRC)BeginUpdateResource("GreenDLL.exe", FALSE); 
	if (hUpdateExe == NULL)  WriteLog("无法打开要写入资源的文件!"); 


	bResult = UpdateResource((HINSTANCE)hUpdateExe, RT_DIALOG, MAKEINTRESOURCE(IDD_ABOUTBOX),  
     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), lpResLock, 
     SizeofResource((HINSTANCE)hExe, hRes));  
	if (bResult == FALSE)  WriteLog("替换资源失败!"); 
	
	if (!EndUpdateResource(hUpdateExe, FALSE)) WriteLog("不能写入对文件的修改!");	
 
	if (!FreeLibrary((HINSTANCE)hExe)) 	WriteLog("释放文件失败!"); 	
}



八.屏蔽键盘Power键

通过回调函数,可以屏蔽系统按键的处理。通过底层键盘钩子的回调函数来屏蔽POWER键的方法。由于POWER键是底层键盘按键,因此
需要使用底层键盘钩子回调函数
LRESULT CALLBACK LowLevelKeyboardProc(
int nCode,//指定钩子处理代码 
WPARAM wParam,//指定键盘信息的标志符
LPARAM lParam);//定向KBDKKHOOKSTRUCT结构的指针,其中存储按下的按键的信息




Power键的按键代码是1,因此将其传入DLL中的StartShieldKey()函数后可以屏蔽Power按键。
//屏蔽键盘POWER键
void CDLLAppSampleDlg::OnButtonDisablePower() 
{
	DWORD dwVerKey[] = {0x00000001};
	DWORD dwConKey[] = {0};
    int nLength = sizeof(dwVerKey) / sizeof(DWORD);
    if (StartShieldKey(dwVerKey, dwConKey, nLength)) WriteLog("已经屏蔽POWER键");
	else WriteLog("屏蔽POWER键失败");
}




ShieldKeyBordSample.dll:
// 底层键盘钩子回调函数
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{    
     if (nCode == HC_ACTION)	// 禁用键盘的某个按键
     {
         KBDLLHOOKSTRUCT* pHookStruct = (KBDLLHOOKSTRUCT*)lParam;	// 取出钩子结构
		 LPDWORD tmpVirKey = m_lpdwVirtualKey;		// 取出要屏蔽的键的列表指针
         for (int i = 0; i < m_nLength; i++)
         {			 
			 if (*m_lpdwContentKey++ == 1)
			 {
				 DWORD dwAltKey = 32;
				 if ((pHookStruct->vkCode == *tmpVirKey++)
					 && (pHookStruct->flags == dwAltKey)) return TRUE;
			 }
			 if (pHookStruct->vkCode == *tmpVirKey++) return TRUE;
         }
     }
     return CallNextHookEx(m_hHook, nCode, wParam, lParam);	// 如果不是要屏蔽的按键则传给系统中的下一个钩子
}
// 启动屏蔽
SHIELDKEYBORDSAMPLE_API bool StartShieldKey(LPDWORD lpdwVirtualKey, LPDWORD lpdwContentKey, int nLength)
{
     if (m_hHook != NULL) return StopShieldKey();
     m_lpdwVirtualKey = (LPDWORD)malloc(sizeof(DWORD) * nLength);
	 m_lpdwContentKey = (LPDWORD)malloc(sizeof(DWORD) * nLength);
     LPDWORD tmpVirKey = m_lpdwVirtualKey;// 要屏蔽的底层键盘;
	 LPDWORD tmpConKey = m_lpdwContentKey;// 要屏蔽的底层键盘组合键;
     for (int i = 0; i < nLength; i++)
     {
         *tmpVirKey++ = *lpdwVirtualKey++;
		 *tmpConKey++ = *lpdwContentKey++;
     }


	 m_nLength = nLength;     
     // 安装底层键盘钩子
     m_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, m_hInstance, NULL);
     if (m_hHook == NULL) return FALSE;
     return TRUE;
}


// 停止屏蔽
SHIELDKEYBORDSAMPLE_API bool StopShieldKey()
{
     if (UnhookWindowsHookEx(m_hHook) == 0) return FALSE;
     m_hHook = NULL;
     return TRUE;
}





猜你喜欢

转载自blog.csdn.net/greless/article/details/77715511