In Windows, the client program does not need to link with a static library in order to access functions in a DLL. The dynamic linking can happen entirely at run time without the client program even being aware of the existence of the DLL at the time it was compiled.
For example, if you wanted to call a function name "foo" in a DLL named "bar.dll", you could write code like this:
HINSTANCE hinst = LoadLibrary("bar.dll");
FARPROC foo = GetProcAddress(hinst, "foo");
foo();
And "foo" and "bar.dll" could easily have been values that were only established at run time, say via a configuration file or some other user input.
The purpose of the static library is to automate this dynamic loading process, by creating stubs that appear like to be regular functions as far as the client program is concerned, but are linked to the DLL at runtime. Typically this linking happens at the time the client process is loaded, but libraries can also be generated that will load and link on demand, so the DLL won't be brought into memory until it is actually needed. It is the static library that determines when the linking occurs.
For the most part, a compiler can generate these libraries automatically, so technically they aren't needed when just linking to DLL functions. However, the one exception to this (that I'm aware of) is when linking to shared variables.
In a Windows DLL you can create a shared data segment with variables that can be accessed by any process that has loaded that DLL. The information about the size and types of those variables is stored in the associated static library, and can't be determined from the DLL alone. In order to access those variables, the client program must link against the static library for that DLL.
As far as I'm aware, Linux Shared Libraries don't support such a concept.
Update
I should also mention that on Windows it's possible to create a DLL where the function entry points are only exported by ordinal (number) rather than name. This can be thought of as a form of data hiding and will typically be used when an implementor wants certain functions to remain private.
Someone with access to the static library would be able to call those functions by name, since the library would have the details linking the function name to the appropriate ordinal. Anyone who only had the DLL would have to manually link to the functions by ordinal or generate their own static library with made up names.