Как-то раз мне пришлось загружать очень много функций из dll. После десятого вызова GetProcAddress и добавление переменной в класс (к тому же функции вызывались не из одной библиотеки, что приводило ещё к вызовам LoadLibrary и FreeLibrary) я решил автоматизировать этот процесс раз и навсегда.

#ifndef DYNAMIC_LIB_PROC
#define DYNAMIC_LIB_PROC

class CDynamicLibProcException
{
// Здесь какая-то начинка исключения.
};

struct CUnloadLibOnExeption
{
void operator () (HMODULE hlib)
{
if(hlib)
::FreeLibrary(hlib);
}
};

struct CNotUnloadLibOnExeption { void operator () (HMODULE) { } };

template<typename ProcT, typename ExceptionActionT = CUnloadLibOnExeption>
class CDynamicLibProc
{
public:
CDynamicLibProc(LPCTSTR libname, LPCSTR procname,
bool unload_lib_on_destroy = true) :
m_hlib(::LoadLibrary(libname)),
m_unload_lib_on_destroy(unload_lib_on_destroy)
{
LoadProc(procname);
}

CDynamicLibProc(const HMODULE hlib, LPCSTR procname,
bool unload_lib_on_destroy = false) :
m_hlib(hlib),
m_unload_lib_on_destroy(unload_lib_on_destroy)
{
LoadProc(procname);
}

~CDynamicLibProc()
{
if(m_unload_lib_on_destroy && m_hlib)
::FreeLibrary(m_hlib);
}

HMODULE GetLibHandle() const
{
return m_hlib;
}

public:
ProcT Execute;

private:

void LoadProc(LPCSTR procname)
{
if(!m_hlib)
throw CDynamicLibProcException(); // Тут Вы дополняете своё исключение.
Execute = (ProcT)::GetProcAddress(m_hlib, procname);
if(!Execute)
{
ExceptionActionT ea;
ea(m_hlib);
throw CDynamicLibProcException(); // Тут Вы дополняете своё исключение.
}
}

private:
HMODULE m_hlib;
bool m_unload_lib_on_destroy;
};

#endif // #ifndef DYNAMIC_LIB_PROC

Ну, а использовать этот класс можно так

#include <windows.h>
#include <tchar.h>
#include "DynamicLibProc.h"

int main()
{
CDynamicLibProc<DWORD (WINAPI *)(HWND, LPCWSTR, DWORD, DWORD)>
message_box(_T("user32.dll"), "MessageBoxW");
message_box.Execute(NULL, L"Hello from MessageBox", NULL, 0);
return 0;
}