The difference between traditional DLL and COM DLL
A COM DLL is simply a DLL with Com-specific entry points. COM exposes class factories for creating com objects, so there needs to be a way of getting access to one of the class factories implemented by a COM server. That's what DllGetClassObject does. Furthermore, COM DLL's are self-registering: they can notify Windows of their available classes and interfaces. The Entry point for having the DLL register itself is DllRegisterServer.
There are a couple of other entry points, but they are along these lines.
If there wasn't a well-defined entry point for DllRegisterServer, then clients wouldn't be able to cause DLL's to self-register. It would make installation of COM components more complex.
If there weren't a standardized entry point for getting class factories, then each DLL would have to define its own entry point and that information would have to be put in the Windows Registry so that the COM infrastructure would know how to access each DLL's class factory. There's no justification for the extra complexity, so that entry point is also standarized.
As to where COM differs from 'C', the main difference is the concept of contracts. COM encourages programmers to think in terms of abstract interfaces between modules rather than a hierarchical, top-down decomposition of functionality. This is one kind of 'OOP', but that term is too loose to be of much use, IMO. Advantages of the contract-oriented approach are manifold for strongly-typed, statically linked languages like C/C++.
No, there's a Big difference. COM has a well defined protocols for creating objects, exposing methods, managing memory, publishing type information, managing threading. There is practically no language left that doesn't support using a COM server, no matter what language it was written in.
You will not get that from exposing your own functions directly. That will likely be only usable from a program written in C/C++ (so it can read your header files), compiled with the exact same version of the C++ compiler and no lack of all kinds of interop problems. Something as simple as exposing a C++ class object like std::string is not safe. Neither the memory layout is guaranteed to be compatible, nor is there any kind of memory ownership protocol.
It could well be more OOPy, COM doesn't support inheritance because OOP is so hard to get compatible at the binary level. That problem requires runtime support that all code buys into, VMs like .NET and Java.