C++动态链接库DLL文件的加载

Stands for “Dynamic Link Library.” A DLL (.dll) file contains a library of functions and other information that can be accessed by a Windows program. When a program is launched, links to the necessary .dll files are created. If a static link is created, the .dll files will be in use as long as the program is active. If a dynamic link is created, the .dll files will only be used when needed. Dynamic links help programs use resources, such as memory and hard drive space, more efficiently.

1、如何从DLL中获得资源(MFC DLL)

LoadLibrary+::LoadString/::LoadIcon/::LoadBitmap

    HINSTANCE hModule = LoadLibrary(_T("test.dll"));
    HBITMAP hBitmap = LoadBitmap(hModule,MAKEINTRESOURCE(1002));

	if (hBitmap != NULL)
	{
		//设置位图
		CBitmap bmp;
		bmp.Attach(hBitmap);
		CRect rect;
		GetClientRect(rect);
		CDC* pDC = GetDC();
		CDC memDC;
		memDC.CreateCompatibleDC(pDC);
		memDC.SelectObject(&bmp);
		pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), 
			&memDC, 0, 0, SRCCOPY);
		bmp.Detach();
		memDC.DeleteDC();
	}

2、如何使用DEF文件导出函数

int fnTest(void);

如何使用关键字_declspec (dllexport)导出函数

#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif
extern "C" TEST_API int fnTest(void);

3、如何显式链接DLL

//加载DLL
	HINSTANCE hModule = LoadLibrary(_T("test.dll"));
	if (hModule == NULL) return;
	typedef int (_cdecl *FUNTEST)(void);
	FUNTEST pfnTest;
	//获得导出函数的地址
	pfnTest = (FUNTEST)GetProcAddress(hModule, "fnTest");
	//调用导出函数
	if (pfnTest != NULL)
	{
		int nValue = (*pfnTest)();
		CString strMessage = _T("");
		strMessage.Format(_T("%d"), nValue);
		AfxMessageBox(strMessage);
	}
	else
	{
		int n = GetLastError();
		TRACE(_T("LastError:%d\n"), n);	
	}
	//释放DLL
	FreeLibrary(hModule);

4、如何隐式链接DLL

//DLL导出函数的头文件
#include "Test.h"
//DLL的导入库lib文件
#pragma comment(lib, "test.lib")
//直接调用DLL的导出函数
int nValue = fnTest();

5、如何在DLL中共享数据

#pragma data_seg(".SharedData")
int nCount = 0;
#pragma data_seg()
int GetCount(){
	return nCount;
}
EXPORTS:	GetCount
SECTIONS:	.SharedData SHARED
//DLL导出函数的头文件
#include "Test.h"
//DLL的导入库lib文件
#pragma comment(lib, "test.lib")
int nCount = GetCount();

6、如何在DLL中使用对话框资源(MFC DLL)

//改变模块的状态
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CTestDlg dlg;
dlg.DoModal();
//DLL的导入库lib文件
#pragma comment(lib, "test.lib")
void ShowDialog();

7、如何在MFC扩展DLL中导出类

#include "ExtClass.h"
#include "DeskTopTool.h"
//DLL的导入库lib文件
#pragma comment(lib, "test.lib")
……
	CExtClass ExtClass;
	ExtClass.Test();

8、DLL文件路径

Dynamic-Link Library Search Order

8.1 方式一、采用LoadLibraryEx

若DLL不在调用方的同一目录下,可以用LoadLibrary(L"DLL绝对路径")加载。但若调用的DLL内部又调用另外一个DLL,此时调用仍会失败。解决办法是用LoadLibraryEx:

LoadLibraryEx("DLL绝对路径", NULL,LOAD_WITH_ALTERED_SEARCH_PATH);

通过指定LOAD_WITH_ALTERED_SEARCH_PATH,让系统DLL搜索顺序从DLL所在目录开始。

8.2 方式二、采用SetCurrentDir

跨目录调用dll,你应该这样
1 用GetCurrentDir保存当前的工作目录
2 用SetCurrentDir将当前的工作目录,设置为你的DLL所在的路径,需要使用绝对路径
3 用LoadLibrary你的DLL
4 使用SetCurrentDir恢复到原来的工作路径

TCHAR chCurDir[MAX_PATH] = {0};
GetCurrentDirectory(MAX_PATH, chCurDir);
SetCurrentDirectory(_T("E:\\test\\"));
m_hDLL = LoadLibrary(_T("MyTest.dll"));
SetCurrentDirectory(chCurDir);

8.3 dll的加载顺序总结

  1. EXE所在目录;
  2. 当前目录GetCurrentDirectory();
  3. 系统目录GetSystemDirectory();
  4. WINDOWS目录GetWindowsDirectory();
  5. 环境变量 PATH 所包含的目录。

所以使用loadlibrary加载dll使用的路径,但是这个函数会忽略这个路径,只会按既定规则加载dll。所以如果要加载指定目录的dll,可以用上述两个解决方案。

8.4 LoadLibraryEx函数参数说明

LoadLibraryExA function

