原文地址:www.tenouk.com/ModuleCC1.h…
原文作者:www.tenouk.com/
发布时间:约2004年前后
本模块有哪些内容?
- 创建一个简单的动态链接库程序
- 使用加载时动态链接
- 使用运行时动态链接
我的训练时间: aa小时。在你开始之前,请阅读这里的一些说明。DLL的Windows MFC编程(GUI编程)可以在MFC GUI编程步骤教程中找到。
Win32编程技能。
- 能够理解、构建和运行动态链接库程序。
- 能够区分静态链接和动态链接。
- 能够识别不同类型的动态链接库。
- 能够创建DLL的导出和导入函数。
创建一个简单的动态链接库程序
下面快照演示如何创建和使用DLL。首先我们来看看如何创建DLL项目的步骤。
选择Win32控制台项目,把项目名称。
选择DLL单选按钮并勾选 "空项目"。
然后照常添加C++源文件。
复制并粘贴下面的源代码。构建即可,不要运行。稍后,我们要创建一个应用程序,在我们的DLL程序中使用mydll()函数。接下来我们就可以构建我们的DLL程序了。在这个例子中,我们构建的是Release版本。
下面的例子mysrcdll.cpp是创建一个简单的DLL程序mydllpro.dll所需要的源代码。文件mysrcdll.cpp包含一个简单的字符串打印函数,叫做mydll()。mydllpro.dll并没有定义一个入口点函数,因为它是与C运行时库链接在一起的,没有自己的初始化或清理功能要执行。
// Project name: mydllpro, File name: mysrcdll.cpp, generating mydllpro.dll, mydllpro.lib...
// The mydll function writes a null-terminated string to
// the standard output device...
// The export mechanism used here is the __declspec(export)
// method supported by Microsoft Visual Studio, but any
// other export method supported by your development
// environment may be substituted.
// For WinXp, don't forget to add
// Advapi32.lib library if needed...
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define EOF (-1)
#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
#endif
__declspec(dllexport) int mydll(LPTSTR lpszMsg)
{
DWORD cchWritten;
HANDLE hStdout;
BOOL fRet;
printf("-This is mydll.dll file lol!-\n");
// Get a handle to the standard output device.
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (INVALID_HANDLE_VALUE == hStdout)
{
// failed to get the handle, give some message, get error code, just exit...
printf("GetStdHandle(), invalid handle, error: GetLastError().\n");
return EOF;
}
else
printf("GetStdHandle(), standard handle is OK.\n");
// Write a null-terminated string to the standard output device.
while (*lpszMsg != '\0')
{
fRet = WriteFile(hStdout, lpszMsg, 1, &cchWritten, NULL);
if ((fRet == FALSE) || (cchWritten != 1))
// If something wrong just exit or provide meaningful message/error code...
return EOF;
// else, write more...
lpszMsg++;
}
printf("\n");
return 1;
}
#ifdef __cplusplus
}
#endif
设置发布版本。
或者使用配置管理器...
好了,最后让建立程序。然后,验证一下准备使用的DLL文件(mydllpro.dll)的创建。注意,mydllpro.lib文件将用于隐式链接(加载)。
使用加载时动态链接
创建了一个DLL之后,就可以在应用程序中使用它了。下面的文件mydllloadtime.cpp是一个空的Win32控制台应用程序的源代码,它使用从mydll.dll导出的mydll()函数。请注意,我们之前创建的DLL程序中没有任何用户定义的头文件。
// File: mydllloadtime.cpp
// A simple program that uses mydll() from mydllpro.dll.
// For WinXp, don't forget to add
#define _WIN32_WINNT 0x0501
#include <windows.h>
// call to a function in the mydllpro.dll
__declspec(dllimport) int mydll(LPTSTR);
// Another form: int mydll(LPTSTR);
int main()
{
int Ret = 1;
Ret = mydll("This message was printed using the DLL function");
return Ret;
}
因为mydllloadtime.cpp隐式调用DLL函数,所以应用程序的模块必须与导入的librarymydllpro.lib链接。在本例中,mydllpro.lib和mydllpro.dll被复制到项目目录下。
不幸的是,尽管已经遵循了所有必要的步骤,但当调用mydll()时,这个程序失败了。错误如下所示。
...
...
Loaded kernel32.lib(KERNEL32.dll)
Found __NULL_IMPORT_DESCRIPTOR
Referenced in kernel32.lib(KERNEL32.dll)
Loaded kernel32.lib(KERNEL32.dll)
Found KERNEL32_NULL_THUNK_DATA
Referenced in kernel32.lib(KERNEL32.dll)
...
...
testdll.obj : error LNK2019: unresolved external symbol "int __cdecl mydll(char *)" (?mydll@@YAHPAD@Z) referenced in function _main
Release/mydlltest.exe : fatal error LNK1120: 1 unresolved externals
从构建输出来看,库文件已经被搜索,但没有被加载/处理。Tenouk没有在Visual C++编译器上尝试这个例子。让我们尝试使用同样的代码来实现Run-Time Dynamic Linking。
使用Run-Time Dynamic Linking
你可以在加载时和运行时动态链接中使用同一个DLL。下面的源代码产生了与上一节中加载时示例相同的输出。程序使用LoadLibrary()函数来获取mydll.dll的句柄。如果LoadLibrary()成功,程序在GetProcAddress()函数中使用返回的句柄来获取DLL的mydll()函数的地址。
调用DLL函数后,程序调用FreeLibrary()函数来卸载DLL。下面的例子说明了运行时和加载时动态链接之间的重要区别。如果themydll.dll文件不可用,使用加载时动态链接的应用程序就会简单地终止。然而,运行时动态链接的例子可以对错误做出响应。
这个项目是一个空的控制台模式的应用程序。将mydllpro.dll复制到项目目录或系统目录或前面提到的任何其他目录序列中。在本例中,mydllpro.dll已被复制到项目目录下。
// File: testmydllruntime.cpp
// Using Run-Time Dynamic Linking
// A simple program that uses LoadLibrary() and
// GetProcAddress() to access mydll() in mydllpro.dll.
// For WinXp, don't forget to add
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <windows.h>
typedefvoid (*MYPROC)(LPTSTR);
int main()
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to our DLL module created in the previous example.
hinstLib = LoadLibrary("mydllpro");
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
printf("The dll handle is valid...\n");
ProzAdd = (MYPROC) GetProcAddress(hinstLib, "mydll");
// If the function address is valid, call the function.
if (ProcAdd != NULL)
{
printf("The function address is valid...\n\n");
fRunTimeLinkSuccess = TRUE;
// Pass some text, mydll() will display it on the standard output...
(ProcAdd) ("\nThis message is via DLL function...\n");
}
else
printf("\nThe function address is NOT valid, error: %d.\n", GetLastError());
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
if (fFreeResult != 0)
printf("FreeLibrary() is OK.\n");
else
printf("FreeLibrary() is not OK, error: %d.\n", GetLastError());
}
else
printf("The dll handle is not valid, error: %d.\n", GetLastError());
// If unable to call the DLL function, use an alternative.
if (!fRunTimeLinkSuccess)
printf("This message via alternative method...\n");
return 0;
}
一个示例输出。
好了,它工作了! 该程序使用运行时动态链接;在创建该程序时,你不应该像我们的Load-Time动态链接示例那样与导入库链接。让我们继续看更多的故事。
进一步的阅读和挖掘
-
Microsoft Visual C++,在线MSDN。
-
结构、枚举、联合和typedef故事可以参考C/C++结构、枚举、联合和typedef。
-
多字节、Unicode字符和本地化请参考Locale、宽字符和Unicode(Story)和Windows用户与组编程教程(Implementation)。
-
Windows数据类型是Windows数据类型。
通过www.DeepL.com/Translator(免费版)翻译