升级动态链接库
有时需要把一个DLL升级替换到新版本。替换DLL前,检查确认替换的确是较新版本。有时可能要替换一个正在使用的DLL。替换DLL的方法依据操作系统的不同而不同,Windows XP及后续版本,应用程序应该使用独立程序及并行系统来实现。
按照以下步骤进行升级就不必重启计算机:
用MoveFileEx 函数重命名要被替换掉的DLL。不要指定MOVEFILE_COPY_ALLOWED,并确定重命名的文件仍在原始卷中。你也可以通过修改扩展名重命名到当前目录下。拷贝新的DLL到包含重命名DLL的目录(译者注:应该是重命名DLL前的原始目录)。现在,所有应用程序都将使用新的DLL。以MOVEFILE_DELAY_UNTIL_REBOOT调用MoveFileEx 删除重命名的DLL。 实现替换前,应用程序将一直使用原DLL知道被unload。一旦实现了替换,应用程序将使用新DLL。编写DLL时,尤其要小心确认考虑到了该情形,尤其是DLL维系着全局状态信息或者与其他服务进行着通讯的话更需要加以考虑。如果还没有对全局状态或通讯协议有所准备的话,升级DLL就需要你重启计算机,以确信所有应用程序都在使用同一版本的DLL。
Windows Me/98/95: 由于MoveFileEx 不被支持,升级动态链接库就需要重启计算机,更多详细信息,可参照MoveFileEx的详细说明。
创建一个简单的动态链接库
下例,MYPUTS.C,包含创建一个简单DLL(MYPUTS.DLL)所需的源代码,MYPUTS.C中包含了一个简单的字符显示函数—myPuts。MYPUTS DLL没有定义入口函数,这是因为它是用C运行时库连接的,并且没有实现自己初始化及清除函数。
// File: MYPUTS.C.
// The myPuts function writes a null-terminated string to
// the standard output device.
#include <windows.h>
#define EOF (-1)
int myPuts(LPTSTR lpszMsg)
{
DWORD cchWritten;
HANDLE hStdout;
BOOL fRet;
// Get a handle to the standard output device.
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (INVALID_HANDLE_VALUE == hStdOut)
return EOF;
// Write a null-terminated string to the standard output device.
while (*lpszMsg != '\0')
{
fRet = WriteFile(hStdout, lpszMsg, 1, &cchWritten, NULL);
if( (FALSE == fRet) || (1 != cchWritten) )
return EOF;
lpszMsg++;
}
return 1;
}
最后要生成DLL,就需要参照开发工具文档中的指示去做就行了。
使用载入时动态链接
创建DLL后,就可以把它用到一个程序中。下面的文件—LOADTIME.C使用MYPUTS.DLL中的myPuts函数实现了一个简单的控制台应用程序。
// File: LOADTIME.C.
// A simple program that uses myPuts from MYPUTS.DLL.
#include <windows.h>
VOID myPuts(LPTSTR); // a function from a DLL
int main(VOID)
{
int Ret = 1;
Ret = myPuts("message printed using the DLL function\n");
return Ret;
}
由于LOADTIME.C明确调用了DLL函数,该应用程序模块就必须与MYPUTS.LIB连接。更多创建DLL的信息,可参照开发工具相关文档。
使用运行时动态链接
你可以以载入时或运行时动态链接方式使用同一个DLL。以下源码实现上节载入时示例的相同输出。程序利用LoadLibrary 获取MYPUTS.DLL的句柄,LoadLibrary 成功,程序通过该句柄调用GetProcAddress 函数获取DLL中myPuts函数地址。调用DLL函数后,程序调用FreeLibrary函数释放DLL。
下例示范了运行时动态链接与载入时动态链接的重要区别。如果MYPUTS.DLL文件不可用,使用载入时动态连接的程序直接终止,而运行时连接的程序可以报告错误产生。
// File: RUNTIME.C
// A simple program that uses LoadLibrary and
// GetProcAddress to access myPuts from MYPUTS.DLL.
#include <stdio.h>
#include <windows.h>
typedef VOID (*MYPROC)(LPTSTR);
VOID main(VOID)
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module.
hinstLib = LoadLibrary("myputs");
// 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) ("message via DLL function\n");
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("message via alternative method\n");
}
由于使用了运行时动态链接,就不要再连接导入库了。