这是否避免在XP下加载该特定功能,以便我不需要拨打GetModuleHandle
和GetProcAddress
?
是的。这正是发明延迟加载的情况。您的代码可以调用DLL函数,就好像它是静态链接的一样,但是可执行文件不会在运行时加载DLL函数指针,直到第一次实际调用该函数为止。在内部,延迟加载机制为您使用LoadLibrary()
和GetProcAddress()
。
当只有少数函数需要延迟加载时,推荐延迟加载DLL吗?
如果一个DLL是延迟加载的,它的所有函数都是延迟加载的,你不能选择和选择你想要的。因此,如果您的应用程序需要使用许多来自同一个DLL的函数,例如user32.dll
,那么静态链接通常会更高效,然后您可以手动使用GetProcAddress()
来处理您需要以不同方式处理的几个函数。
在这种情况下,我会建议摆脱OS检查的干脆只在DLL函数是否实际存在依赖与否,如:
typedef BOOL (WINAPI *LPFN_ACFL)(HWND);
LPFN_ACFL lpAddClipboardFormatListener = (LPFN_ACFL) GetProcAddress(GetModuleHandle(TEXT("user32")), "AddClipboardFormatListener");
if(lpAddClipboardFormatListener != NULL)
lpAddClipboardFormatListener(hWnd);
else
SetClipboardViewer(hWnd);
如果延迟加载真正的亮点是在其挂钩。例如,在较早的系统上,您可以使用延迟加载失败挂钩来实现您自己的版本AddClipboardFormatListener()
,然后您的主代码可以在所有系统上无条件地调用AddClipboardFormatListener()
,并且它不会知道区别。例如(只是一个演示,没有实际测试过):
LRESULT CALLBACK ClipboardSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, &ClipboardSubClassProc, uIdSubclass);
break;
case WM_CHANGECBCHAIN:
{
if (wParam == dwRefData)
SetWindowSubclass(hWnd, &ClipboardSubClassProc, uIdSubclass, lParam);
else if (dwRefData != 0)
SendMessage((HWND)dwRefData, uMsg, wParam, lParam);
break;
}
case WM_DRAWCLIPBOARD:
{
SendMessage(hWnd, WM_CLIPBOARDUPDATE, 0, 0);
if (dwRefData != 0)
SendMessage((HWND)dwRefData, uMsg, wParam, lParam);
break;
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
BOOL WINAPI My_AddClipboardFormatListener(HWND hWnd)
{
HWND hWndNext = SetClipboardViewer(hWnd);
if ((!hWndNext) && (GetLastError() != 0))
return FALSE;
if (!SetWindowSubclass(hWnd, &ClipboardSubClassProc, 1, (DWORD_PTR)hWndNext))
{
DWORD dwErr = GetLastError();
ChangeClipboardChain(hWnd, hwndNext);
SetLastError(dwErr);
return FALSE;
}
return TRUE;
}
BOOL WINAPI My_RemoveClipboardFormatListener(HWND hWnd)
{
DWORD_PTR dwRefData;
if (!GetWindowSubclass(hWnd, &ClipboardSubClassProc, 1, &dwRefData))
{
SetLastError(ERROR_NOT_FOUND);
return FALSE;
}
RemoveWindowSubclass(hWnd, &ClipboardSubClassProc, 1);
return ChangeClipboardChain(hWnd, (HWND)dwRefData);
}
FARPROC WINAPI MyDliFailureHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
if ((dliNotify == dliFailGetProc) && (pdli->dlp.fImportByName))
{
if (strcmp(pdli->dlp.szProcName, "AddClipboardFormatListener") == 0)
return (FARPROC) &My_AddClipboardFormatListener;
if (strcmp(pdli->dlp.szProcName, "RemoveClipboardFormatListener") == 0)
return (FARPROC) &My_RemoveClipboardFormatListener;
}
return NULL;
}
__pfnDliFailureHook2 = &MyDliFailureHook;
...
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
AddClipboardFormatListener(hWnd);
break;
case WM_DESTROY:
RemoveClipboardFormatListener(hWnd);
break;
case WM_CLIPBOARDUPDATE:
// do all of your clipboard processing here...
break;
...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
1.是,作为GetProcAddress的实际要求第一次调用(仅在第一次)2.是的,这是标准的用例 –
是的,你可以使用DELAYLOAD对于'user32.dll' - 在这种情况下,您不需要直接调用'GetProcAddress' - 所有任务都将在'__delayLoadHelper2'内完成。并且你可以在这种情况下使用snipet代码 – RbMm