HMODULE LoadLibraryExA(
  [in] LPCSTR lpLibFileName,
       HANDLE hFile,
  [in] DWORD  dwFlags
);
//Load the FMAPI DLL
hLib = ::LoadLibraryEx(L"fmapi.dll", NULL, NULL);    
if ( !hLib )
{
      wprintf(L"Could not load fmapi.dll, Error #%d.\n", GetLastError());
      return;
}

LoadLibraryEx装载指定的动态链接库,并为当前进程把它映射到地址空间。一旦载入,就可以访问库内保存的资源。

  1. 它的返回值,Long,成功则返回库模块的句柄,零表示失败。会设置GetLastError。
    它的参数类型及说明如下:

  2. lpLibFileName String,指定要载入的动态链接库的名称。采用与CreateProcess函数的lpCommandLine参数指定的同样的搜索顺序。

  3. hFile Long,未用,设为零。

  4. dwFlags Long,指定下述常数的一个或多个:
    (1)DONT_RESOLVE_DLL_REFERENCES:不对DLL进行初始化,仅用于NT
    (2)LOAD_LIBRARY_AS_DATAFILE:不准备DLL执行。如装载一个DLL只是为了访问它的资源,就可以改善一部分性能
    (3)LOAD_WITH_ALTERED_SEARCH_PATH:指定搜索的路径

9、DLL文件相关函数

Dynamic-Link Library Functions

FunctionDescription
AddDllDirectoryAdds a directory to the process DLL search path.
DisableThreadLibraryCallsDisables thread attach and thread detach notifications for the specified DLL.
DllMainAn optional entry point into a DLL.
FreeLibraryDecrements the reference count of the loaded DLL. When the reference count reaches zero, the module is unmapped from the address space of the calling process.
FreeLibraryAndExitThreadDecrements the reference count of a loaded DLL by one, and then calls ExitThread to terminate the calling thread.
GetDllDirectoryRetrieves the application-specific portion of the search path used to locate DLLs for the application.
GetModuleFileNameRetrieves the fully qualified path for the file containing the specified module.
GetModuleFileNameExRetrieves the fully qualified path for the file containing the specified module.
GetModuleHandleRetrieves a module handle for the specified module.
GetModuleHandleExRetrieves a module handle for the specified module.
GetProcAddressRetrieves the address of an exported function or variable from the specified DLL.
LoadLibraryMaps the specified executable module into the address space of the calling process.
LoadLibraryExMaps the specified executable module into the address space of the calling process.
LoadPackagedLibraryMaps the specified packaged module and its dependencies into the address space of the calling process. Only Windows Store apps can call this function.
RemoveDllDirectoryRemoves a directory that was added to the process DLL search path by using AddDllDirectory.
SetDefaultDllDirectoriesSpecifies a default set of directories to search when the calling process loads a DLL.
SetDllDirectoryModifies the search path used to locate DLLs for the application.

10、示例说明

Creating a Simple Dynamic-Link Library

10.1 在dll文件内定义函数

#include <windows.h>
#define EOF (-1)
 
#ifdef __cplusplus    // If used by C++ code, 
extern "C" {          // we need to export the C interface
#endif
 
__declspec(dllexport) int __cdecl myPuts(LPWSTR lpszMsg)
{
    DWORD cchWritten;
    HANDLE hConout;
    BOOL fRet;
 
    // Get a handle to the console output device.

    hConout = CreateFileW(L"CONOUT$",
                         GENERIC_WRITE,
                         FILE_SHARE_WRITE,
                         NULL,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         NULL);

    if (INVALID_HANDLE_VALUE == hConout)
        return EOF;
 
    // Write a null-terminated string to the console output device.
 
    while (*lpszMsg != L'\0')
    {
        fRet = WriteConsole(hConout, lpszMsg, 1, &cchWritten, NULL);
        if( (FALSE == fRet) || (1 != cchWritten) )
            return EOF;
        lpszMsg++;
    }
    return 1;
}
 
#ifdef __cplusplus
}
#endif

10.2 静态加载(Using Load-Time Dynamic Linking)

#include <windows.h> 

extern "C" int __cdecl myPuts(LPWSTR);   // a function from a DLL

int main(VOID) 
{ 
    int Ret = 1;

    Ret = myPuts(L"Message sent to the DLL function\n"); 
    return Ret;
}

10.3 动态加载(Using Run-Time Dynamic Linking)

#include <windows.h> 
#include <stdio.h> 
 
typedef int (__cdecl *MYPROC)(LPWSTR); 
 
int main( void ) 
{ 
    HINSTANCE hinstLib; 
    MYPROC ProcAdd; 
    BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; 
 
    // Get a handle to the DLL module.
 
    hinstLib = LoadLibrary(TEXT("MyPuts.dll")); 
 
    // If the handle is valid, try to get the function address.
 
    if (hinstLib != NULL) 
    { 
        ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts"); 
 
        // If the function address is valid, call the function.
 
        if (NULL != ProcAdd) 
        {
            fRunTimeLinkSuccess = TRUE;
            (ProcAdd) (L"Message sent to the DLL function\n"); 
        }
        // Free the DLL module.
 
        fFreeResult = FreeLibrary(hinstLib); 
    } 

    // If unable to call the DLL function, use an alternative.
    if (! fRunTimeLinkSuccess) 
        printf("Message printed from executable\n"); 

    return 0;

}

在这里插入图片描述

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值