There are several different ways of loading Windows libraries, but each way serves a different purpose.
Using LoadLibrary() and GetProcAddress() manually is intended to allow runtime decisions about several different dynamic linking situations. These calls are simply system calls which do not affect any aspect of the resulting PE file whatsoever, and the addresses returned by GetProcAddress() are not special in any manner with regards to code generation. This means that the caller is responsible for properly use these symbols at the very syntactical level (for example, using the proper calling convention and the correct number, size and alignment of the arguments, if any, for a function call).
Linking against a .lib file associated with a .dll is different. The client code refers to the runtime content using external identifiers, as if they were statically linked symbols. During the build process, the linker will resolve these identifiers with the symbols found in the .lib file. While, in principle, these symbols could point to anything at all (as any other symbol could), an automatically generated .lib file will simply provide symbols which act as tiny proxies to the memory content that will be filled at load time by the PE loader.
The manner in which these proxies are implemented is dependent on the type of memory access expected. For example, a symbol which refers to a function in the .dll will be implemented as a single indirect jmp instruction, in such a way that the original call instruction from the client code will hit the jmp instruction from the .lib content and will be forwarded to an address resolved by the PE loader at load time. At this address reside the dynamically loaded function's code.
Many more details aside, all of this is used to instruct the PE loader to do the same job as the client code would do by itself: call LoadLibrary() to map a PE into memory and dig through the export tables with GetProcAddress() to find and calculate the proper address to every needed symbol. The PE loader does this automatically at load time from the information found in the import table of the client executable.
In other words, load-time dynamic linking is slower and fatter than run-time dynamic linking by the tiniest amount, if any, but it is intended to provide a much simpler programming interface to the ordinary developer, specially because many libraries are always required and always available. Attempting to provide any additional logic through manual loading is not useful in these circumstances.
Summarizing, do not bother to use LoadLibrary() and GetProcAddress() just because they seem to provide more performance or robustness. Link against .lib files whenever possible.
Going further on the topic, it is even possible to create PE images which don't contain any import tables at all (and can still access system calls and other exported routines). This approach is used by malware to hide suspicious API usage (such as Winsock calls) by stripping any load-time information.
GetProcAddressis if you need to make runtime decisions about what library to load (i.e. if you have multiple choices, plugins, or if the library isn't guaranteed to exist). Otherwise, you should use a.liband let the system take care of library loading and linking.Windows.h!