Unless you really need it to be a COM/MFC dll, for example you need to plug it into an MFC application, then things might be clearer for you if you make it a straight C++ .dll.
In answer to your question regarding the extern keyword - I think this is only used in the calling application, when you are including a .lib file.
Here is a tutorial on creating straight C++ dll's.
Once you have your dll, the issue then becomes the fact that you're dealing with unmanaged code in your dll versus managed code in your C# application. In other words, because C++ knows nothing about the managed types used in C# and similarly, C# has no idea how to handle the memory for types used in the C++ dll, its then down to you to manage the memory in your dll. The C# garbage collector can only deal with memory in the C# application.
I think an answer could be to create a 'normal' dll in C++, then create a wrapper for it in C++/CLI that contains all the memory management - and the conversion from C++ unmanaged types to C# types and vice versa. You may need to use the marshal
class to convert between managed types (C#) and unmanaged types (C++). And then, you import the C++/CLI wrapper rather than the C++ dll directly. Calling the functions then becomes trivial in your C# application, because the wrapper has done the "bridge work".
I've done something similar with a thirdparty C++ dll and I don't think this is as bad as it sounds.
Here is a tutorial on how to do this.