Well, if you have the source for the DLL, you can likely produce a static version of that library, then link statically with it.

Otherwise, you can DYNAMICALLY link to the DLL (load it implicitly or manually) at runtime.

While @stahta01 is right that there is some preference for DLL's among many programmers, many of us prefer static linking where possible as it simplifies development.

Now, about the libs.

A static lib will generate what is basically a package of object files, and the extension is often .lib. A linker can be configured to produce an executable, a static library or a dynamic library. They are all valid output targets. The specifics differ for every compiler.

When you produce a dynamic library, the extension for Windows is usually DLL, but it could be anything. Plugins, for example, often use some application defined extension, but it is the same binary concept - a dynamic library of compiled code.

Static libs, on the other hand, are merely packaged object files and link just like any collection of object files produced from individual translation units.

For the dynamic library you have an additional layer of complexity. If there is an import library, the process can automatically perform dynamic linking at runtime - which is to say the running executable will "know" what functions are in the DLL. However, without that, the running executable will not know, automatically, what functions are in the DLL, which means they must be "discovered" - a process of getting the function pointer and assigning them during runtime during the loading process.

You'll need to practice that on a simple application contrived for the purpose of understanding how it's done.